2016-09-27 5 views
4

Q1) Numpy関数はさまざまな形で引数を取ることができます。たとえば、np.sum(V)は以下の2つのうちのいずれかをとり、異なる形の出力を返します。さまざまな形の引数を取ることができる関数を作成する

x1= np.array([1,3]) #(1) 
x2= np.array([[[1,2],[3,4]], [[5,6],[7,8]]]) #(2) 

以下のように、長さ2の1Dベクトルに2つの値を加え、実数を返します。

def foo(V): 
    return V[0]+V[1]; 

ただし、このfoo関数は1つの1Dベクトルしか取ることができず、他の形をとることはできません。引数としてx1をとりますが、x2はとりません。上記の2つの変数(x1とx2)、または最後の次元で2の長さの配列を持つ他のシェイプのいずれかで関数を動作させたい場合は、foo関数をどのように修正する必要がありますか?


---------------------------アップデート--------------- ---------------

私の元の関数は、ハードコードされた負のガウス関数pdfでした。

def nGauss(X, mu, cov): 
    # multivariate negative gaussian.  
    # mu is a vector and cov is a covariance matrix. 

    k = X.shape[0]; 
    dev = X-mu 
    p1 = np.power(np.power(np.pi * 2, k) , -0.5); 
    p2 = np.power(np.linalg.det(cov) , -0.5) 
    p3 = np.exp(-0.5 * np.dot(np.dot(dev.transpose(), np.linalg.inv(cov)), dev)); 

    return -1.0 * p1 * p2 * p3; 

これで彼の関数は1つのpdf値しか返せません。例えば、np.array([1,2])のような引数を取ることはできますが、np.array([[[1,2]、[5,6]]、[[7,8 ]、[9,0]]])。ここで私の質問は、どのように私のガウス関数を任意の形状の引数を取ると nGauss(np.array([1,2]), mu, cov)返す[0.000023]を返すなど、同じ構造を維持する各点のPDF値を返すようでした nGauss(np.array([[[1,2], [5,6]], [[7,8],[9,0]]]), mu, cov)返す[[0.000023,0000014 ]、[0.000012,0.000042]]。

私はscipy関数 'multivariate_normal.pdf'がこれを行うことができることに気付きました。


Q2) 私はまた、NPの基本的な配列を理解するのに困難を抱えています。

t1=np.array([[1,2,3], [4,5,6]]) 
t2=np.array([1,2,3]) 
t3=np.array([[1,2,3], [4,5,6],5]) 

t1の形状は(2,3)であり、マトリックスパースペクティブの観点から正当であると思われます。 2行3列。しかし、t2の形状は(3)でなければならないと思います(3)。 "3"の後の空白の意味はなんですか?また、t3の形状は(3、)である。この場合、寸法が変化する空きスペースの意味ですか?

事前に、お手数をおかけします。

+0

'x1'の場合と' x2'の場合の、fooの出力の形状をどうしたいですか?私はスカラーを#(1)、(2、2)を#(2)と推測していますか?しかし、あなたはもう一番内側のディメンションを追加していますか?手作業で手動で計算して希望の出力をポストすることができれば役に立ちます。 – Praveen

+0

@Praveen元のガウス関数を更新しました。今では1つのベクトルを引数Xとして取ることができます。したがって、 'np.array([1,2])'をXとすると、その時点でpdfの値が得られます。私は今、ガウス関数を使って任意の形のデータを受け入れ、同じ構造のPDF値を最後の次元を除くXの引数に返すことができるのだろうかと思います。 –

答えて

1

、私は関係なく、配列が持っているどのように多くの次元の、あなたの配列の最も内側の寸法を追加したい推測しています。これを行う最も簡単な方法は、ellipsis indexingを使用することです。

>>> a = np.array([1, 2]) 
>>> a[..., 0] + a[..., 1] 
3 

だからとしてfoo定義します:これは、1次元配列のために同様に動作

>>> a = np.arange(24).reshape((3, 4, 2)) 
>>> a 
array([[[ 0, 1], 
     [ 2, 3], 
     [ 4, 5], 
     [ 6, 7]], 

     [[ 8, 9], 
     [10, 11], 
     [12, 13], 
     [14, 15]], 

     [[16, 17], 
     [18, 19], 
     [20, 21], 
     [22, 23]]]) 
