Greatest values in a matrix, row by row - matlab - matlab

I have an m-by-n matrix. For each row, I want to find the position of the k greatest values, and set the others to 0.
Example, for k=2
I WANT
[1 2 3 5 [0 0 3 5
4 5 9 3 0 5 9 0
2 6 7 1] 0 6 7 0 ]

You can achieve it easily using the second output of sort:
data = [ 1 2 3 5
4 5 9 3
2 6 7 1 ];
k = 2;
[M N] = size(data);
[~, ind] = sort(data,2);
data(repmat((1:M).',1,N-k) + (ind(:,1:N-k)-1)*M) = 0;
In the example, this gives
>> data
data =
0 0 3 5
0 5 9 0
0 6 7 0

You can use prctile command to find the threshold per-line.
prctile returns percentiles of the values in the rows of data and thus can be easily tweaked to return the threshold value above which the k-th largest elements at each row exist:
T = prctile( data, 100*(1 - k/size(data,2)), 2 ); % find the threshold
out = bsxfun(#gt, data, T) .* data; % set lower than T to zero
For the data matrix posted in the question we get
>> out
out =
0 0 3 5
0 5 9 0
0 6 7 0

Related

Matlab how to distribute a matrix elements randomly

hi everyone how to make a matrix randomly distributed to another matrix n,
m = [ 1 1 3 3 3 4 4 6 6 7 7 7];
n = zeros(3,10);
the same value must in the sequence, ex : 4 4 4, 7 7 7.result reqiured can be something like {or other combinations):
distributed_matrix =
0 1 1 0 7 7 7 0 0 0
0 0 3 3 3 4 4 0 0 0
6 6 6 0 0 0 0 0 0 0
thank you...
If you do not impose any constraint on the order at which the elements of m are distributed, then randsample might help:
ridx = randsample( numel(n), numel(m) ); %// sample new idices for elelemtns
n(ridx) = m;
Looking into the additional constraints, things get a bit more messy.
For identifying the sequences and their extent in m, you can:
idx = [1 find(diff(m)~=0)+1];
extent = diff([idx numel(m)+1]); %// length of each sequence
vals = m(idx); %// value of each sequence
Once you have the sequqnces and their length you can randomly shuffle them and then distribute along the lines...
If I understand your question correctly, the possible solution is
m = [ 1 1 3 3 3 4 4 6 6 7 7 7];
n = zeros(3,10);
p= randperm(numel(n)); % generate the random permutation
n(p(1:length(m)))= m % assign the elments of m to the elements with indices taken
% from the first length(m) numbers of random permutation

Shift rows in matrix with respect to vector values in Octave/MATLAB

Can I shift rows in matrix A with respect to values in vector v?
For instance A and v specified as follows:
A =
1 0 0
1 0 0
1 0 0
v =
0 1 2
In this case I want to get this matrix from A:
A =
1 0 0
0 1 0
0 0 1
Every i-th row in A has been shifted by i-th value in v
Can I do this operation with native functions?
Or should I write it by myself?
I've tried circshift function, but I couldn't figure out how to shift rows separately.
The function circshift does not work as you want and even if you use a vector for the amount of shift, that is interpreted as the amount of shift for each dimension. While it is possible to loop over the rows of your matrix, that will not be very efficient.
More efficient is if you compute the indexing for each row which is actually quite simple:
## First, prepare all your input
octave> A = randi (9, 4, 6)
A =
8 3 2 7 4 5
4 4 7 3 9 1
1 6 3 9 2 3
7 4 1 9 5 5
octave> v = [0 2 0 1];
octave> sz = size (A);
## Compute how much shift per row, the column index (this will not work in Matlab)
octave> c_idx = mod ((0:(sz(2) -1)) .- v(:), sz(2)) +1
c_idx =
1 2 3 4 5 6
5 6 1 2 3 4
1 2 3 4 5 6
6 1 2 3 4 5
## Convert it to linear index
octave> idx = sub2ind (sz, repmat ((1:sz(1))(:), 1, sz(2)) , c_idx);
## All you need is to index
octave> A = A(idx)
A =
8 3 2 7 4 5
9 1 4 4 7 3
1 6 3 9 2 3
5 7 4 1 9 5
% A and v as above. These could be function input arguments
A = [1 0 0; 1 0 0; 1 0 0];
v = [0 1 2];
assert (all (size (v) == [1, size(A, 1)]), ...
'v needs to be a horizontal vector with as many elements as rows of A');
% Calculate shifted indices
[r, c] = size (A);
tmp = mod (repmat (0 : c-1, r, 1) - repmat (v.', 1, c), c) + 1;
Out = A(sub2ind ([r, c], repmat ([1 : r].', 1, c), tmp))
Out =
1 0 0
0 1 0
0 0 1
If performance is an issue, you can replace repmat with an equivalent bsxfun call which is more efficient (I use repmat here for simplicity to demonstrate the approach).
With focus on performance, here's one approach using bsxfun/broadcasting -
[m,n] = size(A);
idx0 = mod(bsxfun(#plus,n-v(:),1:n)-1,n);
out = A(bsxfun(#plus,(idx0*m),(1:m)'))
Sample run -
A =
1 7 5 7 7
4 8 5 7 6
4 2 6 3 2
v =
3 1 2
out =
5 7 7 1 7
6 4 8 5 7
3 2 4 2 6
Equivalent Octave version to use automatic broadcasting would look something like this -
[m,n] = size(A);
idx0 = mod( ((n-v(:)) + (1:n)) -1 ,n);
out = A((idx0*m)+(1:m)')
Shift vector with circshift in loop, iterating row index.

Dividing a vector to form different matrices

I have a two long vector. Vector one contains values of 0,1,2,3,4's, 0 represent no action, 1 represent action 1 and 2 represent the second action and so on. Each action is 720 sample point which means that you could find 720 consecutive twos then 720 consecutive 4s for example. Vector two contains raw data corresponding to each action. I need to create a matrix for each action ( 1, 2, 3 and 4) which contains the corresponding data of the second vector. For example matrix 1 should has all the data (vector 2 data) which occurred at the same indices of action 1. Any Help??
Example on small amount of data:
Vector 1: 0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2
Vector 2: 6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0
Result:
Matrix 1:
5 6 4
0 5 6
Matrix 2:
9 8 7
5 8 0
Here is one approach. I used a cell array to store the output matrices, hard-coding names for such variables isn't a good plan.
V1=[0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2]
V2=[6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0]
%// Find length of sequences of 1's/2's
len=find(diff(V1(find(diff(V1)~=0,1)+1:end))~=0,1)
I=unique(V1(V1>0)); %// This just finds how many matrices to make, 1 and 2 in this case
C=bsxfun(#eq,V1,I.'); %// The i-th row of C contains 1's where there are i's in V1
%// Now pick out the elements of V2 based on C, and store them in cell arrays
Matrix=arrayfun(#(m) reshape(V2(C(m,:)),len,[]).',I,'uni',0);
%// Note, the reshape converts from a vector to a matrix
%// Display results
Matrix{1}
Matrix{2}
Since, there is a regular pattern in the lengths of groups within Vector 1, that could be exploited to vectorize many things while proposing a solution. Here's one such implementation -
%// Form new vectors out of input vectors for non-zero elements in vec1
vec1n = vec1(vec1~=0)
vec2n = vec2(vec1~=0)
%// Find positions of group shifts and length of groups
df1 = diff(vec1n)~=0
grp_change = [true df1]
grplen = find(df1,1)
%// Reshape vec2n, so that we end up with N x grplen sized array
vec2nr = reshape(vec2n,grplen,[]).' %//'
%// ID/tag each group change based on their unique vector 2 values
[R,C] = sort(vec1n(grp_change))
%// Re-arrange rows of reshaped vector2, s.t. same ID rows are grouped succesively
vec2nrs = vec2nr(C,:)
%// Find extents of each group & use those extents to have final cell array output
grp_extent = diff(find([1 diff(R) 1]))
out = mat2cell(vec2nrs,grp_extent,grplen)
Sample run for the given inputs -
>> vec1
vec1 =
0 0 1 1 1 0 0 2 2 2 ...
0 0 1 1 1 0 0 2 2 2
>> vec2
vec2 =
6 7 5 6 4 6 5 9 8 7 ...
9 7 0 5 6 4 1 5 8 0
>> celldisp(out)
out{1} =
5 6 4
0 5 6
out{2} =
9 8 7
5 8 0
Here is another solution:
v1 = [0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2];
v2 = [6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0];
m1 = reshape(v2(v1 == 1), 3, [])'
m2 = reshape(v2(v1 == 2), 3, [])'
EDIT: David's solution is more flexible and probably more efficient.

Permute the Matrix with Given Index

Given A is symmetry matrix with size n and
A =
1 2 3 4 5 % The Position
1 [0 5 2 4 1
2 5 0 3 0 2
3 2 3 0 0 0
4 4 0 0 0 5
5 1 2 0 5 0]
B is a row vector that permute the matrix A row and column
B = [2 4 1 5 3]
The output that I want is
C =
2 4 1 5 3 % The New Position given by Matrix B
2 [0 0 5 2 3
4 0 0 4 5 0
1 5 4 0 1 2
5 2 5 1 0 0
3 3 0 2 0 0]
I can get the output by using simple for loop
index = [2,4,1,5,3];
C = zeros(5,5);
for i = 1:5
for j = 1:5
% Position of in square matrix n
% (i,j) = (i-1)*n + j
C(i,j) = A((index(i)-1)*5+index(j));
end
end
However, if I want to permute a matrix with size 80x80, then I need to run 1600 times in order to get the output.
Is there any simple trick to do it instead of using for loop?
You should be able to rearrange your matrices as follows:
C = A(index,index);
This rearranges each dimension according to the index variable independently.

Find position of vector in matrix [duplicate]

This question already has answers here:
General method to find submatrix in matlab matrix
(3 answers)
Closed 8 years ago.
I have the vector:
1 2 3
and the matrix:
4 1 2 3 5 5
9 8 7 6 3 1
1 4 7 8 2 3
I am trying to find a simple way of locating the vector [1 2 3] in my matrix.
A function returning either coordinates (Ie: (1,2:4)) or a matrix of 1s where there is a match a 0s where there isn't, Ie:
0 1 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
So far, the only function I've found is is 'ismember', which however only tells me if the individual components of the vector appear in the matrix. Suggestions?
Use strfind with a linearized version of the matrix, and then convert linear indices to subindices. Care should be taken to remove matches of the vector spanning different rows.
mat = [1 2 3 1 2 3 1 2;
3 0 1 2 3 5 4 4]; %// data
vec = [1 2 3]; %// data
ind = strfind(reshape(mat.',[],1).', vec);
[col row] = ind2sub(fliplr(size(mat)), ind);
keep = col<=size(mat,2)-length(vec)+1; %// remove result split across rows
row = row(keep);
col = col(keep);
Result for this example:
>> row, col
row =
1 1 2
col =
1 4 3
meaning the vector appears three times: row 1, col 1; row 1, col 4; row 2, col 3.
The result can be expressed in zero-one form as follows:
result = zeros(fliplr(size(mat)));
ind_ones = bsxfun(#plus, ind(keep).', 0:numel(vec)-1);
result(ind_ones) = 1;
result = result.';
which gives
>> result
result =
1 1 1 1 1 1 0 0
0 0 1 1 1 0 0 0
One way to get the starting location of the vector in the matrix is using colfilt:
>> A = [1 2 3 1 2 3 1 2; ...
3 0 1 2 3 5 4 4]; % matrix from Luis Mendo
>> T = [1 2 3];
>> colFun = #(x,t) all(x==repmat(t,1,size(x,2)),1);
>> B = colfilt(A,size(T),'sliding',colFun,T(:))
B =
0 1 0 0 1 0 0 0
0 0 0 1 0 0 0 0
That gives a mask of the center points, which translate to (row,col) coordinates:
>> [ii,jj]=find(B);
>> locs = bsxfun(#minus,[ii jj],floor((size(T)-1)/2))
locs =
1 1
2 3
1 4