Использование accumarray и @min для извлечения min из групп, а также для вывода соответствующих значений из другой переменной / столбца
У меня есть 3 столбца данных:
time = [1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16];
category = [1;1;1;1;2;2;2;2;3; 3; 3; 3; 4; 4; 4; 4];
data = [1;1;0;1;2;2;1;2;3; 3; 2; 3; 4; 4; 4; 3];
Я использую следующее, чтобы извлечь минимальные значения данных для каждой категории:
groupmin = accumarray(category,data,[],@min)
Какие выводы:
groupmin = [0;1;2;3]
Тем не менее, я действительно хотел бы иметь вывод, который также говорит мне, с какого момента времени минимумы, например,
timeofgroupmin = [3;7;11;16]
groupmin = [0;1; 2; 3]
В качестве альтернативы, я хотел бы получить минимумы в собственном векторе с NaN для любой строки, которая не является минимумом ее группы, например
groupminallrows = [NaN;NaN;0;NaN;NaN;NaN;1;NaN;NaN;NaN;2;NaN;NaN;NaN;NaN;3];
Любой подход решит мою проблему. Как новичок в Matlab, я изо всех сил пытаюсь узнать, какие термины искать.
3 ответа
Это работает, если все данные одной категории находятся в одном прогоне, а категории отсортированы, как в вашем примере. В каждой категории допускается несколько минимизаторов.
r = accumarray(category,data,[],@(v) {(min(v)==v)});
r = vertcat(r{:});
groupminallrows = NaN(size(data));
groupminallrows(r) = data(r);
Использование accumarray
с пользовательской функцией:
time = [1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16];
category = [1;1;1;1;2;2;2;2;3; 3; 3; 3; 4; 4; 4; 4];
data = [1;1;0;1;2;2;1;2;3; 3; 2; 3; 4; 4; 4; 3];
groupmin = accumarray( A(:,1), A(:,2), [], @min)
Это то, что у вас есть, но для получения индексов минимумов и их времени вам понадобится второй вывод min
функция, которую я не знаю, возможно ли получить при использовании с accmarray. Но есть следующий обходной путь:
groupidx = accumarray( category, data, [], @(x) find(x == min(x) )).'
occ = cumsum(hist(category,unique(category)))
idx = -occ(1)+occ+groupidx;
timeofgroupmin = time(idx).'
groupmin = data(idx).'
groupmin =
0 1 2 3
timeofgroupmin =
3 7 11 16
Желаемый NaN
-вектор можно получить как:
groupminallrows = NaN(1,numel(data));
groupminallrows(idx) = data(idx)
По поводу вашего комментария:
Я предполагаю, что причина в том, что у вас есть несколько минимумов в каждой группе, то find
возвращает массив. Чтобы решить, что вы можете заменить find(x == min(x))
с find(x == min(x),1)
, Но тогда вы просто получите первое вхождение каждого минимума в каждой группе.
Если это не желательно, я бы сказал, accumarray
как правило, неправильный путь.
Попробуйте это решение:
% first we group the data into cell according to the group they belong to
grouped = accumarray(category, data, [], @(x){x});
% find the minimum and corresponding index of each group
[mn,idx] = cellfun(@min, grouped);
% fix index by offsetting the position to point the whole data vector
offset = cumsum([0;cellfun(@numel, grouped)]);
idx = idx + offset(1:end-1);
% result
[mn(:) idx(:)]
assert(isequal(mn, data(idx)))
% build the vector with NaNs
mnAll = nan(size(data));
mnAll(idx) = mn;
Полученные векторы:
>> mn'
ans =
0 1 2 3
>> idx'
ans =
3 7 11 16
>> mnAll'
ans =
NaN NaN 0 NaN NaN NaN 1 NaN NaN NaN 2 NaN NaN NaN NaN 3
РЕДАКТИРОВАТЬ:
Вот альтернативное решение:
% find the position of min value in each category
idx = accumarray(category, data, [], @minarg);
% fix position in terms of the whole vector
offset = cumsum([0;accumarray(category,1)]);
idx = idx + offset(1:end-1);
% corresponding min values
mn = data(idx);
Я использую следующую пользовательскую функцию для извлечения второго выходного аргумента из min
:
minarg.m
function idx = minarg(X)
[~,idx] = min(X);
end
Результаты такие же, как указано выше.