prosource

NumPy를 사용하여 두 배열의 모든 조합 배열 작성

probook 2023. 6. 2. 20:38
반응형

NumPy를 사용하여 두 배열의 모든 조합 배열 작성

저는 복잡한 일을 하기 전에 6개의 변수 함수의 매개변수 공간을 훑어보고 수치 동작을 연구하려고 합니다. 그래서 저는 이것을 할 수 있는 효율적인 방법을 찾고 있습니다.

제 함수는 6차원 NumPy 배열에 주어진 부동값을 입력으로 사용합니다.제가 처음에 하려고 했던 것은 다음과 같습니다.

먼저 두 개의 어레이를 사용하여 두 어레이의 모든 값 조합으로 어레이를 생성하는 함수를 만들었습니다.

from numpy import *

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

나서, 저는 다음에제가그를 했습니다.reduce()동일한 배열의 tom 복사본에 적용하기

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)

효과는 있지만, 너무 느립니다.매개 변수의 공간이 매우 넓다는 것은 알지만, 이 작업이 그렇게 느려서는 안 됩니다.이 예에서는 10(백만) 포인트만 샘플링했으며6 어레이를 생성하는 데만 15초 이상이 걸렸습니다.values.

NumPy로 이를 수행하는 더 효율적인 방법이 있습니까?

는 는나기능수있습 수 을 니 다 할 정 있 니F필요하면 주장을 받아들입니다.

최신 버전의 NumPy(>1.8.x)에서는 훨씬 더 빠른 구현을 제공합니다.

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() 예전에는 2차원이었지만, 지금은 다차원이 될 수 있습니다.이 경우, 3차원:

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]])

최종 결과의 순서가 약간 다릅니다.

다음은 순수한 NumPy 구현입니다.그것은 그것의 도구를 사용하는 것보다 약 5배 더 빠릅니다.

파이썬 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

파이썬 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

itertools.combinations는 일반적으로 Python 컨테이너에서 조합을 가져오는 가장 빠른 방법입니다(만약 실제로 조합을 원한다면, 반복 없이 순서와 무관하게 배열합니다; 그것은 당신의 코드가 하고 있는 것처럼 보이지 않습니다.하지만 코드가 버그가 있어서 그런 건지, 잘못된 용어를 사용해서 그런 건지 알 수가 없습니다.

조합과 다른 것을 원한다면, 아마도 그 도구에 있는 다른 반복자들일 것입니다.product또는permutations당신에게 더 도움이 될 수도 있습니다.예를 들어 코드는 다음과 거의 같습니다.

for val in itertools.product(np.arange(0, 1, 0.1), repeat=6):
    print F(val)

이 모든 반복기는 목록이나 NumPy 배열이 아닌 튜플을 생성하므로 F가 NumPy 배열을 얻는 데 까다롭다면 각 단계에서 하나를 구성하거나 지우고 다시 채우는 추가 오버헤드를 받아들여야 합니다.

사용할 수 있습니다.np.array(itertools.product(a, b)).

당신은 이런 것을 할 수 있습니다.

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]])

다음 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

기능을 평가하기 위해 그리드를 원하는 것처럼 보이며, 이 경우 numpy.ogrid(열림) 또는 numpy.mgrid(늘어진 상태)를 사용할 수 있습니다.

import numpy

my_grid = numpy.mgrid[[slice(0, 1, 0.1)]*6]

순수한 NumPy를 사용하는 또 다른 방법이 있습니다. 재귀, 목록 이해, 루프에 대한 명시적인 설명이 없습니다.원래 답변보다 약 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]]

1차원 배열(또는 플랫 파이썬 목록)의 데카르트 곱의 순수한 NumPy 구현을 위해서는 meshgrid()를 사용하고 transcose()로 축을 굴린 다음 원하는 출력으로 모양을 변경합니다.

 def cartprod(*arrays):
     N = len(arrays)
     return transpose(meshgrid(*arrays, indexing='ij'),
                      roll(arange(N + 1), -1)).reshape(-1, N)

마지막 축이 가장 빠르게 변경되는 관례가 있습니다("C 스타일" 또는 "행-장조").

In [88]: cartprod([1,2,3], [4,8], [100, 200, 300, 400], [-5, -4])
Out[88]:
array([[  1,   4, 100,  -5],
       [  1,   4, 100,  -4],
       [  1,   4, 200,  -5],
       [  1,   4, 200,  -4],
       [  1,   4, 300,  -5],
       [  1,   4, 300,  -4],
       [  1,   4, 400,  -5],
       [  1,   4, 400,  -4],
       [  1,   8, 100,  -5],
       [  1,   8, 100,  -4],
       [  1,   8, 200,  -5],
       [  1,   8, 200,  -4],
       [  1,   8, 300,  -5],
       [  1,   8, 300,  -4],
       [  1,   8, 400,  -5],
       [  1,   8, 400,  -4],
       [  2,   4, 100,  -5],
       [  2,   4, 100,  -4],
       [  2,   4, 200,  -5],
       [  2,   4, 200,  -4],
       [  2,   4, 300,  -5],
       [  2,   4, 300,  -4],
       [  2,   4, 400,  -5],
       [  2,   4, 400,  -4],
       [  2,   8, 100,  -5],
       [  2,   8, 100,  -4],
       [  2,   8, 200,  -5],
       [  2,   8, 200,  -4],
       [  2,   8, 300,  -5],
       [  2,   8, 300,  -4],
       [  2,   8, 400,  -5],
       [  2,   8, 400,  -4],
       [  3,   4, 100,  -5],
       [  3,   4, 100,  -4],
       [  3,   4, 200,  -5],
       [  3,   4, 200,  -4],
       [  3,   4, 300,  -5],
       [  3,   4, 300,  -4],
       [  3,   4, 400,  -5],
       [  3,   4, 400,  -4],
       [  3,   8, 100,  -5],
       [  3,   8, 100,  -4],
       [  3,   8, 200,  -5],
       [  3,   8, 200,  -4],
       [  3,   8, 300,  -5],
       [  3,   8, 300,  -4],
       [  3,   8, 400,  -5],
       [  3,   8, 400,  -4]])

번째 축을 가장 빨리 변경하려면("Fortran 스타일" 또는 "column-major"),order의 매개 변수.reshape()다음과 같이:reshape((-1, N), order='F')

판다의 합병()은 이 문제에 대한 순진하고 빠른 해결책을 제공합니다.

# Given the lists
x, y, z = [1, 2, 3], [4, 5], [6, 7]

# Get dataframes with the same, constant index 
x = pd.DataFrame({'x': x}, index=np.repeat(0, len(x)))
y = pd.DataFrame({'y': y}, index=np.repeat(0, len(y)))
z = pd.DataFrame({'z': z}, index=np.repeat(0, len(z)))

# Get all permutations stored in a new dataframe
df = pd.merge(x, pd.merge(y, z, left_index=True, right_index=True),
              left_index=True, right_index=True)

언급URL : https://stackoverflow.com/questions/1208118/using-numpy-to-build-an-array-of-all-combinations-of-two-arrays

반응형