one-by-one matrix assignment MATLAB - matlab

I need to find the minimum values in each column of matrix "A", and then replace those min values with the values in last row of matrix "B" (which has same number of columns). Like I have these:
>> A = randi(10,10,5)
A =
3 5 9 5 8
7 6 4 10 2
8 4 1 7 4
4 7 2 8 2
7 5 8 7 5
3 7 10 10 1
5 7 8 5 7
8 3 8 2 3
6 10 2 1 10
3 7 6 7 2
>> B = randi(100,3,5)
B =
10 34 66 18 62
99 95 49 54 81
52 1 52 9 95
>> [M,I] = min(A)
M =
3 3 1 1 1
I =
1 8 3 9 6
And I want to replace the values of "M" with "B(end,:), so that:
A(1,1) = B(end,1);
A(8,2) = B(end,2);
A(3,3) = B(end,3);
A(9,4) = B(end,4);
A(6,5) = B(end,5);
I try "A(I) = B(end,:)" and "A(I(1,:)) = B(end,:)" but they do not work! Any ideas how I could do that? My real matrices are huge (1200x100000) so no way to do it by hand!

try this to replace the first min value:
A = [ 3 5 9 5 8;
7 6 4 10 2;
8 4 1 7 4;
4 7 2 8 2;
7 5 8 7 5;
3 7 10 10 1;
5 7 8 5 7;
8 3 8 2 3;
6 10 2 1 10;
3 7 6 7 2];
B =[ 10 34 66 18 62;
99 95 49 54 81;
52 1 52 9 95];
[M,I] = min(A)
A(sub2ind(size(A),I,1:size(A,2)))=B(end,:)
the output will be:
A =
52 5 9 5 8
7 6 4 10 2
8 4 52 7 4
4 7 2 8 2
7 5 8 7 5
3 7 10 10 95
5 7 8 5 7
8 1 8 2 3
6 10 2 9 10
3 7 6 7 2
However, when you have to replace all of the min values, use the code below instead
A = [ 3 5 9 5 8;
7 6 4 10 2;
8 4 1 7 4;
4 7 2 8 2;
7 5 8 7 5;
3 7 10 10 1;
5 7 8 5 7;
8 3 8 2 3;
6 10 2 1 10;
3 7 6 7 2];
B =[ 10 34 66 18 62;
99 95 49 54 81;
52 1 52 9 95];
M = min(A);
for i=1:size(A,2)
A(find(A(:,i) == M(i)),i)=B(end,i);
end;
A
the output is:
A =
52 5 9 5 8
7 6 4 10 2
8 4 52 7 4
4 7 2 8 2
7 5 8 7 5
52 7 10 10 95
5 7 8 5 7
8 1 8 2 3
6 10 2 9 10
52 7 6 7 2

You can acces you matrix by a single index, which looks like this:
Indeces =
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
Since you get the indeces for each individual column, you just need to increase it by the column number times the height of the matrix.
This should yield the correct result:
A( I + (0 : size(A,2)-1) * size(A,1) ) = B(end,:)

Related

How to exchange group of rows of a matrix in MATLAB?

