Я ищу простой способ получить среднее значение по столбцам подмножества значений в матрице (индексированное логической матрицей), желательно без использования цикла. Проблема, с которой я сталкиваюсь, заключается в том, что, поскольку количество значений в каждом столбце различно, Matlab сворачивает матрицу значений, и ее среднее значение по столбцам становится общим средним (всей матрицы). Есть ли конкретная функция или простой обходной путь для этой проблемы? См. пример ниже.
%% define value matrix and logical indexing matrix
values=[1 2 3 4; 5 6 7 8; 9 10 11 12];
indices=[1 0 0 1; 0 1 0 1; 1 1 0 0];
indices=indices==1; %convert to logical
%% calculate column-wise average
mean(values(indices),1)
accumarray
подходИспользуйте индекс столбца в качестве группирующей переменной для accumarray
:
[~, col] = find(indices);
result = accumarray(col(:), values(indices), [size(values,2) 1], @mean, NaN).';
Обратите внимание, что:
Во второй строке используется (:)
, чтобы сделать первый вход вектор-столбцом. Это необходимо, потому что первая строка может создать col
как вектор-строку или столбец, в зависимости от размера indices
.
NaN
используется в качестве значения заполнения. Это указано как пятый вход в accumarray
.
Третий вход в accumarray
определяет размер вывода. Необходимо указать это явно (вместо того, чтобы позволить accumarray
понять это), если последние столбцы indices
содержат только false
.
Умножьте и разделите поэлементно на indices
. Это превратит нежелательные записи в NaN
, которые затем можно проигнорировать mean
с помощью опции 'omitnan'
:
result = mean(values.*indices./indices, 1, 'omitnan');
Умножьте поэлементно на indices
, просуммируйте каждый столбец и разделите поэлементно на сумму каждого столбца indices
:
result = sum(values.*indices, 1) ./ sum(indices, 1);
Почему без петель? Я уверен, что для размеров массивов, где важна реализация (т.е. очень большие массивы, для обработки которых требуется нетривиальное время), циклический подход будет самым быстрым. Циклы больше не медленные в MATLAB, и они не были, по крайней мере, 15 лет. Пришло время людям отказаться от этого менталитета «избегать петель любой ценой».