Reputation: 89
I have a cell array that looks like:
ID Weight Position
'img1' [23.6793] [6]
'img1' [22.6368] [2]
'img1' [22.8294] [4]
'img2' [24.3452] [8]
'img2' [25.0608] [3]
'img2' [25.2548] [9]
'img2' [27.1751] [12]
'img2' [25.7463] [5]
'img2' [23.6599] [2]
'img3' [27.1899] [4]
'img3' [28.0790] [1]
'img3' [27.6633] [2]
'img3' [28.9362] [3]
I want to create a new column that contains the maximum weight for each ID and the position for that maximum weight. The result should look like:
ID Weight Position Max_Weight Max_Weight_Pos
'img1' [23.6793] [6] [23.6793] [6]
'img1' [22.6368] [2] [23.6793] [6]
'img1' [22.8294] [4] [23.6793] [6]
'img2' [24.3452] [8] [27.1751] [12]
'img2' [25.0608] [3] [27.1751] [12]
'img2' [25.2548] [9] [27.1751] [12]
'img2' [27.1751] [12] [27.1751] [12]
'img2' [25.7463] [5] [27.1751] [12]
'img2' [23.6599] [2] [27.1751] [12]
'img3' [27.1899] [4] [28.9362] [3]
'img3' [28.0790] [1] [28.9362] [3]
'img3' [27.6633] [2] [28.9362] [3]
'img3' [28.9362] [3] [28.9362] [3]
Is there an easy way to do this?
Thanks.
Upvotes: 1
Views: 50
Reputation: 104503
First let's recreate your cell array:
>> C = {'img1' [23.6793] [6]
'img1' [22.6368] [2]
'img1' [22.8294] [4]
'img2' [24.3452] [8]
'img2' [25.0608] [3]
'img2' [25.2548] [9]
'img2' [27.1751] [12]
'img2' [25.7463] [5]
'img2' [23.6599] [2]
'img3' [27.1899] [4]
'img3' [28.0790] [1]
'img3' [27.6633] [2]
'img3' [28.9362] [3]};
I'll approach this in another way instead of using accumarray
as per thewaywewalk.... but I would have done it that way if I had the chance!
Another suggestion I have would be to loop over all unique labels, find the maximum within the groups and get the corresponding position information as well as the maximum of each group.
Something like this:
%// Get the labels
labels = unique(C(:,1));
%// Convert data and positions to numerical
data = vertcat(C{:,2});
positions = vertcat(C{:,3});
%// To store the maximum values and positions of each group
out_data = zeros(size(labels,1), 1);
pos_data = out_data;
for idx = 1 : numel(labels)
lbl = labels{idx}; %// Get the ith label
%// Determine the indices of the labels that match
ind = strcmp(lbl, C(:,1));
%// Get the numbers and positions
num = data(ind);
pos = positions(ind);
%// Find maximum value and position
[out_data(idx) ind] = max(num);
pos_data(idx) = pos(ind);
end
% // Now place into cell array
C(:,4) = num2cell(out_data(id));
C(:,5) = num2cell(pos_data(id));
We get:
>> C
C =
'img1' [23.6793] [ 6] [23.6793] [ 6]
'img1' [22.6368] [ 2] [23.6793] [ 6]
'img1' [22.8294] [ 4] [23.6793] [ 6]
'img2' [24.3452] [ 8] [27.1751] [12]
'img2' [25.0608] [ 3] [27.1751] [12]
'img2' [25.2548] [ 9] [27.1751] [12]
'img2' [27.1751] [12] [27.1751] [12]
'img2' [25.7463] [ 5] [27.1751] [12]
'img2' [23.6599] [ 2] [27.1751] [12]
'img3' [27.1899] [ 4] [28.9362] [ 3]
'img3' [28.0790] [ 1] [28.9362] [ 3]
'img3' [27.6633] [ 2] [28.9362] [ 3]
'img3' [28.9362] [ 3] [28.9362] [ 3]
Upvotes: 0
Reputation: 25232
Thats a job for accumarray
:
[~,~,u] = unique(data(:,1));
maxima = accumarray(u,[data{:,2}],[],@max)
temp = cell2mat(data(:,[2,3]))
pos = accumarray(u,1:size(data,1),[],@(x) getfield(sortrows( temp(x,:),1),{numel(x),2}) )
output = [data num2cell(maxima(u)) num2cell(pos(u))]
I used @max
as you were asking for the maximum, your output actually shows @min
. But you could apply any function (@mean
, etc.).
Upvotes: 3