I have a matrix A ,and vector x as following (left side)
where S0, H0,...is row number of each block. I want to exchange these blocks such that S0 and S1; H0 and H1 are near together as right side. This is my code
S0=3;
H0=2;
N0=2;
S1=4;
H1=5;
N1=4;
Cols=5;
Rows=S0+H0+N0+S1+H1+N1;
A=randi(10,[ Rows Cols]);
x=randi(10,[Rows 1]);
%% Exchange two block
temp=A(S0+H0+1:S0+H0+N0,1:end);
A(S0+H0+1:S0+H0+H1,1:end)=A(S0+H0+N0+S1+1:S0+H0+N0+S1+H1,1:end);
A(S0+H0+N0+S1+1:S0+H0+N0+S1+H1,1:end)=temp;
%% How exchange x
The above code is not work. How can I fixed it in MATLAB? Thank in advance.
One approach with mat2cell and cell2mat -
grps = [S0,H0,N0,S1,H1,N1]
new_pattern = [1 4 2 5 3 6]
celldata_roworder = mat2cell((1:size(A,1))',grps); %//'
newx = cell2mat(celldata_roworder(new_pattern)).'; %//'
newA = A(newx,:)
Sample run -
Input :
A =
6 8 9 8 7
4 8 8 3 4
3 8 2 1 10
5 2 6 8 3
5 7 4 7 7
4 5 6 8 7
6 3 4 7 4
8 1 5 5 2
5 9 2 4 1
5 2 3 9 5
2 2 1 4 2
1 7 10 9 8
3 9 7 8 4
4 6 10 9 9
7 8 2 6 8
10 2 10 7 6
10 10 8 10 2
5 6 6 5 10
3 7 5 1 3
8 1 3 9 10
grps =
3 2 2 4 5 4
new_pattern =
1 4 2 5 3 6
Output:
newx =
1 2 3 8 9 10 11 4 5 12 ...
13 14 15 16 6 7 17 18 19 20
newA =
3 3 2 5 8
4 3 3 7 7
1 5 2 8 1
4 6 4 1 4
7 1 5 8 8
4 9 10 10 8
7 10 10 4 3
7 3 1 6 9
2 9 2 6 10
1 1 7 10 3
10 10 10 4 7
9 1 8 9 5
8 7 4 5 7
9 8 7 5 3
1 10 7 6 8
8 1 10 6 1
4 6 3 3 2
7 9 3 2 9
6 9 7 4 8
6 7 6 8 10
I assume you are using a 2-dimensional matrix with Row rows and Cols columns.
You can use the colon : as a second index to address a full row, e.g. for the third row:
A(3, :)
(equal to A(3, 1:end) but little bit clearer).
So you could split your matrix into lines and re-arrange them like this (putting back together the lines to a two-dimensional matrix):
A = [ A(3:4, :); A(1:2, :); A(5:end, :) ]
This moves rows 3 and 4 at the beginning, then old lines 1 and 2 and then all the rest. Does this help you?
Hint: you can use eye for experimenting.

Reshape matrix by distributing submatrices to third dimension

I have a long nx3 matrix. For eg, I take a 9x3 matrix
A =
8 9 8
9 2 9
2 9 6
9 9 1
6 5 8
1 8 9
3 2 7
5 4 7
9 9 7
Now I want it reshaped, (taking successive 3x3 sub-matrix to the next dimension) such that,
out(:,:,1) =
8 9 8
9 2 9
2 9 6
out(:,:,2)
9 9 1
6 5 8
1 8 9
out(:,:,3)
3 2 7
5 4 7
9 9 7
I could do this with loops but I wanted to know how to vectorize this process..
Can i do it with reshape and permute alone?
Yes, you can use permute and reshape:
A = [...
8 9 8
9 2 9
2 9 6
9 9 1
6 5 8
1 8 9
3 2 7
5 4 7
9 9 7
3 2 7
5 4 7
9 9 7]
n = size(A,2);
B = permute( reshape(A.',n,n,[]), [2 1 3]) %'
%// or as suggested by Divakar
%// B = permute( reshape(A,n,n,[]), [1 3 2])
out(:,:,1) =
8 9 8
9 2 9
2 9 6
out(:,:,2) =
9 9 1
6 5 8
1 8 9
out(:,:,3) =
3 2 7
5 4 7
9 9 7
out(:,:,4) =
3 2 7
5 4 7
9 9 7
This could be one approach -
N = 3
out = permute(reshape(A,N,size(A,1)/N,[]),[1 3 2])
This one has the advantage of avoiding the transpose as used in the other answer by #thewaywewalk.
Sample run -
A =
8 9 8
9 2 9
2 9 6
9 9 1
6 5 8
1 8 9
3 2 7
5 4 7
9 9 7
out(:,:,1) =
8 9 8
9 2 9
2 9 6
out(:,:,2) =
9 9 1
6 5 8
1 8 9
out(:,:,3) =
3 2 7
5 4 7
9 9 7

Matlab filter matrix

My data matrix is large: smt like 180:3000 size.
Each element value is between 0 to 255;
I have to find areas in this matrix where average value is higher than some threshold (lets call it 'P'). And reset each element in these areas to '0'. Another words filter my matrix.
I have width and heigth of filter area.
So I need to loop over data matrix to find appropriate areas (As many as exist).
EDIT:
Please, see an example:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13
This is given matrix. Lets try to find areas (2, 3) of size where average value is > 15.
So the result will be:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
Please, look at bottom of matrix
Please, give me some tips how it is possible to loop throw.
Thank you very much.
One way of doint this is as follows:
% example A with more areas of mean greater than 15
% there are four such areas as shown here: http://i.imgur.com/V6m0NfL.jpg
A = [16 16 16 5 16 16 16
16 16 16 8 16 16 16
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 15.1 15 15 5 5
4 5 15 15 15 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13];
% filter size
[n,m] = deal(2,3);
% filter center
center = floor(([n,m]+1)/2);
% find where we have areas greater than 15
B = nlfilter(A, [n,m], #(b) mean(b(:)) > 15);
% get coordinates of areas with mean > 15
[rows,cols] = find(B);
% zero out elements in all found areas
for i = 1:size(rows,1)
% calculate starting coordinates for the area to be set to 0
row = rows(i) - center(1) + 1;
col = cols(i) - center(2) + 1;
A(row:row+n-1 , col:col+m-1) = 0;
end
Results in:
A =
0 0 0 5 0 0 0
0 0 0 8 0 0 0
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 0 0 0 5 5
4 5 0 0 0 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
try this
a = input_matrix;
ii = 2 ; jj = 3;
threshold = 15;
x = ones(ii,jj)/(ii*jj);
%\\create matrix temp2 with average value of block a(i:i+ii-1,j:j+jj-1) at temp2(i,j)
temp1 = conv2(a,x,'full');
temp2 = temp1(ii:end-ii+1,jj:end-jj+1);
%\\find row and column indices of temp2 with value > threshold
[row_ col_] = find(temp2>threshold);
out = a;
%\\assign zero value to the corresponding blocks
for iii = 1:length(row_)
out(row_(iii):row_(iii)+ii-1,col_(iii):col_(iii)+jj-1) = 0;
end

Getting all submatrices

I have got an N×M matrix m like:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
I want to get all submatrices of size P×Q (P,Q are odd) w/o employing a for-loop.
The result s should be a P×Q×((N-P+1)·(M-Q+1)) matrix.
E.g. if P=Q=3:
s(:,:,1) = [1 2 3; 5 6 7; 9 10 11]
s(:,:,2) = [2 3 4; 6 7 8; 10 11 12]
s(:,:,3) = [5 6 7; 9 10 11; 13 14 15]
s(:,:,4) = [6 7 8; 10 11 12; 14 15 16]
im2col can help you out here:
m =
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
>> P = 3; Q = 3;
>> columnized = im2col(m,[P Q],'sliding');
>> nMatrices = size(columnized,2);
>> s = reshape(columnized, [P Q nMatrices])
s(:,:,1) =
1 2 3
5 6 7
9 10 11
s(:,:,2) =
5 6 7
9 10 11
13 14 15
s(:,:,3) =
2 3 4
6 7 8
10 11 12
s(:,:,4) =
6 7 8
10 11 12
14 15 16
im2col with the 'sliding' option finds all the overlapping submatrices and returns each as a (P·Q)-element column vector in columnized. To turn these back into matrices, we reshape this (P·Q)×((N-P+1)·(M-Q+1)) matrix into a P×Q×((N-P+1)·(M-Q+1)) one.

MATLAB: Filling a matrix with each column being the same

I am trying to create a matrix that is 3 x n, with each of the columns being the same. What's the easiest way of achieving it? Concatenation?
After
n=7
x=[1;2;3]
it's either
repmat(x,[1 n])
or
x(:,ones(1,n))
(Octave can be considered as an open source/free version of MATLAB)
octave-3.0.3:2> rowvec = [1:10]
rowvec =
1 2 3 4 5 6 7 8 9 10
octave-3.0.3:3> [rowvec; rowvec; rowvec]
ans =
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Use repmat if the number of rows is large.
octave-3.0.3:7> repmat(rowvec, 10, 1)
ans =
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Use multiplication with a 1 x 3 matrix of ones
eg, x * [1 1 1]
Edit:
In Octave:
octave-3.0.3.exe:1> x = [1;2;3;4]
x =
1
2
3
4
octave-3.0.3.exe:5> x * [1 1 1]
ans =
1 1 1
2 2 2
3 3 3
4 4 4