25

numpy のitertools.combinationsを実装したいと思います。この議論に基づいて、1D入力で機能する関数があります:

def combs(a, r):
    """
    Return successive r-length combinations of elements in the array a.
    Should produce the same output as array(list(combinations(a, r))), but 
    faster.
    """
    a = asarray(a)
    dt = dtype([('', a.dtype)]*r)
    b = fromiter(combinations(a, r), dt)
    return b.view(a.dtype).reshape(-1, r)

出力は理にかなっています:

In [1]: list(combinations([1,2,3], 2))
Out[1]: [(1, 2), (1, 3), (2, 3)]

In [2]: array(list(combinations([1,2,3], 2)))
Out[2]: 
array([[1, 2],
       [1, 3],
       [2, 3]])

In [3]: combs([1,2,3], 2)
Out[3]: 
array([[1, 2],
       [1, 3],
       [2, 3]])

ただし、次元を追加することで、一度に複数の呼び出しをすばやく実行できるようにする ND 入力に拡張できれば最高です。したがって、概念的には、ifcombs([1, 2, 3], 2)プロデュース[1, 2], [1, 3], [2, 3]および combs([4, 5, 6], 2)プロデュース は[4, 5], [4, 6], [5, 6]、「and」が平行な行または列 (意味のある方) を表す場所combs((1,2,3) and (4,5,6), 2)を生成する必要があります。[1, 2], [1, 3], [2, 3] and [4, 5], [4, 6], [5, 6](および追加の次元についても同様)

わからない:

  1. 他の関数が機能する方法と一貫性のある論理的な方法でディメンションを機能させる方法 (いくつかの numpy 関数がaxis=パラメーターを持ち、軸 0 のデフォルトを持っている方法など)。他の軸は並列計算を表すだけですか?)
  2. 上記のコードを ND で動作させる方法 (現在はValueError: setting an array element with a sequence.)
  3. もっと良い方法はありますdt = dtype([('', a.dtype)]*r)か?
4

4 に答える 4

23

を使用itertools.combinations()してインデックス配列を作成し、NumPy のファンシー インデックスを使用できます。

import numpy as np
from itertools import combinations, chain
from scipy.special import comb

def comb_index(n, k):
    count = comb(n, k, exact=True)
    index = np.fromiter(chain.from_iterable(combinations(range(n), k)), 
                        int, count=count*k)
    return index.reshape(-1, k)

data = np.array([[1,2,3,4,5],[10,11,12,13,14]])

idx = comb_index(5, 3)
print(data[:, idx])

出力:

[[[ 1  2  3]
  [ 1  2  4]
  [ 1  2  5]
  [ 1  3  4]
  [ 1  3  5]
  [ 1  4  5]
  [ 2  3  4]
  [ 2  3  5]
  [ 2  4  5]
  [ 3  4  5]]

 [[10 11 12]
  [10 11 13]
  [10 11 14]
  [10 12 13]
  [10 12 14]
  [10 13 14]
  [11 12 13]
  [11 12 14]
  [11 13 14]
  [12 13 14]]]
于 2013-04-15T06:03:56.273 に答える
4

パフォーマンス面でどのように機能するかはわかりませんが、インデックス配列で組み合わせを実行してから、実際の配列スライスをnp.take次のように抽出できます。

def combs_nd(a, r, axis=0):
    a = np.asarray(a)
    if axis < 0:
        axis += a.ndim
    indices = np.arange(a.shape[axis])
    dt = np.dtype([('', np.intp)]*r)
    indices = np.fromiter(combinations(indices, r), dt)
    indices = indices.view(np.intp).reshape(-1, r)
    return np.take(a, indices, axis=axis)

>>> combs_nd([1,2,3], 2)
array([[1, 2],
       [1, 3],
       [2, 3]])
>>> combs_nd([[1,2,3],[4,5,6]], 2, axis=1)
array([[[1, 2],
        [1, 3],
        [2, 3]],

       [[4, 5],
        [4, 6],
        [5, 6]]])
于 2013-04-15T05:52:26.757 に答える