>>> a[..., 0] 
array([[ 0, 2, 4, 6], 
     [ 8, 10, 12, 14], 
     [16, 18, 20, 22]]) 
>>> a[..., 1] 
array([[ 1, 3, 5, 7], 
     [ 9, 11, 13, 15], 
     [17, 19, 21, 23]]) 
>>> a[..., 0] + a[..., 1] 
array([[ 1, 5, 9, 13], 
     [17, 21, 25, 29], 
     [33, 37, 41, 45]]) 

:ここでは詳細な例だあなたnGauss機能について

def foo(V): 
    return V[..., 0] + V[..., 1] 

を、最も簡単な解決策はnp.apply_along_axisです。たとえば、あなたはこのようにそれを呼び出します。

>>> np.apply_along_axis(nGauss, -1, x1, mu, cov) 
+0

本当にありがとうございます! 「...」インデックス作成は私には新しいものなので、詳細な例を参考にして検討します。 Q2に関して、私は間違った方法でそれを考えていますか? –

+0

@AnnDescomp Q2の回答を少し追加しますが、一方、hpualjの回答も見てください。これはQ2について詳しく説明しており、素晴らしいリンクも提供しています。 – Praveen

+0

ありがとう、今私は彼のリンクを探しています。私はまた、最初の質問を私の元の機能で更新します。私の偽のfoo関数は、私の元のガウス関数に代わるものではないようです。どんな追加入力も高く評価されます! –

1

Q1のためにあなたがパックと引数を展開することができます

def foo(*args): 

    result = [] 
    for v in args: 
     result.append(v[0] + v[1]) 

    return result 

これは、各結果のリストを返し、それらを反復、あなたが望むようあなたができるだけ多くのベクトル引数を渡すことができます。 **でkwargsをパックして展開することもできます。詳細:Q1については

https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists

+0

オペレータは配列の数が少ないことを望んでいます。 numpy配列をアンパックすることはできません。一番外側の配列をリストに変換して関数に渡すと、ベクトル化された操作の点でnumpyの利点のほとんどが失われます。 – Praveen

+0

@ZzCalvinzZ入力いただきありがとうございます! –

2

あなたの関数は、両方の配列で動作します:

In [1]: def foo(V): 
    ...:  return V[0]+V[1] 
    ...: 
In [2]: foo(np.array([1,3])) 
Out[2]: 4 
In [3]: foo(np.array([[[1,2],[3,4]], [[5,6],[7,8]]])) 
Out[3]: 
array([[ 6, 8], 
     [10, 12]]) 

この答えは、これら2つの配列の単なる総和である:

In [4]: np.array([[[1,2],[3,4]], [[5,6],[7,8]]])[0] 
Out[4]: 
array([[1, 2], 
     [3, 4]]) 
In [5]: np.array([[[1,2],[3,4]], [[5,6],[7,8]]])[1] 
Out[5]: 
array([[5, 6], 
     [7, 8]]) 

の場合あなたは何か他のことを期待していました。あなたの2番目の質問については

In [6]: t1=np.array([[1,2,3], [4,5,6]]) 
    ...: t2=np.array([1,2,3]) 
    ...: t3=np.array([[1,2,3], [4,5,6],5]) 
    ...: 
In [7]: t1.shape 
Out[7]: (2, 3) 
In [8]: t2.shape 
Out[8]: (3,) 
In [9]: t3.shape 
Out[9]: (3,) 

(3,)は、1つの要素のタプルです。これらの表現を比較する。

In [11]: (3) 
Out[11]: 3 
In [12]: (3,) 
Out[12]: (3,) 

(3)V(3,1)形状アレイ、およびnp.array([[1,2,3]]) Vに関する最近のいくつかの質問がありました。np.array([1,2,3])

t3は、3つの要素を持つオブジェクトdtype配列です。 3つの入力は異なる長さなので、2次元配列を作成することはできません。今のところこのタイプの配列から離れてください。より単純な配列に焦点を合わせる。 nGauss

