ベクトル内のすべてのアイテムに関数を適用するには、たとえば 、v + 1または関数 を使用できますarrayfun。forループを使用せずに、行列のすべての行/列に対してそれを行うにはどうすればよいですか?
12 に答える
sumやのような多くの組み込み操作prodは、すでに行または列全体で操作できるため、これを利用するために適用する関数をリファクタリングできる場合があります。
mat2cellそれが実行可能なオプションでない場合、それを行う 1 つの方法は、またはを使用して行または列をセルに収集しnum2cell、 を使用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
これがどれほど効率的かについてはコメントできませんが、解決策は次のとおりです。
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)
Alex's answerに基づいて、より一般的な関数を次に示します。
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))'
完全性/興味のために、matlabには、要素ごとではなく行ごとにデータを操作できる機能があることを追加したいと思います。これはrowfun( http://www.mathworks.se/help/matlab/ref/rowfun.html ) と呼ばれますが、唯一の「問題」は、テーブルで動作することです( http://www.mathworks.se/help/ matlab/ref/table.html ) ではなく、マトリックス。
この質問に対する答えの進化する性質に加えて、r2016b 以降、MATLAB は暗黙的にシングルトン次元を拡張しbsxfun、多くの場合の必要性を取り除きます。
暗黙的な拡張: 長さ 1 の次元の自動拡張を使用して、要素単位の操作と関数を配列に適用します。
暗黙的な拡張は、スカラー拡張の一般化です。スカラー拡張を使用すると、スカラーは別の配列と同じサイズに拡張され、要素単位の操作が容易になります。暗黙的な拡張を使用すると、ここにリストされている要素単位の演算子と関数は、配列のサイズに互換性がある限り、入力を同じサイズに暗黙的に拡張できます。すべての次元について、入力の次元サイズが同じであるか、いずれかが 1 である場合、2 つの配列は互換性のあるサイズを持ちます。詳細については、基本演算で互換性のある配列サイズおよび配列対行列演算を参照してください。
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たとえば、行列 A の各列の平均を計算し、A - mean(A) を使用して各列から平均値のベクトルを減算できます。
以前は、この機能は bsxfun 関数を介して利用できました。bsxfun のほとんどの使用を、暗黙的な展開をサポートする関数と演算子への直接呼び出しに置き換えることをお勧めします。bsxfun を使用する場合と比較して、暗黙的な展開では速度が向上し、メモリ使用量が向上し、コードの可読性が向上します。
上記の回答はどれも「すぐに」機能しませんでしたが、他の回答のアイデアをコピーすることで得られた次の機能が機能します。
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
受け入れられている答えは、最初にセルに変換してから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) エントリが の i 番目の要素にvec1の j 番目の要素を掛けたものと呼ばれる行列が得られますvec2。
あらゆる種類の組み込み関数に使用bsxfunでき、独自の関数を宣言できます。ドキュメントには多くの組み込み関数のリストがありますが、基本的には、引数として 2 つの配列 (ベクトルまたは行列) を受け入れる任意の関数に名前を付けて、それを機能させることができます。
行列の行の合計を計算する方法を探しているときに、この質問/回答に出くわしました。
Matlab の SUM 関数は、特定の次元、つまり 2 次元の標準行列の合計を実際にサポートしていることを付け加えたいと思います。
したがって、列の合計を計算するには、次のようにします。
colsum = sum(M) % or sum(M, 1)
行の合計については、次のようにします。
rowsum = sum(M, 2)
私の賭けは、これはforループのプログラミングとセルへの変換の両方よりも速いということです:)
これらはすべて、SUM の matlab ヘルプに記載されています。
行の長さがわかっている場合は、次のようなものを作成できます。
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) )