MATLABで行列のすべての行/列に関数を適用するにはどうすればよいですか?


106

たとえば、と発声することで、ベクター内のすべてのアイテムに関数を適用できます。また、関数をv + 1使用することもできますarrayfun。forループを使用せずに、行列のすべての行/列に対してどのように実行できますか?

回答:


73

多くのような操作を内蔵sumし、prodすでにあなたがこれを利用するために適用されている機能をリファクタリングすることができるかもしれので、行または列にわたって動作することができます。

それは実行可能な選択肢ではないなら、それを行うための一つの方法は、使用して細胞内に行または列を収集することであるmat2cellnum2cell、そして使用しcellfunた電池アレイ上で動作します。

例として、行列の列を合計するとしますM。あなたは単にこれを使用してこれを行うことができますsum

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

そして、より複雑なnum2cell/ cellfunオプションを使用してこれを行う方法を次に示します。

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

17
単純なforループに対して特定のケースについてこのアプローチのパフォーマンスをテストします。これは、行列をセル配列に変換するよりも高速な場合があります。tic / tac wrapを使用してテストします。
2010

5
@yuk:「tic / toc」の意味だと思います。;)
gnovice、2010

4
@gnovice、おそらくyukは魔法をかけ、tak = tocを割り当てました。true = falseが有効なステートメントである言語では、あなたがそれを行うことができる方法があると私は確信しています(:
chessofnerd

1
@Argyll:どのアプローチがより効率的かは、適用したい関数の種類、行列のサイズなどによって決まります。要するに、問題に依存している可能性があります。実際、古き良きforループが最速の選択になる場合があります。
ノヴィツェ2014

2
@gnovice、への編集をお勧めしますsum(M, 1)。初心者は、sumこの方法を任意のサイズのマトリックスに使用できると考えて、マトリックスの1日がになると困惑するかもしれません1-by-n
Stewie Griffin 2016

24

より不明瞭なMatlab関数bsxfunが必要な場合があります。Matlabドキュメンテーションから、bsxfunは、「関数ハンドルfunで指定された要素ごとのバイナリ演算を、シングルトン展開が有効になっている配列AおよびBに適用します。」

上記の@gnoviceは、合計およびその他の基本的な関数が最初の1でない次元(つまり、複数の行がある場合は行、1行しかない場合は列、または低い次元がすべてsize == 1の場合は高い次元)で動作することを述べました。 )。ただし、bsxfunは(特に)ユーザー定義関数を含むすべての関数で機能します。

たとえば、行列Aと行ベクトルBEgがあるとしましょう。

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

Aのすべての要素をBの対応する列の累乗でベクトルCに返す関数power_by_colが必要です。

上記の例から、Cは3x3行列です。

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

つまり、

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

repmatを使用してこれを力ずくで行うことができます。

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

または、内部でrepmatステップを処理するbsxfunを使用して上品な方法でこれを行うことができます。

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

そのため、bsxfunはいくつかの手順を節約します(Aの次元を明示的に計算する必要はありません)。ただし、私の非公式のテストでは、適用する関数(上記の私のべき関数のように)が単純な場合、repmatはおよそ2倍高速であることが判明しています。したがって、シンプルにするかスピードにするかを選択する必要があります。


21

これがいかに効率的であるかについてコメントすることはできませんが、これが解決策です:

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)

より一般的な答えをここに示します
ウォック

11

アレックスの答えに基づいて、これはより一般的な関数です:

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

2つの関数の比較を次に示します。

>> % 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))'


4

この質問への答えの進化する性質に加えて、r2016b以降、MATLABは暗黙的にシングルトンの次元を拡張しbsxfun、多くの場合で必要性を排除します。

r2016bリリースノート

暗黙的な拡張:長さ1の次元の自動拡張を使用して、要素ごとの演算と関数を配列に適用します。

