2016-03-29 5 views
3

Ich möchte den Mittelwert der letzten z. 3 Zahlen ungleich Null in jeder Spalte einer Matrix in Matlab. Die Spalten wurden am Ende mit Nullen gefüllt, um Vektoren gleicher Länge zu erzeugen.Wie man den Mittelwert des letzten z. 100 von Null verschiedene Zahlen in jeder Spalte einer Matrix in Matlab

Beispiel Matrix:

A = [5 6 3 5 6 8 9; 
    1 2 3 5 4 7 6; 
    0 1 2 3 4 5 6; 
    0 0 1 2 3 4 5; 
    0 0 0 1 2 3 4; 
    0 0 0 0 2 3 4; 
    0 0 0 0 2 3 4; 
    0 0 0 0 0 0 3] 
+1

Was ist, wenn Sie den Mittelwert von drei Nicht-Nullen wollen und es gibt nur 2 (wie in der ersten Spalte) – Suever

Antwort

2

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.

enter image description here

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 
+0

Vielen Dank @Suever foir die umfassende Antwort! – toocomplex