3 Stimmen

Wie sollte ich Gruppen von Zeilen in einer Matrix mitteln, um eine neue, kleinere Matrix zu erhalten?

Ich habe eine sehr große Matrix (216 Zeilen, 31286 Spalten) mit Doppelwerten. Aus datenbedingten Gründen möchte ich alle 9 Zeilen mitteln, um eine neue Zeile zu erzeugen. Die neue Matrix wird also 216/9=24 Zeilen haben.

Ich bin ein Matlab-Anfänger und frage mich, ob diese Lösung, die ich mir ausgedacht habe, verbessert werden kann. Grundsätzlich wird jede Gruppe in einer Schleife durchlaufen, die Zeilen summiert und dann die neue Zeile durch 9 geteilt. Hier ist eine vereinfachte Version dessen, was ich geschrieben habe:

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

8voto

mathematical.coffee Punkte 54672

Sie können reshape Ihre große Matrix von 216 x 31286 auf 9 x (216/9 * 31286).

Dann können Sie mean die auf jede Spalte wirkt. Da Ihre Matrix nur 9 Zeilen pro Spalte hat, wird der Durchschnitt aus 9 Zeilen ermittelt.

Dann können Sie einfach reshape Ihre Matrix zurück.

% 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) ]);

In einem Einzeiler (aber warum sollten Sie?):

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

Hinweis: Dies führt zu Problemen, wenn die Anzahl der Zeilen in M ist nicht genau durch 9 teilbar, aber das gilt auch für Ihren ursprünglichen Code.

1voto

zenpoy Punkte 19010

Ich habe die 4 Lösungen gemessen, und hier sind die Ergebnisse:

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.

Dies ist der von mir verwendete Code:

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

0voto

Jonas Punkte 74252

Hier ist eine Alternative, die auf accumarray . Sie erstellen ein Array mit Zeilen- und Spaltenindizes in matrix_avg das Ihnen sagt, welches Element in matrix_avg ein bestimmtes Element in M beiträgt, dann verwenden Sie accumarray um den Durchschnitt der Elemente zu ermitteln, die zu demselben Element in matrix_avg . Diese Lösung funktioniert auch, wenn die Anzahl der Zeilen in M ist nicht durch 9 teilbar.

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);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X