Как мне усреднить группы строк в матрице, чтобы получить новую, меньшую матрицу? - PullRequest
3 голосов
/ 06 марта 2012

У меня очень большая матрица (216 строк, 31286 столбцов) двойников. По причинам, характерным для данных, я хочу усреднить каждые 9 строк, чтобы получить одну новую строку. Итак, новая матрица будет иметь 216/9 = 24 строки.

Я новичок в Matlab, поэтому мне было интересно, можно ли улучшить это решение, которое я придумала. По сути, он проходит по каждой группе, суммирует строки, а затем делит новую строку на 9. Вот упрощенная версия того, что я написал:

matrix_avg = []
for group = 1:216/9
    new_row = zeros(1, 31286);
    idx_low = (group - 1) * 9 + 1;
    idx_high = idx_low + 9 - 1;
    % Add the 9 rows to new_row
    for j = idx_low:idx_high
        new_row = new_row + M(j,:);
    end
    % Compute the mean
    new_row = new_row ./ 9
    matrix_avg = [matrix_avg; new_row];
end

Ответы [ 3 ]

8 голосов
/ 06 марта 2012

Вы можете reshape свою большую матрицу от 216 х 31286 до 9 х (216/9 * 31286).

Тогда вы можете использовать mean, который работает с каждым столбцом. Поскольку ваша матрица имеет только 9 строк на столбец, для этого требуется среднее значение из 9 строк.

Тогда вы можете просто reshape вернуть свою матрицу.

% generate big matrix
M = rand([216 31286]);
n = 9   % want 9-row average.

% reshape
tmp = reshape(M, [n prod(size(M))/n]);
% mean column-wise (and only 9 rows per col)
tmp = mean(tmp);
% reshape back
matrix_avg = reshape(tmp, [ size(M,1)/n size(M,2) ]);

В одной строке (но с чего бы вы?):

matrix_avg = reshape(mean(reshape(M,[n prod(size(M))/n])), [size(M,1)/n size(M,2)]);

Примечание - это будет иметь проблемы, если количество строк в M не будет делиться точно на 9, но так же будет и ваш исходный код.

1 голос
/ 07 марта 2012

Я измерил 4 решения и вот результаты:

reshape: Elapsed time is 0.017242 seconds.
blockproc [9 31286]: Elapsed time is 0.242044 seconds.
blockproc [9 1]: Elapsed time is 44.477094 seconds.
accumarray: Elapsed time is 103.274071 seconds.

Это код, который я использовал:

M = rand(216,31286);

fprintf('reshape: ');
tic;
n = 9;
matrix_avg1 = reshape(mean(reshape(M,[n prod(size(M))/n])), [size(M,1)/n size(M,2)]);
toc

fprintf('blockproc [9 31286]: ');
tic;
fun = @(block_struct) mean(block_struct.data);
matrix_avg2 = blockproc(M,[9 31286],fun);
toc

fprintf('blockproc [9 1]: ');
tic;
fun = @(block_struct) mean(block_struct.data);
matrix_avg3 = blockproc(M,[9 1],fun);
toc

fprintf('accumarray: ');
tic;
[nR,nC] = size(M);
n2average = 9;
[xx,yy] = ndgrid(1:nR,1:nC);
x = ceil(xx/n2average); %# makes xx 1 1 1 1 2 2 2 2 etc
matrix_avg4 = accumarray([xx(:),yy(:)],M(:),[],@mean);
toc
0 голосов
/ 06 марта 2012

Вот альтернатива, основанная на accumarray.Вы создаете массив с индексами строк и столбцов в matrix_avg, который сообщает вам, какому элементу в matrix_avg способствует данный элемент в M, затем вы используете accumarray для усреднения элементов, которые вносят вклад в тот же элемент в matrix_avg.Это решение работает, даже если число строк в M не делится на 9.

M = rand(216,31286);
[nR,nC] = size(M);
n2average = 9;

[xx,yy] = ndgrid(1:nR,1:nC);
x = ceil(xx/n2average); %# makes xx 1 1 1 1 2 2 2 2 etc

matrix_avg = accumarray([xx(:),yy(:)],M(:),[],@mean);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...