2017-09-21 17 views
1

値のペアからなるnumpy配列があるとします。私はそれらを裂くことなく、ペアのすべての組み合わせを見つけたいと思います。特に、私はこのためのnumpy.meshgrid解決策を望んでいました。meshgridを介してペアのnumpy配列のすべての組み合わせを見つける

ように構成され配列想像

ab = np.array([[1,10], [2,20], [3,30], [4,40]]) 

は、その後、私の所望の出力が

>>> out: ([1,10], [2,20]) 
     ([1,10], [3,30]) 
     ([1,10], [4,40]) 
     ([2,20], [3,30]) 
     ([2,20], [4,40]) 
     ([3,30], [4,40]) 

ある出力が(私はそれに応じて後で変換することができる)np.array、又はtupleのいずれかであり得ます。私の結婚式の順序を無視して、私の結果に重複がどのように省かれているか注意してください([[1,10], [2,20]]が既にある場合、私は[[2,20], [1,10]]を私の出力に入れたくありません)。実際のケースでは、abのサイズは30,000ですから、速度も別の問題です。

私はまずmeshgridを試しました。単一の値の簡単なケースでは が、これは簡単に(重複してまだ、まだ)行われます

a = np.array([1,2,3,4]) 
mesh = np.array(np.meshgrid(a,a)).T.reshape(-1,2) 
>>> out: [[1 1] 
      [1 2] 
      [1 3] 
      [1 4] 
      [2 1] 
      [...] 
      [4 4]] 

しかし、私のペアのために、

mesh = np.array(np.meshgrid(ab,ab)).T 

の私の試みは私に

[[[ 1 1] 
    [ 1 10] 
    [ 1 2] 
    [ 1 20] 
    [ 1 3] 
    [ 1 30] 
    [ 1 4] 
    [ 1 40]] 

[[10 1] 
    [10 10] 
    [10 2] 
    [10 20] 
...  
    [40 3] 
    [40 30] 
    [40 4] 
    [40 40]]] 
を与える

つまり、meshgridは私のペアを分割します。私は解決策が近いと思うが、自分でそれを思いつくことはできなかった。どんな助けでも感謝しています!

+0

あなたが望んでいた述べました'meshgrid'ソリューションですが、' itertools'はあまり冗長でなく、速い代替手段であると考えてください。 [permutations(ab)](https://docs.python.org/2/library/itertools)を呼びたいと思うでしょう。html)を使用して希望の出力を得る。 – charlesreid1

+1

@ charlesreid1私は希望の結果を得るためには 'コンビネーション 'になると信じています。しかし実際には、itertoolsジェネレータをnumpy配列に変換するのが非常に遅いため、以下の解決法(itertoolsを使用しない方が速い)(特に大きな入力の場合)は高速です。 –

+0

最初に 'itertools'を避けました。なぜなら、速度に関しては' meshgrid'の方が性能が優れているとよく読んでいるからです。より頻繁に計算されなければならないタスクの場合、私は確かに両方を試し、より速いものを見つけるでしょう。しかし、これは1回限りの仕事なので、私はDivakarの解決策に行くことに決めました。しかし、あなたもありがとう! – offeltoffel

答えて

3

meshgridは、すべての可能な組み合わせを作成するため、後で除外するのではなく機能するとは思わないでしょうか。それを解決するために、2つのアプローチを提案することができる。取得する

In [99]: r,c = np.triu_indices(len(ab),1) 

In [100]: np.hstack((ab[r], ab[c])) 
Out[100]: 
array([[ 1, 10, 2, 20], 
     [ 1, 10, 3, 30], 
     [ 1, 10, 4, 40], 
     [ 2, 20, 3, 30], 
     [ 2, 20, 4, 40], 
     [ 3, 30, 4, 40]]) 

- 私たちはそうのような所望の出力を得るために行に行重複せず、それらのペアワイズ組み合わせのインデックスと、単にインデックスを取得することができる

アプローチ#1

In [115]: np.stack((ab[r], ab[c]), axis=1) 
Out[115]: 
array([[[ 1, 10], 
     [ 2, 20]], 

     [[ 1, 10], 
     [ 3, 30]], 

     [[ 1, 10], 
     [ 4, 40]], 

     [[ 2, 20], 
     [ 3, 30]], 

     [[ 2, 20], 
     [ 4, 40]], 

     [[ 3, 30], 
     [ 4, 40]]]) 

として機能するように、出力を3Dとして出力します。

def pairwise_combs1(ab): 
    r,c = np.triu_indices(len(ab),1) 
    return np.stack((ab[r], ab[c]), axis=1) 

アプローチ#2メモリ効率、ひいてはパフォーマンスをターゲットslicingarray-initializationのもう一つ -

def pairwise_combs2(ab): 
    n = len(ab) 
    N = n*(n-1)//2 
    out = np.empty((N,2,2),dtype=ab.dtype) 
    idx = np.concatenate(([0], np.arange(n-1,0,-1).cumsum())) 
    start, stop = idx[:-1], idx[1:] 
    for j,i in enumerate(range(n-1)): 
     out[start[j]:stop[j],0] = ab[j] 
     out[start[j]:stop[j],1] = ab[j+1:] 
    return out 

ランタイムテスト

In [166]: ab = np.random.randint(0,9,(1000,2)) 

In [167]: %timeit pairwise_combs1(ab) 
10 loops, best of 3: 20 ms per loop 

In [168]: %timeit pairwise_combs2(ab) 
100 loops, best of 3: 6.25 ms per loop 

In [169]: np.allclose(pairwise_combs1(ab), pairwise_combs2(ab)) 
Out[169]: True 
+1

これはすごくうっすらです。ただ拡張する。その結果が格納される必要がなく*後で反復される場合は、 'itertools.combinations(ab、2)'が最速の解決策になります。しかし、 'itertools'オブジェクトを' numpy ndarray'に変換することは、保存する必要がある場合には高速ではありません。 –

+0

'np.triu_indices'は素晴らしいことです。もう一度私はnumpyが異なる問題に提供する解決策の量について驚いています。残念ながら、私は 'MemoryError'を取得しています。 30,000組のすべての組み合わせは、900,000,000組を意味する。私はスライスで作業しなければならないかもしれません。 – offeltoffel

関連する問題