2016-04-02 9 views
4

2つのnumpy ndarrayを結合して、最適化されたnumpyを使用してループを起こさずに、以下を高速に達成するにはどうすればよいですか?numpy配列の結合または結合

>>> a = np.random.rand(2,2) 
>>> a 
array([[ 0.09028802, 0.2274419 ], 
     [ 0.35402772, 0.87834376]]) 

>>> b = np.random.rand(2,2) 
>>> b 
array([[ 0.4776325 , 0.73690098], 
     [ 0.69181444, 0.672248 ]]) 

>>> c = ??? 
>>> c 
array([[ 0.09028802, 0.2274419, 0.4776325 , 0.73690098], 
     [ 0.09028802, 0.2274419, 0.69181444, 0.672248 ], 
     [ 0.35402772, 0.87834376, 0.4776325 , 0.73690098], 
     [ 0.35402772, 0.87834376, 0.69181444, 0.672248 ]]) 
+1

'np.hstack(([[0、0、1、1]]、[[0 Bを、0,1]]) 'これは、おそらく誰かがより一般的な方法でそれをやることができるでしょう。 – Paul

答えて

2

関連する方法を説明するために、いくつかのインラインコメントを使って、異なる形状の配列を含む一般的なケースを扱うために、将来のソリューションを見ていきます。

(1)まず、入力配列の形状を保存します。

ma,na = a.shape 
mb,nb = b.shape 

(2)次は、入力配列ab内の列の数の和である列の数で3Dアレイを初期化します。このタスクにはnp.emptyを使用してください。

out = np.empty((ma,mb,na+nb),dtype=a.dtype) 

(3)次に、a[:,None,:]aから行と列「NA」最初のための3次元アレイの第一の軸を設定します。したがって、out[:,:,:na]に割り当てると、その2番目のコロンはNumPy配列にシングルトンディムが常に存在するため、できるだけブロードキャストされた設定が必要であることをNumPyに示します。実際には、これはタイリング/リピートと同じですが、おそらく効率的な方法です。

out[:,:,:na] = a[:,None,:] 

(4)bから出力配列に設定を繰り返します。今回は、outの最初の軸に沿ってout[:,:,na:]で放送し、その最初のコロンはその放送を手助けしました。

out[:,:,na:] = b 

(5)最後のステップは、出力を2次元形状に再形成することです。これは、必要な2D形状タプルで形状を単純に変更することで行うことができます。再構築するだけでビューが変更され、効果的にゼロコストになります。すべてを凝縮

out.shape = (ma*mb,na+nb) 

、完全な実装は次のようになります -

ma,na = a.shape 
mb,nb = b.shape 
out = np.empty((ma,mb,na+nb),dtype=a.dtype) 
out[:,:,:na] = a[:,None,:] 
out[:,:,na:] = b 
out.shape = (ma*mb,na+nb) 
+1

ライナーではありませんが、速いです。 – hpaulj

+0

@hpaulj時には醜いものが高速なものです:) – Divakar

+0

@Divakar私はちょっと驚いています。私はあなたがちょうど 'シェイプ'タプルを割り当てることができたことを理解していませんでした。何が起きているのか正確に説明できますか? – Paul

-1

すべての配列は、あなただけ呼び出すことでマージすることができますので、刃先交換式です:

c = np.vstack(a,b) 
+0

最初のことはちょうど2つのプレを作成します。もしOPが2つの配列のデカルト積であるnumpyの配列を必要とするならば、 – Paul

3

a[:2],b[:2] 

か、コアnumpyのスタッキング機能を使用することができ、このようになるはずですあなたが望むのは、明らかに、水平に積み重なったabのデカルト積です。あなたはそれらをスタックするnumpy.hstack、その後、numpyの配列のインデックスを生成するitertoolsモジュールを使用することができます。

import numpy as np 
from itertools import product 

a = np.array([[ 0.09028802, 0.2274419 ], 
       [ 0.35402772, 0.87834376]]) 

