2017-09-21 2 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 '에 비해 성능이 뛰어나다는 것을 자주 읽었 기 때문입니다. 더 자주 계산해야하는 작업의 경우 확실히 두 가지를 모두 시도하고 더 빠른 작업을 찾습니다. 그러나 이것이 일회성 일이기 때문에 나는 Divakar의 해결책을 찾기로 결심했다. 하지만 너 덕분에! – offeltoffel

답변

3

meshgrid은 가능한 모든 조합을 만들 때 작동하지 않을 것이라고 생각하지 마십시오 (나중에 필터링하지 않아도 됨). 이를 해결하기 위해 두 가지 접근법을 제안 할 수 있습니다.

우리는 중복없이 그 페어 조합의 행 인덱스를 얻을 수 있습니다 다음 행으로 단순히 인덱스가 같은, 원하는 출력을 얻기 위해 1

접근 번호 -

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

얻을려면 어레이로 원하는 출력 - 두 번째 축을 따라 스택 -

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

기능 :

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

접근 # 메모리 효율성 때문에 성능 목표 2 slicing 또 다른 및 array-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

관련 문제