Related
I have got the following function for spreading out the number of 1's in a matrix and if there are rows with all 0's or all 1's then that particular row has to be deleted
function ReducedMatrix = ReduceMatrix(result)
D1 = sum(result(:));
NumberOfOnes = floor(D1*0.3);
NewMatrix = zeros(size(result));
NewMatrix(randi(numel(NewMatrix),1,NumberOfOnes)) = 1;
ReducedMatrix = NewMatrix;
while numel(ReducedMatrix)/numel(NewMatrix) > 0.2
IndexOfFullRows = find(all(ReducedMatrix));
if isempty(IndexOfFullRows)
break
end
ReducedMatrix(:,IndexOfFullRows(1)) = [];
end
end
The input of the function and output are as follows
result =
0 1 1 1 1 1 1 1 1 1
1 1 1 1 1 0 1 0 1 1
1 1 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 1 0 1
1 0 1 1 1 1 1 0 1 1
1 1 1 1 0 1 1 1 0 1
1 0 1 1 1 0 1 1 1 1
1 1 1 1 0 1 0 1 1 1
1 1 1 0 1 1 1 1 1 1
ReducedMatrix =
0 1 1 0 0 0 0 0 1 0
0 1 0 0 0 0 0 1 0 0
1 1 1 0 0 0 0 0 0 0
0 0 0 1 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0
0 1 0 0 0 0 1 0 1 1
1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 0 1
row_sum =
3
2
3
2
1
4
2
2
0
3
col_sum =
3 4 4 1 0 0 3 2 2 3
Now if there exists a row or column with the row_sum/col_sum equal to either 0 or 1 then then the corresponding row has to be deleted.
For Example. Row-R4,R9 and Col-C4,C5,C6 have row_sum and col_sum as either 1,0. So adding them up R4,R9,C4,C5,C6 = 5 rows have to be eliminated from the matrix so my reduced matrix should be of the size 5x5. Please note column should not be eliminated and instead of removing columns having 0 and 1, the corresponding rows can be removed. Similarly this function has to run for larger matrices with the same constraints. I tried doing the above function however i do not possess enough skills to achieve my desired results, Any help is much appreciated
I see a number of potential problems and possible simplifications to your code.
For one thing, the way you construct the original matrix, NewMatrix(randi(numel(NewMatrix),1,NumberOfOnes)) = 1; may not behave the way you would expect. randi does not guarantee that the same index will not appear multiple times in the output, so your new matrix may have fewer ones than the original. To solve this, shuffle the elements using randperm:
ReducedMatrix = [ones(1, NumberOfOnes), zeros(1, numel(result) - NumberOfOnes)];
ReducedMatrix = ReducedMatrix(randperm(numel(ReducedMatrix)));
ReducedMatrix = reshape(ReducedMatrix, size(result));
Secondly, you do not need to construct the new matrix as NewMatrix and then reassign it with ReducedMatrix = NewMatrix;. Just do ReducedMatrix = zeros(size(result)); and skip the reassignment. For the while loop condition, where NewMatrix appears to be "used", remember that numel(NewMatrix) == numel(result).
If you are not removing homogeneous columns, only rows, you do not need a loop to do the removal:
rowSum = sum(ReducedMatrix, 2);
rowMask = (rowSum == size(ReducedMatrix, 2) | rowSum == 0);
ReducedMatrix(rowMask, :) = [];
Your original code seems to swap the row and column indices when removing the rows. It also did not handle the case of all zeros. If you want to remove not more than 30% of rows, you can do something like this before the removal:
rowMask = find(rowMask); % Convert to indices
rowMask = rowMask(1:min(numel(rowMask), round(0.3 * size(ReducedMatrix, 2))));
If I have a vector such as:
0 0 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 1 1 0 0 1 0 1 1 1 1 1 1 0 0 0
How do I find the position of the first time there are two consecutive 1s. I.e. the answer to the above would be 9.
Thanks!
Can't comment, so will give you a hint here: "Finite State Machines"
Let's have a M = [10 x 4 x 12] matrix. As example I take the M(:,:,4):
val(:,:,4) =
0 0 1 0
0 1 1 1
0 0 0 1
1 1 1 1
1 1 0 1
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
How can I obtain this:
val(:,:,4) =
0 0 3 0
0 2 2 2
0 0 0 4
1 1 1 1
1 1 0 1
0 2 2 2
1 1 1 1
1 1 1 1
0 0 3 3
0 0 3 3
If I have 1 in the first column then all the subsequent 1's should be 1.
If I have 0 in the first column but 1 in the second, all the subsequent 1's should be 2.
If I have 0 in the first and second column but 1 in the third then all the subsequent 1's should be 3.
If I have 0 in the first 3 columns but 1 in the forth then this one should be four.
Note: The logical matrix M is constructed:
Tab = [reshape(Avg_1step.',10,1,[]) reshape(Avg_2step.',10,1,[]) ...
reshape(Avg_4step.',10,1,[]) reshape(Avg_6step.',10,1,[])];
M = Tab>=repmat([20 40 60 80],10,1,size(Tab,3));
This is a very simple approach that works for both 2D and 3D matrices.
%// Find the column index of the first element in each "slice".
[~, idx] = max(val,[],2);
%// Multiply the column index with each row of the initial matrix
bsxfun(#times, val, idx);
This could be one approach -
%// Concatenate input array along dim3 to create a 2D array for easy work ahead
M2d = reshape(permute(M,[1 3 2]),size(M,1)*size(M,3),[]);
%// Find matches for each case, index into each matching row and
%// elementwise multiply all elements with the corresponding multiplying
%// factor of 2 or 3 or 4 and thus obtain the desired output but as 2D array
%// NOTE: Case 1 would not change any value, so it was skipped.
case2m = all(bsxfun(#eq,M2d(:,1:2),[0 1]),2);
M2d(case2m,:) = bsxfun(#times,M2d(case2m,:),2);
case3m = all(bsxfun(#eq,M2d(:,1:3),[0 0 1]),2);
M2d(case3m,:) = bsxfun(#times,M2d(case3m,:),3);
case4m = all(bsxfun(#eq,M2d(:,1:4),[0 0 0 1]),2);
M2d(case4m,:) = bsxfun(#times,M2d(case4m,:),4);
%// Cut the 2D array thus obtained at every size(a,1) to give us back a 3D
%// array version of the expected values
Mout = permute(reshape(M2d,size(M,1),size(M,3),[]),[1 3 2])
Code run with a random 6 x 4 x 2 sized input array -
M(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 1 1
1 0 0 0
1 0 1 1
M(:,:,2) =
0 1 0 1
1 1 0 0
1 1 0 0
0 0 1 1
0 0 0 1
0 0 1 0
Mout(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 3 3
1 0 0 0
1 0 1 1
Mout(:,:,2) =
0 2 0 2
1 1 0 0
1 1 0 0
0 0 3 3
0 0 0 4
0 0 3 0
What matlab command, or combination of commands (using 25 characters or less), could be used to create the following matrix?
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
I got as far as this;
repmat(tril(ones(3,3)),5)
But repmat creates a 5 by 5 matrix. I however, need a 4,5 matrix.
Thank you for taking the time to help!
Add one more argument to repmat and remove one from ones (as Divakar noted):
repmat(tril(ones(3)),4,5)
As you can see, you can specify how many replications you want for both the rows and the columns. A single value argument to either function will use that value for both rows and columns.
I'll throw the kron solution out there. Just because.
kron(ones(4,5),tril(ones(3)))
More than 25 characters, but hey:
bsxfun(#le,mod(0:3*5-1,3),mod(0:3*4-1,3).')
Let say that I have 1 matrix with numbers (0,1). How can i create new matrix that is the result of a logical operation among the columns?
eg. A =
0 0 0 1 0
1 1 1 1 1
0 1 1 0 0
0 0 0 0 1
1 0 0 1 0
1 1 1 1 1
If all elements of **rows** are equal to 1 - 1, if not - 0.
(like AND operation)
Ans= 0
1
0
0
0
1
Thanks!
To solve your problem this would work -
all(A,2)
If you were looking to set elements based on the columnwise data in A, you would do this -
all(A,1)
More info on all, must serve you well.