Assume that we have a 100*4 array.
We also have a 100*1 array of 1 and 0. Assume there are n 1's.
We want to create a n*4 array from the 100*4 array, where we only include the columns for which the second array is a 1.
One way to do it is through a double for loop. Is there a simpler method?
So, We have
A = [ [ 332 44 33 22 33 55 33 211 .....
[ 823 44 12 98 19 23 32 911 .....
....
....
]
and
B = [1 0 0 1 0 0 0 ....]
and we want
C = [ [ 332 22 ...
[ 823 98 ...
....
....
]
You should use logical indexing:
C = A(:, B==1 );
First you repmat the logical vector so that it has the exact same size as the matrix A.
idx2keep = repmat(b, [1 4]); % Or [4 1] depending on if it's a col or row vector
Then you can simply index them with
B = A( idx2keep )
you can then make it into a column vector:
B = B(:)
That should do the job. Next time please always post some code or notation so it's easier and clearer to answer this.
Related
A = [5 10 16 22 28 32 36 44 49 56]
B = [2 1 1 2 1 2 1 2 2 2]
How to get this?
C1 = [10 16 28 36]
C2 = [5 22 32 44 49 56]
C1 needs to get the values from A, only in the positions in which B is 1
C2 needs to get the values from A, only in the positions in which B is 2
You can do this this way :
C1 = A(B==1);
C2 = A(B==2);
B==1 gives a logical array : [ 0 1 1 0 1 0 1 0 0 0 ].
A(logicalArray) returns elements for which the value of logicalArray is true (it is termed logical indexing).
A and logicalArray must of course have the same size.
It is probably the fastest way of doing this operation in matlab.
For more information on indexing, see matlab documentation.
To achieve this with an arbitrary number of groups (not just two as in your example), use accumarray with an a anoynmous function to collect the values in each group into a cell. To preserve order, B needs to be sorted first (and the same order needs to be applied to A):
[B_sort, ind_sort] = sort(B);
C = accumarray(B_sort.', A(ind_sort).', [], #(x){x.'});
This gives the result in a cell array:
>> C{1}
ans =
10 16 28 36
>> C{2}
ans =
5 22 32 44 49 56
For example, A = [19 20 21 22 23 24 25]; B = [2 0 3 0 0 0 2];
How can we get a new array, repeating each value from B accordingly X times?
For example, answer here is: [19 19 21 21 21 25 25].
Please note that I am only allowed to a for loop combined with a repmat call.
If you are only allowed to use repmat and a for loop, you can do the following:
S = [];
for idx = 1 : length(B)
S = [S repmat(A(idx), 1, B(idx))];
end
S is initially a blank array, then for as many values as there are in B (or A since they're both equal in length), simply concatenate S with each value in A that is repeated by the corresponding number in B. S will contain the output.
By running the above example, I get:
S =
19 19 21 21 21 25 25
However, I highly recommend you use more vectorized approaches. I'll leave that to you as an exercise.
Good luck!
I want to pass columns in various matrices to a for loop.
If my two matrices had the same number of columns, I might do something like this:
mat1 = matrix(rep(1:25), 5,5)
mat2 = matrix(rep(26:50), 5,5)
array.mat = array(c(mat1,mat2), dim=c(5,5,2))
mat1.ncol = ncol(mat1)
mat2.ncol = ncol(mat2)
mat.ncol = c(mat1.ncol, mat2.ncol)
mat.ncol
array.mat
for (dimi in 1:2){
dim.col = mat.ncol[dimi]
for (coli in 1:dim.col){
st = shapiro.test(array.mat[,coli,dimi])$p.value
if(st > .001){
array.mat[,coli,dimi] = log(array.mat[,coli,dimi])
}}}
But, my data don't have the same number of columns, so I'd like to use a list of matrices instead.
mat1 = matrix(rep(1:10), 5,2)
mat2 = matrix(rep(26:50), 5,5)
list.mat=list(a=mat1, b=mat2)
list.mat
But I can't figure out how I'd pass the columns of the matrices?
list.mat$a[1:5]
gives the first column of the first matrix, but how would you pass $a and [startindex:endindex] in a loop? All the other answers I see tend to pass the ith element (e.g., column) of both matrices. I need to keep the two matrices (a and b) separate for later computations, but I want them together (the list of the two matrices) for these types of loops.
Once again, I'm probably just thinking about this incorrectly. Thanks for any thoughts.
Can you use numeric indices? e.g., matrix 1, column 1: list.mat[[1]][,1]
In a loop:
for (m in 1:2) {
for (i in 1:ncol(list.mat[[m]])) {
cat('Here is matrix', m, ', columnn', i, '\n')
print(list.mat[[m]][,i])
}
}
result:
Here is matrix 1 , columnn 1
[1] 1 2 3 4 5
Here is matrix 1 , columnn 2
[1] 6 7 8 9 10
Here is matrix 2 , columnn 1
[1] 26 27 28 29 30
Here is matrix 2 , columnn 2
[1] 31 32 33 34 35
Here is matrix 2 , columnn 3
[1] 36 37 38 39 40
Here is matrix 2 , columnn 4
[1] 41 42 43 44 45
Here is matrix 2 , columnn 5
[1] 46 47 48 49 50
In trying to port an algorithm from C# to Matlab I found that Matlab is inefficient at running for loops. As such I want to vectorize the algorithm.
I have following inputs:
lowrange:
[ 00 10 20 30 40 50 ... ]
highrange:
[ 10 20 30 40 50 60 ... ]
These arrays are equal in length.
I now have a third array Values (which could be any length) and for this array I want to count the occurrences of Values elements between lowerange(i) and highrange(i) (You can see I'm coming from a for loop).
The output should be an array of length lowrange/highrange.
So with the above arrays and input LineData:
[ 1 2 3 4 6 11 12 16 31 34 45 ]
I expect to get:
[ 05 03 00 02 01 00 ... ]
I tried the (for me) obvious thing:
LineData(LineData < PixelEnd & LineData > PixelStart)
But that doesn't work because it just checks LineData on an element by element way. It does not try to apply the comparison over all values in LineData.
Unfortunately, I cannot come up with anything else since I'm not yet used to think in a Matlab 'vector' way, let alone knowing all applicable instructions from memory.
As you are looking to do a basic histogram with given edges, you can use Matlabs built-in function histc:
values = [ 1 2 3 4 6 11 12 16 31 34 45 ];
edges = 0:10:60;
histc(values, edges)
ans =
5 3 0 2 1 0 0
For ranges with identical intervals and starting from 0, here's a bsxfun based counting approach -
LineData = [ 1 2 3 4 6 11 12 16 31 34 45 ] %// Input
interval = 10; %// interval width
num_itervals = 6; %// number of intervals
%// Get matches for each interval and sum them within each interval for the counts
out = sum(bsxfun(#eq,ceil(LineData(:)/interval),1:num_itervals))
Output -
LineData =
1 2 3 4 6 11 12 16 31 34 45
out =
5 3 0 2 1 0
Assuming that the last interval would be the one holding the max of input data, you can try out a diff + indexing based approach too -
LineData = [ 1 2 3 4 6 11 12 16 31 34 45 ] %// Input
interval = 10; %// interval width
labels = ceil(LineData(:)/interval); %// set labels to each input entry
df_labels = diff(labels)~=0; %// mark the change of labels
df_labels_pos = find([df_labels; 1]); %// get the positions of label change
intv_pos= labels([true;df_labels]);%// position of each interval with nonzero counts
%// get counts from interval between label position change and put at right places
out(intv_pos) = [ df_labels_pos(1) ; diff(df_labels_pos)];
I have two arrays in Matlab
say
A = [1 4 89 2 67 247 2]
B = [0 1 1 1 0 0 1]
I want an array C, which contains elements from array A, if there is 1 in B at the corresponding index. In this case, C = [4 89 2 2].
How to do this?
Use logical indexing:
>> C = A(logical(B))
C =
4 89 2 2