I have 2 vectors
A=[10 22 31 14 55 16 47 18];
B= [1 2 1 1 1 2 1 2];
I want to make a third vector C which contains values of A for values of B=1;
like
C=[10 NaN 31 14 55 NaN 47 NaN]
or
C=[10 31 14 55 47]
I did this using a for loop.
Just want to know if this is doable without using for loop as it may save a lot of computation time. (The vectors with me are really really large
for i=1:length (A);
if B(i)==1;
C(i)=A(i)
else C(i)=NaN;
end;
end;
use boolean logic for indexing. In your case, as you also suggest, you can do it with a simple
C = A(B==1);
For more complicated conditions, you can also use the function find(), as in
C = A(find(B==1));
or
C = nan(size(A));
C(find(B==1)) = A(find(B==1));
Related
I tried to resample my data from a block of matrix that defined its indices. Hopefully this example can make it clear:
A=rand(18400,100);
A_IDX=randi([1 100],[18400 100]);
A_IDX consist 18400 rows and 100 columns. I wanted to extract the matrix A at the A_IDX indices. Result would be something like:
A=[1 2 3; 4 5 6];
A_IDX=[1 3; 2 3];
A_Result=[1 3; 5 6];
I tried A(:,A_IDX) but that gave me 1840x184000 matrix size, which is not what I wanted to do in the first place. Anyone can help? Thanks in advance!
We could get the linear index equivalent for those indices and then simply indexing into the input array would give us the desired output. Now, to get those linear indices, we would make use of bsxfun for the math computations related to the index computations, which would basically involve scaling and offsetting.
Indexing with 2D array of column indices
For a 2D array of column indices, we would have -
function out = take_cols(a, col_idx)
n = size(a,1);
lidx = bsxfun(#plus,(col_idx-1)*n,(1:n).');
out = a(lidx);
Sample run -
>> a
a =
39 83 39 48 36
58 74 20 19 50
69 97 65 34 57
47 58 80 24 51
>> col_idx
col_idx =
2 4
3 5
1 4
2 5
>> take_cols(a, col_idx)
ans =
83 48
20 50
69 34
58 51
Indexing with 2D array of row indices
For a 2D array of row indices, it would be -
function out = take_rows(a, row_idx)
[m,n] = size(a);
lidx = bsxfun(#plus,row_idx, (0:n-1)*m);
out = a(lidx);
Sample run -
>> a
a =
39 83 39 48 36
58 74 20 19 50
69 97 65 34 57
47 58 80 24 51
>> row_idx
row_idx =
3 2 3 1 2
4 3 4 2 4
>> take_rows(a, row_idx)
ans =
69 74 65 48 50
47 97 80 19 51
This weird monster of code will give you what you want. It generates proper subscripts for each index and converts them to linear, then just indexes A linearly.
A_IDX_aux=A_IDX';
reshape(A(sub2ind(size(A),repelem(1:size(A,1),1,size(A_IDX,1)).',A_IDX_aux(:))),[size(A,1), size(A_IDX,2)]).';
I find my solution for this task too, but not so fast, as Divakar and Ander :)
Behold:
res = cell2mat(arrayfun( #(x) A(x,A_IDX(x,:)), (1:size(A,1))', 'UniformOutput',false));
It use cell2mat and I suppose it is not so fast as bsxfun, but hope is still alive and I was curios to test all the 3 solutions. And I got unobvious results!
Elapsed time is 0.000058 seconds. % Divakar
Elapsed time is 0.000077 seconds. % Andres
Elapsed time is 0.000339 seconds. % Me
This mean bsxf is fastest! But using right indexing give fast result too! And my solution was really slow. I suppose it's because of 'UniformOutput', false - I forced to convert to cells and then back, so it slow my method a lot.
Conclusion:
If you can use bsxf - use it!
Despite the fact that my method looks more visually pleasing than that of Andres, it is still slower.
So there is no any sense to post this answer :D I spend some time for current work, maybe it will help someone in future
I have a few multidimensional matrices of dimensions mxnxt, where each element in mxn is an individual sensor input, and t is time. What I want to do is analyse only the peak values for each element in mxn over t, so I would end up with a single 2D matrix of mxn containing only max values.
I know there are are ways to get a single overall max value, but is there a way to combine this with element-by-element operations like bsxfun so that it examines each individual element over t?
I'd be grateful for any help you can give because I'm really stuck at the moment. Thanks in advance!
Is this what you want?
out = max(A,[],3); %// checking maximum values in 3rd dimension
Example:
A = randi(50,3,3,3); %// Random 3x3x3 dim matrix
out = max(A,[],3);
Results:
A(:,:,1) =
35 5 8
38 12 42
23 46 27
A(:,:,2) =
50 6 39
4 49 41
23 1 44
A(:,:,3) =
5 41 10
20 22 14
13 46 8
>> out
out =
50 41 39
38 49 42
23 46 44
You can call max() with the matrix and select the dimension (look the documentation) on which the operation will be calculated, e.g
M = max(A,[],3)
I have two arrays threshold and values.
threshold=[10 22 97]
values=[99 23 77 11 8 10]
I want to output idx such that threshold(idx-1)<values(i)<=threshold(idx). That is for the above example output will be
output=[4 3 3 2 1 1]
The naive code that can produce above output will be
output=ones(1,length(values))*(length(values)+1);
for i=1:length(values)
for j=1:length(threshold)
if(values(i)>threshold(j))
output(i)=j;
end
end
end
Is there a simple way of doing it. I want to avoid loops.
You can use histc command, with a slight adjustment of threshold array
>> threshold=[-inf 10 22 97 inf];
>> values=[99 23 77 11 8 10];
>> [~, output] = histc( values, threshold+.1 )
output =
4 3 3 2 1 1
The modification of threshold is due to "less-than"/"less-than-equal" type of comparison for bin boundary decisions.
No loops often means you'll gain speed by increasing peak memory. Try this:
threshold = [10 22 97];
values = [99 23 77 11 8 10];
%// Do ALL comparisons
A = sum(bsxfun(#gt, values.', threshold));
%// Find the indices and the ones before
R = max(1, [A; A-1]);
%// The array you want
R(:).'
If you run out of memory, just use the loop, but then with a find replacing the inner loop.
Loops aren't all that bad, you know (if you have MATLAB > R2008). In theory, the solution above shouldn't even be faster than a loop with find, but oh well...profiling is key :)
I have a matrix of 2d lets assume the values of the matrix
a =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
17 24 1 8 15
11 18 25 2 9
This matrix is going to be divided into three different matrices randomly let say
b =
17 24 1 8 15
23 5 7 14 16
c =
4 6 13 20 22
11 18 25 2 9
d =
10 12 19 21 3
17 24 1 8 15
How can i know the index of the vectors in matrix d for example in the original matrix a,note that the values of the matrix can be duplicated.
for example if i want to know the index of {10 12 19 21 3} in matrix a?
or the index of {17 24 1 8 15} in matrix a,but for this one should return only on index value?
I would appreciate it so much if you can help me with this. Thank you in advance
You can use ismember with the 'rows' option. For example:
tf = ismember(a, c, 'rows')
Should produce:
tf =
0
0
1
0
0
1
To get the indices of the rows, you can apply find on the result of ismember (note that it's redundant if you're planning to use this vector for matrix indexing). Here find(tf) return the vector [3; 6].
If you want to know the number of the row in matrix a that matches a single vector, you either use the method explained and apply find, or use the second output parameter of ismember. For example:
[tf, loc] = ismember(a, [10 12 19 21 3], 'rows')
returns loc = 4 for your example. Note that here a is the second parameter, so that the output variable loc would hold a meaningful result.
Handling floating-point numbers
If your data contains floating point numbers, The ismember approach is going to fail because floating-point comparisons are inaccurate. Here's a shorter variant of Amro's solution:
x = reshape(c', size(c, 2), 1, []);
tf = any(all(abs(bsxfun(#minus, a', x)) < eps), 3)';
Essentially this is a one-liner, but I've split it into two commands for clarity:
x is the target rows to be searched, concatenated along the third dimension.
bsxfun subtracts each row in turn from all rows of a, and the magnitude of the result is compared to some small threshold value (e.g eps). If all elements in a row fall below it, mark this row as "1".
It depends on how you build those divided matrices. For example:
a = magic(5);
d = a([2 1 2 3],:);
then the matching rows are obviously: 2 1 2 3
EDIT:
Let me expand on the idea of using ismember shown by #EitanT to handle floating-point comparisons:
tf = any(cell2mat(arrayfun(#(i) all(abs(bsxfun(#minus, a, d(i,:)))<1e-9,2), ...
1:size(d,1), 'UniformOutput',false)), 2)
not pretty but works :) This would be necessary for comparisons such as: 0.1*3 == 0.3
(basically it compares each row of d against all rows of a using an absolute difference)
I'm sure there's an easy answer to this, but I'm not really sure what to search for. I have an array, M, of D dimensions, where D is constrained to be 1 <= D <= 5, and a vector of length D, X. I'd like to use D as an address within M and increment the value at that address, so if D were [1 2 3], I would want to increment M(1,2,3). I know I can do it like so:
if D == 1
M(X(1)) = M(X(1)) + 1;
end
if D == 2
M(X(1), X(2)) = M(X(1), X(2)) + 1;
end
But it's really ugly and I have to imagine there's a simpler, less clumsy way. Thanks!
You can use the function sub2ind to convert the address vector D to the corresponding dimensions in M. However, this would require that you store D as a cell and not a vector. The following example should help.
A=magic(5);%# just a test matrix
A=
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
d={3,4};%we need the element at row 3, column 4
indx=sub2ind(size(A),d{:});%# get the index corresponding to the subscript 3,4
A(indx)
ans=
20
You can also directly index it into the matrix A as A(sub2ind(size(A),d{:})), without having to create a separate variable.
You can also use num2cell to convert the vector to a cell. This might be a better option, as you might want to store D as a vector for other purposes. So the corresponding line becomes
indx=sub2ind(size(A),num2cell(d));