182

複雑なことをする前に、6パラメーター関数のパラメーター空間を調べて数値の振る舞いを調べようとしているので、これを行うための効率的な方法を探しています。

私の関数は、6次元のnumpy配列で指定されたfloat値を入力として受け取ります。私が最初にやろうとしたのはこれでした:

最初に、2つの配列を受け取り、2つの配列からの値のすべての組み合わせで配列を生成する関数を作成しました。

from numpy import *
def comb(a,b):
    c = []
    for i in a:
        for j in b:
            c.append(r_[i,j])
    return c

次に、reduce()同じ配列のm個のコピーにそれを適用していました。

def combs(a,m):
    return reduce(comb,[a]*m)

最後に、次のように関数を評価します。

values = combs(np.arange(0,1,0.1),6)
for val in values:
    print F(val)

これは機能しますが、すぎます。パラメータのスペースが大きいことは知っていますが、これはそれほど遅くないはずです。この例では106 (100万)ポイントしかサンプリングしておらず、配列を作成するだけで15秒以上かかりましたvalues

numpyでこれを行うより効率的な方法を知っていますか?

必要に応じて、関数Fが引数を取る方法を変更できます。

4

10 に答える 10

176

の新しいバージョンnumpy(>1.8.x)numpy.meshgrid()では、はるかに高速な実装が提供されます。

@pvのソリューション

In [113]:

%timeit cartesian(([1, 2, 3], [4, 5], [6, 7]))
10000 loops, best of 3: 135 µs per loop
In [114]:

cartesian(([1, 2, 3], [4, 5], [6, 7]))

Out[114]:
array([[1, 4, 6],
       [1, 4, 7],
       [1, 5, 6],
       [1, 5, 7],
       [2, 4, 6],
       [2, 4, 7],
       [2, 5, 6],
       [2, 5, 7],
       [3, 4, 6],
       [3, 4, 7],
       [3, 5, 6],
       [3, 5, 7]])

numpy.meshgrid()以前は 2D のみでしたが、現在は ND が可能です。この場合、3D:

In [115]:

%timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)
10000 loops, best of 3: 74.1 µs per loop
In [116]:

np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)

Out[116]:
array([[1, 4, 6],
       [1, 5, 6],
       [2, 4, 6],
       [2, 5, 6],
       [3, 4, 6],
       [3, 5, 6],
       [1, 4, 7],
       [1, 5, 7],
       [2, 4, 7],
       [2, 5, 7],
       [3, 4, 7],
       [3, 5, 7]])

最終結果の順序が若干異なることに注意してください。

于 2016-02-24T17:14:46.077 に答える
174

これが純粋な実装です。itertoolsを使用するよりも約5倍高速です。

Python 3:

import numpy as np

def cartesian(arrays, out=None):
    """
    Generate a cartesian product of input arrays.

    Parameters
    ----------
    arrays : list of array-like
        1-D arrays to form the cartesian product of.
    out : ndarray
        Array to place the cartesian product in.

    Returns
    -------
    out : ndarray
        2-D array of shape (M, len(arrays)) containing cartesian products
        formed of input arrays.

    Examples
    --------
    >>> cartesian(([1, 2, 3], [4, 5], [6, 7]))
    array([[1, 4, 6],
           [1, 4, 7],
           [1, 5, 6],
           [1, 5, 7],
           [2, 4, 6],
           [2, 4, 7],
           [2, 5, 6],
           [2, 5, 7],
           [3, 4, 6],
           [3, 4, 7],
           [3, 5, 6],
           [3, 5, 7]])

    """

    arrays = [np.asarray(x) for x in arrays]
    dtype = arrays[0].dtype

    n = np.prod([x.size for x in arrays])
    if out is None:
        out = np.zeros([n, len(arrays)], dtype=dtype)

    #m = n / arrays[0].size
    m = int(n / arrays[0].size) 
    out[:,0] = np.repeat(arrays[0], m)
    if arrays[1:]:
        cartesian(arrays[1:], out=out[0:m, 1:])
        for j in range(1, arrays[0].size):
        #for j in xrange(1, arrays[0].size):
            out[j*m:(j+1)*m, 1:] = out[0:m, 1:]
    return out

Python 2:


import numpy as np

def cartesian(arrays, out=None):
    arrays = [np.asarray(x) for x in arrays]
    dtype = arrays[0].dtype

    n = np.prod([x.size for x in arrays])
    if out is None:
        out = np.zeros([n, len(arrays)], dtype=dtype)

    m = n / arrays[0].size
    out[:,0] = np.repeat(arrays[0], m)
    if arrays[1:]:
        cartesian(arrays[1:], out=out[0:m, 1:])
        for j in xrange(1, arrays[0].size):
            out[j*m:(j+1)*m, 1:] = out[0:m, 1:]
    return out
于 2009-08-05T19:48:42.863 に答える
12

このようなことができます

import numpy as np

def cartesian_coord(*arrays):
    grid = np.meshgrid(*arrays)        
    coord_list = [entry.ravel() for entry in grid]
    points = np.vstack(coord_list).T
    return points

a = np.arange(4)  # fake data
print(cartesian_coord(*6*[a])

を与える

array([[0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 2],
   ..., 
   [3, 3, 3, 3, 3, 1],
   [3, 3, 3, 3, 3, 2],
   [3, 3, 3, 3, 3, 3]])
于 2014-08-23T14:38:44.677 に答える
11

次の numpy の実装は約である必要があります。指定された回答の速度の 2 倍:

def cartesian2(arrays):
    arrays = [np.asarray(a) for a in arrays]
    shape = (len(x) for x in arrays)

    ix = np.indices(shape, dtype=int)
    ix = ix.reshape(len(arrays), -1).T

    for n, arr in enumerate(arrays):
        ix[:, n] = arrays[n][ix[:, n]]

    return ix
于 2014-09-03T23:22:41.987 に答える
10

関数を評価するためにグリッドが必要なようです。その場合、numpy.ogrid(open) またはnumpy.mgrid(fleshed out)を使用できます。

import numpy
my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]
于 2011-09-20T07:37:36.190 に答える
8

純粋な NumPy を使用し、再帰もリスト内包表記も明示的な for ループも使用しない、さらに別の方法を次に示します。元の回答よりも約 20% 遅く、np.meshgrid に基づいています。

def cartesian(*arrays):
    mesh = np.meshgrid(*arrays)  # standard numpy meshgrid
    dim = len(mesh)  # number of dimensions
    elements = mesh[0].size  # number of elements, any index will do
    flat = np.concatenate(mesh).ravel()  # flatten the whole meshgrid
    reshape = np.reshape(flat, (dim, elements)).T  # reshape and transpose
    return reshape

例えば、

x = np.arange(3)
a = cartesian(x, x, x, x, x)
print(a)

与える

[[0 0 0 0 0]
 [0 0 0 0 1]
 [0 0 0 0 2]
 ..., 
 [2 2 2 2 0]
 [2 2 2 2 1]
 [2 2 2 2 2]]
于 2016-01-21T18:33:29.617 に答える