暗黙的な拡張は、スカラー拡張の一般化です。スカラー拡張を使用すると、スカラーは別の配列と同じサイズに拡張され、要素ごとの操作が容易になります。暗黙的な展開では、配列に互換性のあるサイズがある限り、ここにリストされている要素ごとの演算子と関数は、入力を暗黙的に同じサイズに展開できます。すべての次元について、入力の次元サイズが同じか、1つが1の場合、2つの配列は互換性のあるサイズを持ちます。

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

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

Logical operators&, |, xor

Bit-wise functionsbitand, bitor, bitxor

Elementary math functionsmax, min, mod, rem, hypot, atan2, atan2d

たとえば、行列Aの各列の平均を計算し、A-mean(A)を使用して各列から平均値のベクトルを減算できます。

以前は、この機能はbsxfun関数を介して利用できました。現在、bsxfunのほとんどの使用を、暗黙の拡張をサポートする関数および演算子の直接呼び出しに置き換えることをお勧めします。bsxfunを使用する場合と比較して、暗黙的な拡張により、速度が速くなり、メモリ使用量が増え、コードの可読性が向上します。


2

上記の回答はどれも「そのまま」機能しませんでしたが、他の回答のアイデアをコピーして得られた次の機能は機能します。

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

関数fを受け取り、それを行列のすべての列に適用しますM

だから例えば:

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

1

Matlabの最近のバージョンでは、テーブルのデータ構造を活用できます。「rowfun」操作さえありますが、これを行うだけの方が簡単であることがわかりました。

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

または、古いMatlabバージョンで、テーブルを必要としない古いバージョンをここに示します。

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

1

受け入れられた答えは、最初にセルに変換してからcellfun、すべてのセルを操作するために使用することです。特定のアプリケーションはわかりませんが、一般的にはbsxfun、マトリックスを操作するために使用する方が効率的だと思います。基本的bsxfunに、2つの配列にわたって要素ごとに操作を適用します。したがって、配列を取得するn x 1ためにm x 1ベクターの各アイテムをベクターの各アイテムで乗算するn x m場合は、次のように使用できます。

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

これによりresult、(i、j)エントリがのj番目の要素でvec1乗算されたi番目の要素となると呼ばれる行列が得られますvec2

bsxfunあらゆる種類の組み込み関数に使用でき、独自の関数を宣言できます。ドキュメントには多くの組み込み関数のリストがありますが、基本的には2つの配列(ベクトルまたは行列)を引数として受け入れる任意の関数に名前を付けて機能させることができます。


-1

行列の行の合計を計算する方法を模索しているときに、この質問/回答に遭遇しました。

MatlabのSUM関数が、特定の次元、つまり2次元の標準行列の合計を実際にサポートしていることを付け加えておきます。

したがって、列の合計を計算するには、次のようにします。

colsum = sum(M) % or sum(M, 1)

行の合計については、単に

rowsum = sum(M, 2)

私の賭けは、これがforループのプログラミングとセルへの変換の両方よりも速いということです:)

これはすべて、SUMのMATLABヘルプで確認できます。


7
特定の次元に沿ってSUMを適用する機能については、この質問に対する元の回答の最初の文で説明しました。答えは、ディメンションを選択する機能がまだ関数に組み込まれていない場合に対処するために続いた。ただし、組み込みのディメンション選択オプションを使用すると(可能な場合)、forループやセルへの変換よりもほとんどの場合高速です。
cjh 2012

確かに、上記の答えは私がmatlabのドキュメントに戻ってきたという事実です。私はそれほど空想を必要としなかったので、単純な解決策を必要とする他の人たちを検索して共有して保存したかっただけです。
12

-2

行の長さがわかっている場合は、次のようにすることができます。

a=rand(9,3);
b=rand(9,3); 
arrayfun(@(x1,x2,y1,y2,z1,z2) line([x1,x2],[y1,y2],[z1,z2]) , a(:,1),b(:,1),a(:,2),b(:,2),a(:,3),b(:,3) )

2
この答えを見た人へ:これはそれを行う方法ではありません!これは、MATLABで何かを行う方法ではありません!
Stewie Griffin 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.