b = np.array([[ 0.4776325 , 0.73690098], 
       [ 0.69181444, 0.672248 ], 
       [ 0.79941110, 0.52273 ]]) 

a_inds, b_inds = map(list, zip(*product(range(len(a)), range(len(b))))) 

c = np.hstack((a[a_inds], b[b_inds])) 

これはのcその結果:インデックスの事を破壊

array([[ 0.09028802, 0.2274419 , 0.4776325 , 0.73690098], 
     [ 0.09028802, 0.2274419 , 0.69181444, 0.672248 ], 
     [ 0.09028802, 0.2274419 , 0.7994111 , 0.52273 ], 
     [ 0.35402772, 0.87834376, 0.4776325 , 0.73690098], 
     [ 0.35402772, 0.87834376, 0.69181444, 0.672248 ], 
     [ 0.35402772, 0.87834376, 0.7994111 , 0.52273 ]]) 

product(range(len(a)), range(len(b))は、リストに変換すると次のようなものが生成されます。

[(0, 0), (0, 1), (1, 0), (1, 1)] 

[0, 0, 1, 1][0, 1, 0, 1]のようなものが必要なので、ジェネレータをトランスポーズする必要があります。これを行うための慣用的な方法はzip(*zipped_thing)です。あなただけの直接これらを割り当てる場合は、あなたはこのように、tuplesを得るでしょう:私はマッピングされた理由である、

[(0, 0, 1, 1), (0, 1, 0, 1)] 

しかし、numpyの配列は多次元インデックスとしてタプルを解釈するので、あなたがリストにそれらを有効にしたいです関数の結果にlistコンストラクタを追加します。

3

ないきれいな、しかし、あなたはhstack組み合わせることができ、repeat、そしてtile

>>> a = np.arange(4).reshape(2,2) 
>>> b = a+10 
>>> a 
array([[0, 1], 
     [2, 3]]) 
>>> b 
array([[10, 11], 
     [12, 13]]) 
>>> np.hstack([np.repeat(a,len(a),0),np.tile(b,(len(b),1))]) 
array([[ 0, 1, 10, 11], 
     [ 0, 1, 12, 13], 
     [ 2, 3, 10, 11], 
     [ 2, 3, 12, 13]]) 

または3x3のケースについて

>>> a = np.arange(9).reshape(3,3) 
>>> b = a+10 
>>> np.hstack([np.repeat(a,len(a),0),np.tile(b,(len(b),1))]) 
array([[ 0, 1, 2, 10, 11, 12], 
     [ 0, 1, 2, 13, 14, 15], 
     [ 0, 1, 2, 16, 17, 18], 
     [ 3, 4, 5, 10, 11, 12], 
     [ 3, 4, 5, 13, 14, 15], 
     [ 3, 4, 5, 16, 17, 18], 
     [ 6, 7, 8, 10, 11, 12], 
     [ 6, 7, 8, 13, 14, 15], 
     [ 6, 7, 8, 16, 17, 18]]) 
+0

これは素晴らしいことです。私の質問では指定されていませんが、aとbが異なる次元である場合、ソリューションでエラーが発生します。 'np.hstack([np.repeat(a、len(b)、0)、np.tile(b、(len(a)、1))])' –

+0

実際には、上記の私の上記の編集は、提案は機能しません。しかし、 'b = np.random.rand(3,2)'を試してみてください。 'ValueError:連結軸を除くすべての入力配列の次元が正確に一致しなければならない ' –

+0

@HelloWorld:上記は' a 'と' b'はあなたの例のように正方形で同じ形をしていました。あなたは一般的なケースを扱う必要がありますか? – DSM

0

を使用できdstack()broadcast_arrays()

import numpy as np 

a = np.random.randint(0, 10, (3, 2)) 
b = np.random.randint(10, 20, (4, 2)) 

np.dstack(np.broadcast_arrays(a[:, None], b)).reshape(-1, a.shape[-1] + b.shape[-1]) 
+0

この 'broadcast_arrays'の使用は賢明ですが、' repeat'と 'tile'を持つものよりも遅いです。 – hpaulj