4

は、出力がn次元 ( m 1  ×  m 2 … ×  m n ) 配列でfある 1 つのパラメーターの関数であり、要素がすべて の有効な引数である長さkのベクトルであるとします。Bf

によって得られる ( n +1) 次元 ( m 1  ×  m 2  ×…×  m n  ×  k ) 配列を生成するための、便利で、さらに重要なことに、「形状にとらわれない」MATLAB 式 (またはレシピ) を探しています。 k n次元配列を「積み重ねる」 。f(b)パラメータのb範囲はB.

でこれを行うにはnumpy、次のような式を使用します。

C = concatenate([f(b)[..., None] for b in B], -1)

なんらかの用途がある場合に備えて、この numpy 式を以下に展開します ( APPENDIXを参照)。ただし、ここで強調したい特徴は、およびの形状/サイズに完全に依存しないことです 。私が考えている種類のアプリケーションでは、このような「形状にとらわれない」コードを記述できることが最も重要です。(この種の操作を行うために遭遇する多くの MATLAB コードは明らかに「形状にとらわれない」ものではなく、そのようにする方法がわからないため、この点を強調します。)f(b) B


付録

一般に、Aが numpy 配列である場合、式A[..., None]は "再形成" と見なすことができるAため、1 つの追加の些細な次元が取得されます。したがって、f(b)n次元 ( m 1  ×  m 2 … ×  m n ) 配列の場合、f(b)[..., None]は対応する ( n +1) 次元 ( m 1  ×  m 2  ×…×  m n  × 1) 配列です。(この些細な次元を追加する理由は、以下で明らかになります。)

この説明はさておき、 の最初の引数の意味は次のconcatenateとおりです。

[f(b)[..., None] for b in B]

解読するのはそれほど難しくありません。これは標準的な Python の "リスト内包表記" であり、パラメーターが vector の範囲にあるため、 k ( n +1) 次元 ( m 1  ×  m 2  ×…×  m n  × 1) 配列のシーケンスに評価されます。f(b)[..., None]bB

の 2 番目の引数concatenateは、連結が実行される "軸" であり、連結される配列の対応する次元のインデックスとして表されます。endこのコンテキストでは、インデックス -1は、MATLAB でのキーワードと同じ役割を果たします。したがって、式

concatenate([f(b)[..., None] for b in B], -1)

f(b)[..., None]「最後の次元に沿って配列を連結する」と言います。この「最後の次元」を連結するためには、配列を再形成する必要がありf(b)ます (たとえば、f(b)[..., None])。

4

2 に答える 2

6

それを行う1つの方法は次のとおりです。

 % input:
 f=@(x) x*ones(2,2)
 b=1:3;
 %%%%
 X=arrayfun(f,b,'UniformOutput',0);
 X=cat(ndims(X{1})+1,X{:});

多分もっとエレガントな解決策がありますか?

于 2012-09-19T02:07:57.737 に答える
1

形状にとらわれないことは、NumPy と Matlab の根底にある哲学の間の重要な違いです。NumPy よりも Matlab で達成する方がはるかに困難です。また、私の見解では、形状にとらわれないことも悪いことです。行列の形状には数学的な意味があります。一部の関数またはクラスが入力の形状を完全に無視したり、数学表記に従わない方法でそれらを変更したりする場合、その関数は言語の機能と意図の一部を破壊します。

プログラマーの言葉で言えば、形状関連のバグを防ぐために設計された、実際に役立つ機能です。確かに、それはしばしば「プログラム上の不都合」ですが、それは言語を調整する理由にはなりません。それは本当にすべての考え方です。

そうは言っても、あなたの問題に対するエレガントな解決策がMatlabに存在するとは思えません:)後処理を行う必要がないように、すべての要件を関数に詰め込むことをお勧めします:

f = @(x) bsxfun(@times, permute(x(:), [2:numel(x) 1]), ones(2,2, numel(x)) )

動作せず、以外のことを行うため、明らかにこれは正しくありませ。しかし、このワンライナーの醜さがすでに示唆しているように、専用の関数の方が良い考えかもしれません。Oli によって提案されたものは、独自の関数でロックする限り、かなりまともです。f(1)f(1:2)f(1:4)

function y = f(b)

    g = @(x)x*ones(2,2); %# or whatever else you want

    y = arrayfun(g,b, 'uni',false);
    y = cat(ndims(y{1})+1,y{:});
end

f(b)for anybが正しい出力を生成するようにします。

于 2012-09-19T05:10:41.870 に答える