Replace array value at SOME specific rows in matlab - matlab

I try to replace the array values at some specific row (row number 1, 10, 12, 20, 39 etc, not continuous) using the linear index from find. However I don't know how to proceed after this few lines of code:
[valmax, ~]=max(A); %Where A will consist of more than one MAX value
idxmax=find(A==valmax);
mclr=repmat([1 0 0],[10 1]); %Create the matrix of my value
mclr(idxmax,:)=[0 1 0]; %replace the value at idxmax index, this line won't work
Any idea how to fix this? Or there are other function instead of using find?
Thanks!

you can use ind2sub to convert the linear indexes into row indexes:
A = randi(5,[10 3]); % random matrix
[valmax, ~] = max(A(:)); %Where A will consist of more than one MAX value
idxmax = find(A == valmax);
% convert linear index into row index
[rowmax,colmax] = ind2sub(size(A),idxmax);
rowmax = unique(rowmax); % get unique rows
mclr = repmat([1 0 0],[10 1]); %Create the matrix of my value
mclr(rowmax,:) = repmat([0 1 0],[numel(rowmax) 1]); %replace the value at idxmax index
however it's more efficient to directly get the rows containing max values using any(X, 2):
rowmax = find(any(A == valmax,2));

Related

How do I split a very large matrix into submatrices based on the value in a column?

