it-swarm.com.de

Wie kann ich auf jede Zeile/Spalte einer Matrix in MATLAB eine Funktion anwenden?

Sie können auf jedes Element in einem Vektor eine Funktion anwenden, indem Sie beispielsweise v + 1 sagen oder die Funktion arrayfun verwenden. Wie kann ich dies für jede Zeile/Spalte einer Matrix tun, ohne eine for-Schleife zu verwenden?

95
FurtiveFelon

Viele integrierte Operationen wie sum und prod können bereits in Zeilen oder Spalten ausgeführt werden. Sie können also möglicherweise die von Ihnen angewendete Funktion umgestalten, um diese Funktion zu nutzen.

Wenn dies keine praktikable Option ist, besteht eine Möglichkeit darin, die Zeilen oder Spalten mithilfe von mat2cell oder num2cell in Zellen zu sammeln. Verwenden Sie dann cellfun , um das resultierende Zellenfeld zu bearbeiten.

Angenommen, Sie möchten die Spalten einer Matrix M summieren. Sie können dies einfach mit sum tun:

M = magic(10);           %# A 10-by-10 matrix
columnSums = sum(M, 1);  %# A 1-by-10 vector of sums for each column

Und so würden Sie dies mit der komplizierteren Option " num2cell / cellfun " tun:

M = magic(10);                  %# A 10-by-10 matrix
C = num2cell(M, 1);             %# Collect the columns into cells
columnSums = cellfun(@sum, C);  %# A 1-by-10 vector of sums for each cell
68
gnovice

Vielleicht möchten Sie die etwas unklarere Matlab-Funktion bsxfun . In der Matlab-Dokumentation wendet bsxfun "die Element-für-Element-Binäroperation an, die durch den Funktionshandle fun angegeben ist, auf die Arrays A und B, wobei die Erweiterung" Singleton "aktiviert ist."

@gnovice hat oben angegeben, dass sum und andere Grundfunktionen bereits für die erste Nicht-Singleton-Dimension wirksam sind (z. B. Zeilen, wenn es mehr als eine Zeile gibt, Spalten, wenn es nur eine Zeile gibt, oder höhere Dimensionen, wenn die unteren Dimensionen alle die Größe == 1 haben ). Bsxfun funktioniert jedoch für jede Funktion, einschließlich (und insbesondere) benutzerdefinierte Funktionen.

Angenommen, Sie haben eine Matrix A und einen Zeilenvektor B. Zum Beispiel sagen wir:

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

Sie möchten eine Funktion power_by_col, die in einem Vektor C alle Elemente in A an die Potenz der entsprechenden Spalte von B zurückgibt.

Im obigen Beispiel ist C eine 3x3-Matrix:

C = [1^0 2^1 3^2;
     4^0 5^1 6^2;
     7^0 8^1 9^2]

d.h.

C = [1 2 9;
     1 5 36;
     1 8 81]

Sie können dies mit roher Gewalt tun, indem Sie repmat verwenden:

C = A.^repmat(B, size(A, 1), 1)

Oder Sie können dies auf klassische Weise mit bsxfun tun, das intern den Repmat-Schritt übernimmt:

C = bsxfun(@(x,y) x.^y, A, B)

Bsxfun erspart Ihnen einige Schritte (Sie müssen die Abmessungen von A nicht explizit berechnen). Bei einigen informellen Tests von mir stellt sich jedoch heraus, dass Repmat ungefähr doppelt so schnell ist, wenn die anzuwendende Funktion (wie oben meine Power-Funktion) einfach ist. Sie müssen also entscheiden, ob Sie Einfachheit oder Geschwindigkeit wünschen.

23
Daniel Golden

Ich kann nicht sagen, wie effizient dies ist, aber hier ist eine Lösung:

applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :))
applyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1))'

% Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @sum;

applyToRows(myFunc, myMx)
19
Alex

Aufbauend auf Alex's Antwort , hier eine allgemeinere Funktion:

applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :));
newApplyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1), 'UniformOutput', false)';
takeAll = @(x) reshape([x{:}], size(x{1},2), size(x,1))';
genericApplyToRows = @(func, matrix) takeAll(newApplyToRows(func, matrix));

Hier ist ein Vergleich zwischen den beiden Funktionen:

>> % Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @(x) [mean(x), std(x), sum(x), length(x)];
>> genericApplyToRows(myFunc, myMx)

ans =

     2     1     6     3
     5     1    15     3
     8     1    24     3

>> applyToRows(myFunc, myMx)
??? Error using ==> arrayfun
Non-scalar in Uniform output, at index 1, output 1.
Set 'UniformOutput' to false.

Error in ==> @(func,matrix)arrayfun(applyToGivenRow(func,matrix),1:size(matrix,1))'
11
Wok