In [10]: t3 
Out[10]: array([[1, 2, 3], [4, 5, 6], 5], dtype=object) 
In [13]: t3[0] 
Out[13]: [1, 2, 3] 
In [14]: t3[2] 
Out[14]: 5 

Numpy: Why is difference of a (2,1) array and a vertical matrix slice not a (2,1) array

Difference between single and double bracket Numpy array?

=====================

In [53]: mu=np.array([0,0]) 
In [54]: cov=np.eye(2) 
In [55]: xx=np.array([[[1,2], [5,6]], [[7,8],[9,0]]]) 
In [56]: np.apply_along_axis(nGauss, -1, xx, mu, cov) 
Out[56]: 
array([[ -1.30642333e-02, -9.03313360e-15], 
     [ -4.61510838e-26, -4.10103631e-19]]) 

apply_along_axis最初の2つのぼかしで繰り返し、それぞれxx[i,j,:]nGauss。それは高速ではありませんが、比較的簡単に適用できます。

k = X.shape[0]; # I assume you want 
k = X.shape[[1] # the last dimension 
dev = X-mu  # works as long as mu has k terms 

これはスカラーです:

p1 = np.power(np.power(np.pi * 2, k) , -0.5); 

そうだから、ダウンこの式を一般に来る

p2 = np.power(np.linalg.det(cov) , -0.5) 

です、(シンプルで

p3 = np.exp(-0.5 * np.dot(np.dot(dev.transpose(), np.linalg.inv(cov)), dev)); 

2 )xケース、devは1d、dev.transpose()は何もしません。

einsumdotより一般化する方が簡単です。以前の値に一致する

def nGaussA(X, mu, cov): 
    # multivariate negative gaussian.  
    # mu is a vector and cov is a covariance matrix. 

    k = X.shape[-1]; 
    dev = X-mu 
    p1 = np.power(np.power(np.pi * 2, k) , -0.5); 
    p2 = np.power(np.linalg.det(cov) , -0.5) 
    p3 = np.einsum('...i,ij,...j', dev, np.linalg.inv(cov), dev) 
    p3 = np.exp(-0.5 * p3) 
    return -1.0 * p1 * p2 * p3; 

p3 = np.einsum('...i,ij,...j', dev, np.linalg.inv(cov), dev) 

そうで:高い薄暗いへ

p3 = np.einsum('i,ij,j', dev, np.linalg.inv(cov), dev) 

一般化に簡素化

p3 = np.einsum('j,j', np.einsum('i,ij', dev, np.linalg.inv(cov)), dev) 
p3 = np.exp(-0.5 * p3) 

:私は同じだと思います

In [85]: nGaussA(x,mu,cov) 
Out[85]: -0.013064233284684921 
In [86]: nGaussA(xx,mu,cov) 
Out[86]: 
array([[ -1.30642333e-02, -9.03313360e-15], 
     [ -4.61510838e-26, -4.10103631e-19]]) 

したがって、関数を一般化する方法は、各ステップを確認することです。スカラを生成する場合は、そのまま使用してください。 xで動作している場合はそのまま使用してください。しかし、他の配列と次元を調整する必要がある場合は、それを行うnumpy操作を使用します。しばしば放送を伴う。場合によっては、他の数値関数を調べて一般化の仕方を調べることもできます(たとえば、apply_along_axisapply_over_axescrossなど)。

インタラクティブなnumpyセッションは必須です。私は小さなサンプル配列でアイデアを試すことができます。

+0

答えをありがとう。それは本当に私が神秘的な配列を理解するのに役立ちます。一方で、私は今更新した私の元の機能を掲示すべきであることを認識しました。私は、(n、)形のnp.arrayを1つ取る負のガウス関数pdfを書いた。したがって、np.array([1,2])のような引数を取ることはできますが、np.array([[[1,2]、[5,6]]、[7,8]、[ 9,0]]])。ここで私の質問は、私のガウス関数を任意の形の引数を取って、同じ構造を維持する各点のpdf値を返すようにする方法でした。 –

+0

私はあなたの2つのドットプロダクトを一般化するために 'einsum'を使って' nGauss'の一般化を試みました。 – hpaulj

関連する問題