에서 고유 한 행을 찾아야합니다 numpy.array
.
예를 들면 다음과 같습니다.
>>> a # I have
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 0]])
나는 세트를 만들고 배열을 반복 할 수 있다는 것을 알고 있지만 효율적인 순수한 numpy
솔루션을 찾고 있습니다. 데이터 형식을 void로 설정하는 방법이 있다고 생각하고 사용할 수 numpy.unique
는 있지만 사용할 수있는 방법을 알 수 없었습니다.
답변
NumPy 1.13부터 N-dim 배열에서 고유 한 값을 선택할 축을 간단히 선택할 수 있습니다. 고유 한 행을 얻으려면 다음을 수행하십시오.
unique_rows = np.unique(original_array, axis=0)
답변
또 다른 가능한 해결책
np.vstack({tuple(row) for row in a})
답변
구조적 배열을 사용하는 또 다른 옵션 void
은 전체 행을 단일 항목으로 결합 하는 유형 의 뷰를 사용하는 것입니다 .
a = np.array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
_, idx = np.unique(b, return_index=True)
unique_a = a[idx]
>>> unique_a
array([[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
EDITnp.ascontiguousarray
@seberg의 추천에 따라
추가되었습니다 . 배열이 아직 인접하지 않은 경우 메소드 속도가 느려집니다.
편집
위의 내용은 명확성을 희생하여 약간 속도를 높일 수 있습니다.
unique_a = np.unique(b).view(a.dtype).reshape(-1, a.shape[1])
또한 적어도 내 시스템에서 성능면에서 lexsort 방법보다 성능이 우수합니다.
a = np.random.randint(2, size=(10000, 6))
%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
100 loops, best of 3: 3.17 ms per loop
%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
100 loops, best of 3: 5.93 ms per loop
a = np.random.randint(2, size=(10000, 100))
%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
10 loops, best of 3: 29.9 ms per loop
%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
10 loops, best of 3: 116 ms per loop
답변
일련의 튜플 또는 다른 유사한 데이터 구조로 변환하는 데 드는 메모리 비용을 피하려면 numpy의 구조적 배열을 이용할 수 있습니다.
트릭은 원래 배열을 각 배열이 원래 배열의 행에 해당하는 구조적 배열로 보는 것입니다. 이것은 복사본을 만들지 않으며 매우 효율적입니다.
간단한 예를 들면 다음과 같습니다.
import numpy as np
data = np.array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)
uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq
무슨 일이 일어나고 있는지 이해하려면 중개 결과를 살펴보십시오.
사물을 구조적 배열로 보면 배열의 각 요소는 원래 배열의 행입니다. 기본적으로 튜플 목록과 유사한 데이터 구조입니다.
In [71]: struct
Out[71]:
array([[(1, 1, 1, 0, 0, 0)],
[(0, 1, 1, 1, 0, 0)],
[(0, 1, 1, 1, 0, 0)],
[(1, 1, 1, 0, 0, 0)],
[(1, 1, 1, 1, 1, 0)]],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])
In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])
일단 실행 numpy.unique
하면 구조화 된 배열을 다시 얻게됩니다.
In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])
우리는 “정상적인”배열로보기 (필요로하는 _
상점의 마지막 계산 결과 ipython
당신이보고있는 이유입니다 _.view...
) :
In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])
그런 다음 2D 배열로 다시 모양을 변경하십시오 ( -1
자리 수는 numpy에게 올바른 행 수를 계산하고 열 수를 지정하도록 지시합니다).
In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
더 간결하게하고 싶다면 다음과 같이 작성할 수 있습니다.
import numpy as np
def unique_rows(data):
uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
return uniq.view(data.dtype).reshape(-1, data.shape[1])
data = np.array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
print unique_rows(data)
결과 :
[[0 1 1 1 0 0]
[1 1 1 0 0 0]
[1 1 1 1 1 0]]
답변
np.unique
실행할 때 np.random.random(100).reshape(10,10)
고유 한 개별 요소를 모두 반환하지만 고유 한 행을 원하므로 먼저 튜플에 넣어야합니다.
array = #your numpy array of lists
new_array = [tuple(row) for row in array]
uniques = np.unique(new_array)
이것이 내가 원하는 것을하기 위해 유형을 변경하는 유일한 방법이며, 튜플로 변경하는 목록 반복이 “반복되지 않음”으로 괜찮은지 확실하지 않습니다.
답변
np.unique는 평평한 배열을 정렬 한 다음 각 항목이 이전 항목과 같은지 확인하여 작동합니다. 이 작업은 병합하지 않고 수동으로 수행 할 수 있습니다.
ind = np.lexsort(a.T)
a[ind[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]]
이 방법은 튜플을 사용하지 않으며 여기에 제공된 다른 방법보다 훨씬 빠르고 간단해야합니다.
참고 : 이것의 이전 버전에는 a [바로 뒤에 표시가 없었습니다. 이는 잘못된 인덱스가 사용되었음을 의미합니다. 또한, 조 킹톤이 그 좋은 점하게 수행 중간 사본의 다양성을 확인합니다. 다음 방법은 정렬 된 사본을 작성한 후보기를 사용하여 더 적게 만듭니다.
b = a[np.lexsort(a.T)]
b[np.concatenate(([True], np.any(b[1:] != b[:-1],axis=1)))]
이것은 더 빠르고 더 적은 메모리를 사용합니다.
또한 배열의 차원 수에 관계없이 ndarray에서 고유 행을 찾으려면 다음이 작동합니다.
b = a[lexsort(a.reshape((a.shape[0],-1)).T)];
b[np.concatenate(([True], np.any(b[1:]!=b[:-1],axis=tuple(range(1,a.ndim)))))]
흥미로운 나머지 문제는 임의의 차원 배열의 임의의 축을 따라 정렬 / 고유하게하려는 경우 더 어려울 것입니다.
편집하다:
속도 차이를 보여주기 위해 ipython에서 답변에 설명 된 세 가지 다른 방법 중 몇 가지 테스트를 실행했습니다. 으로 당신 이 버전이 조금 더 빠르다 불구하고 정확한 A, 너무 많은 차이가되지 않습니다 :
In [87]: %timeit unique(a.view(dtype)).view('<i8')
10000 loops, best of 3: 48.4 us per loop
In [88]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True], np.any(a[ind[1:]]!= a[ind[:-1]], axis=1)))]
10000 loops, best of 3: 37.6 us per loop
In [89]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10000 loops, best of 3: 41.6 us per loop
그러나 더 큰 a를 사용하면이 버전이 훨씬 빨라집니다.
In [96]: a = np.random.randint(0,2,size=(10000,6))
In [97]: %timeit unique(a.view(dtype)).view('<i8')
10 loops, best of 3: 24.4 ms per loop
In [98]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10 loops, best of 3: 28.2 ms per loop
In [99]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!= a[ind[:-1]],axis=1)))]
100 loops, best of 3: 3.25 ms per loop
답변
@Greg pythonic answer의 또 다른 변형입니다.
np.vstack(set(map(tuple, a)))