Es kann eine effizientere Lösung sein, aber eine Möglichkeit ist sum
zu verwenden, um die Anzahl von Nicht-Null-Zeilen in einer bestimmten Spalte zu finden. Dann schnappen Sie sich die Werte von A durch Durchlaufen aller Spalten mit arrayfun
und Mitteln der N
Zeilen vor der Null in der Spalte.
%// Number of elements to average
N = 3;
%// Last non-zero row in each column
lastrow = sum(A ~= 0, 1);
%// Ensure that we don't have any indices less than 1
startrow = max(lastrow - N + 1, 1);
%// Compute the mean for each column using the specified rows
means = arrayfun(@(k)mean(A(startrow(k):lastrow(k),k)), 1:size(A, 2));
Beispiel
Für Ihre Beispieldaten würde dies ergeben:
3.0000 3.0000 2.0000 2.0000 2.0000 3.0000 3.6667
UPDATE: Eine Alternative
Ein alternativer Ansatz Faltung zu verwenden, wäre dies tatsächlich zu lösen für Sie. Sie können einen Mittelwert mit einem Faltungskern berechnen. Wenn Sie den Mittelwert aller 3-reihigen Kombinationen einer Matrix wollen, würde Ihr Kernel sein:
kernel = [1; 1; 1] ./ 3;
Wenn mit der Matrix von Interesse convolved wird berechnet diese den Durchschnitt aller 3-reihigen Kombinationen innerhalb der Eingangsmatrix .
B = [1 2 3;
4 5 6;
7 8 9];
conv2(B, kernel)
0.3333 0.6667 1.0000
1.6667 2.3333 3.0000
4.0000 5.0000 6.0000
3.6667 4.3333 5.0000
2.3333 2.6667 3.0000
Im Beispiel unten, ich dies tun und dann wieder nur die Werte in den Bereichen, wir kümmern uns um
%// Find the last non-zero entry in each column
lastrow = sum(A ~= 0, 1);
%// Use convolution to compute the mean for every N rows
%// This will be applied to ALL of A
convmean = conv2(A, ones(N, 1)./N);
%// Select only the means that we care about
%// Because of the padding of CONV2, these will live at the rows
%// stored in LASTROW
means = convmean(sub2ind(size(convmean), lastrow, 1:size(A, 2)));
%// Now correct for cases where fewer than N samples were averaged
means = (means * N) ./ min(lastrow, N);
(wo der Durchschnitt nur die letzten
N
Nicht-Nullen in jeder Spalte zusammengesetzt ist)
Und der Ausgang wiederum ist der gleiche
3.0000 3.0000 2.0000 2.0000 2.0000 3.0000 3.6667
Vergleich
Ich habe ein schnelles Testskript ausgeführt, um die Leistung zwischen diesen beiden Methoden zu vergleichen. Es ist klar, dass der faltungsbasierte Ansatz viel schneller ist.
Hier ist der vollständige Testskript.
function benchmark()
dims = round(linspace(1, 1000, 100));
times1 = zeros(size(dims));
times2 = zeros(size(dims));
N = 3;
for k = 1:numel(dims)
A = triu(rand(dims(k)));
times1(k) = timeit(@()test_arrayfun(N, A));
A = triu(rand(dims(k)));
times2(k) = timeit(@()test_convolution(N, A));
end
figure;
plot(dims, times1);
hold on
plot(dims, times2);
legend({'arrayfun', 'convolution'})
xlabel('Dimension of A')
ylabel('Execution Time (seconds)')
end
function test_arrayfun(N, A)
%// Last non-zero row in each column
lastrow = sum(A ~= 0, 1);
%// Ensure that we don't have any indices less than 1
startrow = max(lastrow - N + 1, 1);
%// Compute the mean for each column using the specified rows
means = arrayfun(@(k)mean(A(startrow(k):lastrow(k),k)), 1:size(A, 2));
end
function test_convolution(N, A)
%// Find the last non-zero entry in each column
lastrow = sum(A ~= 0, 1);
%// Use convolution to compute the mean for every N rows
%// This will be applied to ALL of A
convmean = conv2(A, ones(N, 1)./N);
%// Select only the means that we care about
%// Because of the padding of CONV2, these will live at the rows
%// stored in LASTROW
means = convmean(sub2ind(size(convmean), lastrow, 1:size(A, 2)));
%// Now correct for cases where fewer than N samples were averaged
means = (means * N) ./ min(lastrow, N);
end
Was ist, wenn Sie den Mittelwert von drei Nicht-Nullen wollen und es gibt nur 2 (wie in der ersten Spalte) – Suever