I have a 5 x 600,000 matrix. I've had an idea to group the data so I want to group this matrix into submatrices based on the values in column 4.
For values between 0 and 500, I want one matrix, for values between 501 and 1000 I want another, and for values between 1001 and 1500 I want another.
How can I do this?
I currently don't have any reliable material, I have seen some examples online but they only seem to feature 2 variables (i.e. with value 1 or 0 in a column and grouping the 1s and the 0s into 2 submatrices).
I think in Matlab-speak you mean you have an nxm matrix where n=600000, m=5, but if not you can change accordingly.
Is this what you were looking to do?
n=600000;
m=5;
thisCol =4;
values_range = {[0,500];[501,1000];[1001,1500]}; % cell array of vectors
myMatrix = zeros(n,m);
myMatrix(:,thisCol) = 1:600000; % to prove it works.
theseSubMatrices = cell(length(values_range),1); % cell array of matrices
for j=1:length(values_range)
thisLow= values_range{j}(1);
thisHigh= values_range{j}(2);
theseSubMatrices{j} = myMatrix(myMatrix(:,thisCol)>=thisLow & myMatrix(:,thisCol)<=thisHigh,:);
end
If you have some data
arr = rand( 6e5, 5 ); % 5 columns / 600,000 rows
arr(:,5) = arr(:,5) .* 1500; % for this example, get column 5 into range [0,1500]
Then you can use histcounts to "bin" the 5th column according to your edges.
edges = [0, 500, 1000, 1500]; % edges to split column 5 by
[~,~,iSubArr] = histcounts( arr(:,5), edges );
And generate a cell array with one element per sub array
nSubArr = numel(edges)-1; % number of bins / subarrays
subArrs = arrayfun( #(x) arr( iSubArr == x, : ), 1:nSubArr, 'uni', 0 ); % Get a matrix per bin
Output:
subArrs =
1×3 cell array
{200521×5 double} {199924×5 double} {199555×5 double}

Get vector of columns with highest values in matrix

I'd like to be able to create a column vector whose values in each row correspond to the column in a matrix with the max value in that specific row.
For example,
If I have a matrix such as:
A = [1,5,2;3,1,1;0,1,0];
I'd end up with the matrix:
maxValueColumns = transpose([2,1,2]);
Is there an easy/efficient way to do this?
You're looking for max():
A = [1,5,2;3,1,1;0,1,0];
[~, maxValueColumns] = max(A, [], 2); % 'maxValueColumns' will contain [2; 1; 2]

delete elements from a matrix and calculate mean

I have an N-by-M-Matrix as input called GR wich consists of the following numbers: -3,0,2,4,7,10,12
And I have to return a vector. If M=1, then it should just return the input.
If M>1 It should remove the lowest number from the matrix and then calculate the mean of the remaining numbers.
However, if one of the numbers in the row is -3, it should return the value -3 in the output.
My thoughts of the problem:
Is it possible to make a for loop?
for i=1:length(GR(:,1))
If length(GR(1,:))==1
GR=GR
end
If length(GR(1,:))>1
x=min(GR(i,:))=[] % for removing the lowest number in the row
GR=sum(x)/length(x(i,:))
I just don't have any Idea of how to detect if any of the numbers in the row is -3 and then return that value instead of calculating the mean and when I tried to delete the lowest number in the matrix using x=min(GR(i,:)) matlab gave me this error massage 'Deletion requires an existing variable.'
I put in a break function. As soon as it detects a -3 value it breaks from the loop. Same goes for the other function.
Note that it is an i,j (M*N) matrix. So you might need to change your loop.
for i=1:length(GR(:,1))
if GR(i,1)==-3
GR=-3
break
end
If length(GR(1,:))==1
GR=GR
break
end
If length(GR(1,:))>1
x=min(GR(i,:))=[] % for removing the lowest number in the row
GR=sum(x)/length(x(i,:))
end
end
you can use Nan's, nanmean, any, and dim argument in these functions:
% generate random matrix
M = randi(3);
N = randi(3);
nums = [-3,0,2,4,7,10,12];
GR = reshape(randsample(nums,N*M,true),[N M]);
% computation:
% find if GR has only one column
if size(GR,2) == 1
res = GR;
else
% find indexes of rows with -3 in them
idxs3 = any(GR == -3,2);
% the (column) index of the min. value in each row
[~,minCol] = min(GR,[],2);
% convert [row,col] index pair into linear index
minInd = sub2ind(size(GR),1:size(GR,1),minCol');
% set minimum value in each row to nan - to ignore it on averaging
GR(minInd) = nan;
% averaging each rows (except for the Nans)
res = nanmean(GR,2);
% set each row with (-3) in it to (-3)
res(idxs3) = -3;
end
disp(res)

Index of Min of each line in a matrix without loop

I work on a matrix like this :
A=[1,2,3;5,4,6;9,8,7];
I want to get the index of each line. Here it is : Index = [1;2;3]
But how can I get this without a loop ?
I do this for the moment :
for k=1:length(A)
[~,Index(k)] = min(A(k,:));
end
From the documentation:
M = min(A,[],dim) returns the smallest elements along dimension dim. For example, if A is a matrix, then min(A,[],2) is a column vector containing the minimum value of each row.
Looking at output options, you can see
[M,I] = min(___) finds the indices of the minimum values of A and returns them in output vector I.
You were already using the second part of the above documentation notes, so just combine the two...
A=[1,2,3; 5,4,6; 9,8,7];
[~, idx] = min(A, [], 2);
% result: idx = [1; 2; 3];

Building a map from a matrix in Matlab

I have a matrix A which holds integers in a bounded range (0..255) and I need to build a table mapping a value (0..255) to all the coordinates in the matrix which hold this value.
What is the best way to achieve this? - I thought about using containers.Map for the task but Map doesn't support multiple values per key. I could have used lists but that would seem inefficient as I would have to create a new list on each iteration.
A vectorized solution, which gives the same output as the solution from Mikhail, is to sort all the pixel values in your image using the SORT function, convert the linear indices returned from SORT into subscripted indices using the function IND2SUB, and collect them together into a single cell array using the functions ACCUMARRAY and MAT2CELL:
A = randi([0 255],[5 5],'uint8'); %# A sample matrix
[values,indices] = sort(double(A(:))); %# Sort all the pixel values
[y,x] = ind2sub(size(A),indices); %# Convert linear index to subscript
counts = accumarray(values+1,1,[256 1]); %# Count number of each value
map = mat2cell([y x],counts); %# Create a 256-by-1 cell array
Now, for a given integer value iValue you can get the N-by-2 matrix containing the y (first column) and x (second column) coordinates for the N pixels in the image with that value by doing the following:
key = double(iValue)+1; %# Need to use double to avoid integer saturation
points = map{key}; %# An N-by-2 coordinate matrix
In addition, just in case you're interested, you could also make map a structure array with fields x and y using the function STRUCT:
map = struct('x',mat2cell(x,counts),'y',mat2cell(y,counts));
And you can then access the x and y coordinates for pixels with a value iValue as follows:
key = double(iValue)+1;
x = map(key).x;
y = map(key).y
What about using a cell array? You can index it with integers. For example:
map = {[1,1;13,56], [], [4,5]};
In this example index 0 is in the matrix in 1,1 and 13,56, index 1 in none and index 2 in 4,5
Your cell would have 256 elements (mine has 3) and to acces you would simply add 1 to the index.
You could also store indices linearly so the code to fill the table would be:
for ii = 0:255
map{ii+1} = find( mat(:)==ii )
end
Well, I wrote the following and it seems to work in reasonable time. I think the thing that does the trick is preallocating the cell arrays based on the histogram for each value:
[H, W] = size(A);
histogram = hist(A, 256);
AGT = arrayfun(#(avg) {0 cell(1, histogram(avg))}, 1:256, 'UniformOutput', false);
for y = 1:H
for x = 1:W
idx = A(y, x) + 1;
count = AGT{idx}{1};
AGT{idx}{2}{count + 1} = [y x];
AGT{idx}{1} = count + 1;
end
end
Accessing the table is a bit annoyting though :
AGT{200}{2}{:}
to access all coordinates with value 200.