Der Vollständigkeit halber möchte ich noch hinzufügen, dass Matlab über eine Funktion verfügt, mit der Sie Daten pro Zeile und nicht pro Element bearbeiten können. Es heißt rowfun ( http://www.mathworks.se/help/matlab/ref/rowfun.html ), aber das einzige "Problem" ist, dass es mit tables ( http.) Arbeitet : //www.mathworks.se/help/matlab/ref/table.html ) und nicht matrices.

6
kamjagin

Mit der Entwicklung der Antwort auf diese Frage, beginnend mit r2016b, erweitert MATLAB implizit die Singleton-Dimensionen, wodurch in vielen Fällen bsxfun nicht erforderlich ist.

Aus den Versionshinweisen zu r2016b :

Implizite Erweiterung: Wenden Sie elementweise Operationen und Funktionen auf Arrays mit automatischer Erweiterung der Dimensionen der Länge 1 an

Implizite Erweiterung ist eine Verallgemeinerung der skalaren Erweiterung. Mit Bei der Skalarerweiterung wird ein Skalar so groß wie ein anderer Array, um elementweise Operationen zu erleichtern. Bei impliziter Erweiterung Die hier aufgeführten elementweisen Operatoren und Funktionen können implizit erweitern Sie ihre Eingaben auf die gleiche Größe, solange die Arrays kompatible Größen. Zwei Arrays haben kompatible Größen, wenn für jedes Abmessung sind die Abmessungsgrößen der Eingaben entweder gleich oder Einer davon ist 1. Siehe Kompatible Array-Größen für grundlegende Operationen und Weitere Informationen finden Sie unter Matrixoperationen.

Element-wise arithmetic operators — +, -, .*, .^, ./, .\

Relational operators — <, <=, >, >=, ==, ~=

Logical operators — &, |, xor

Bit-wise functions — bitand, bitor, bitxor

Elementary math functions — max, min, mod, rem, hypot, atan2, atan2d

Sie können zum Beispiel den Mittelwert jeder Spalte in einer Matrix A, .__ berechnen. und subtrahieren Sie dann den Vektor der Mittelwerte von jeder Spalte mit A - Mittelwert (A).

Zuvor war diese Funktionalität über die Funktion bsxfun .. verfügbar. Es wird jetzt empfohlen, die meisten Verwendungen von bsxfun durch direct .__ zu ersetzen. ruft die Funktionen und Operatoren auf, die die implizite Erweiterung unterstützen . Im Vergleich zur Verwendung von bsxfun bietet die implizite Erweiterung eine höhere Geschwindigkeit, bessere Speichernutzung und bessere Lesbarkeit von Code.

3
craigim

Die akzeptierte Antwort scheint zu sein, zuerst in Zellen zu konvertieren und dann cellfun zu verwenden, um alle Zellen zu bearbeiten. Ich kenne die spezifische Anwendung nicht, aber im Allgemeinen würde ich denken, dass die Verwendung von bsxfun zum Arbeiten über die Matrix effizienter wäre. Grundsätzlich wendet bsxfun eine Operation Element für Element auf zwei Arrays an. Wenn Sie also jedes Element in einem n x 1-Vektor mit jedem Element in einem m x 1-Vektor multiplizieren möchten, um ein n x m-Array zu erhalten, können Sie Folgendes verwenden:

vec1 = [ stuff ];    % n x 1 vector
vec2 = [ stuff ];    % m x 1 vector
result = bsxfun('times', vec1.', vec2);

Dadurch erhalten Sie eine Matrix mit dem Namen result, wobei der Eintrag (i, j) das i-te Element von vec1 multipliziert mit dem j-ten Element von vec2 ist.

Sie können bsxfun für alle Arten von integrierten Funktionen verwenden und Sie können eigene Funktionen angeben. Die Dokumentation enthält eine Liste mit vielen integrierten Funktionen. Grundsätzlich können Sie jedoch jede Funktion benennen, die zwei Arrays (Vektor oder Matrix) als Argumente akzeptiert, und sie zum Laufen bringen.

1
Engineero

Mit den neuesten Versionen von Matlab können Sie die Tabellendatenstruktur zu Ihrem Vorteil nutzen. Es gibt sogar eine "Rowfun" -Operation, aber ich fand es einfacher, dies zu tun:

a = magic(6);
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0))

oder hier ist ein älterer, den ich hatte, der für ältere Matlab-Versionen keine Tabellen benötigt.

dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)')
1
Jordan

Keine der obigen Antworten funktionierte für mich "out of the box", jedoch die folgende Funktion, die durch das Kopieren der Ideen der anderen Antworten erhalten wurde:

apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0));

Es nimmt eine Funktion f und wendet sie auf jede Spalte der Matrix M an.

Also zum Beispiel:

f = @(v) [0 1;1 0]*v + [0 0.1]';
apply_func_2_cols(f,[0 0 1 1;0 1 0 1])

 ans =

   0.00000   1.00000   0.00000   1.00000
   0.10000   0.10000   1.10000   1.10000
0
patapouf_ai