2016-10-19 21 views
2

Ich möchte die Anzahl der Spalten in einer Matrix zeilenweise reduzieren, indem Sie abhängig von einem für jede Zeile angegebenen Spaltenindex eine Aktion ausführen. Angesichts die folgende Beispiel Daten:Effiziente Möglichkeit, jede Zeile einer Matrix basierend auf einem Spaltenindex für jede Zeile zu reduzieren

M = magic(4); 
col_ind = [1; 3; 2; 4]; 

Ich möchte eine drei Säulenmatrix machen, so dass die erste Spalte enthält die Zeilensumme jeder Reihe bis zum angegebenen Spaltenindex enthält die zweite Spalte den Wert des M in dieser Reihe, von dem Spaltenindex angegeben, und die letzte Spalte enthält die Reihensumme des Restes der Einträge in dieser Reihe, das heißt, erzeugt die Matrix M_out:

M_out = nan(4,3); 
for i = 1:4 
    M_out(i, :) = [sum(M(i, 1:col_ind(i)-1), 2), ... 
     M(i, col_ind(i)), sum(M(i, col_ind(i)+1:end), 2)]; 

end 

so dass:

>> M_out 

M_out = 

    0 16 18 
    16 10  8 
    9  7 18 
    33  1  0 
+1

Check out 'tril',' diag', 'cumsum' und' bsxfun'. –

+0

Ah ja, ich sehe, wie ich Cumsum über Reihen mit linearer Indexierung verwenden könnte. – Alex

Antwort

3

Nach Stewie's comment, ich werde es hier unter Verwendung tril tun. Die zweite Spalte ist einfach unter Verwendung sub2ind. Dann wird die dritte Spalte wird trivial:

T = tril(ones(size(M, 2)), -1); 
M_out = zeros(size(M, 1), 3); 
M_out(:, 1) = sum(T(col_ind,:) .* M, 2); 
M_out(:, 2) = M(sub2ind(size(M), (1:size(M, 1)).', col_ind)); 
M_out(:, 3) = sum(M, 2) - sum(M_out, 2); 

Oder ein bisschen effizienter mit cumsum:

cs = cumsum(M, 2); 
M_out = zeros(size(M, 1), 3); 
M_out(:, 2) = M(sub2ind(size(M), (1:size(M, 1)).', col_ind)); 
M_out(:, 1) = cs(sub2ind(size(cs), (1:size(cs, 1)).', col_ind)) - M_out(:, 2); 
M_out(:, 3) = cs(:, end) - sum(M_out, 2); 
+1

Schön, aber 'arrayfun' ist ein Wolf im Schafspelz ... Es ist _always_ langsamer als explizite Schleifen (aber kürzer und einfacher zu schreiben, wenn das ist Hauptziel). Ich denke, ich bevorzuge den OP-Code, wenn er in Abschnitte unterteilt wurde, die einfacher zu lesen sind ('M (1, :) = ...; M (2, :) = ...;'). Ich schlage vor, Sie ersetzen "abc" durch "M_out (1, :) M_out (2, :) M_out (3, :)' obwohl, aber das liegt an dir, –

+0

Danke, ich wusste, dass 'arrayfun' langsam ist, aber ich wusste nicht, dass es langsamer ist als die Schleife ...! Jetzt werde ich versuchen, meinen Code entsprechend Ihrem Kommentar zu der Frage zu ändern! – erfan

+2

'arrayfun' ist eine verklärte' for' Schleife mit viel Overhead. Der einzige Nutzen, den ich jemals für 'arrayfun' habe, ist, dass er Zellen-Arrays erzeugen kann. – rayryeng

Verwandte Themen