numpy.array에서 고유 한 행 찾기


199

에서 고유 한 행을 찾아야합니다 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는 있지만 사용할 수있는 방법을 알 수 없었습니다.


11
팬더에는 dataframe.drop_duplicates () 메소드가 있습니다. stackoverflow.com/questions/12322779/pandas-unique-dataframepandas.pydata.org/pandas-docs/dev/generated/…를
codeape

고맙지 만 팬더는 사용할 수 없습니다.
Akavall


1
@Andy Hayden은 제목에도 불구하고이 질문과 중복되지 않습니다. codeape의 링크는 중복입니다.
Wai Yip Tung

5
이 기능은 기본적으로 1.13에 제공됩니다. github.com/numpy/numpy/pull/7742
Eric

답변:


115

NumPy 1.13부터 N-dim 배열에서 고유 한 값을 선택할 축을 간단히 선택할 수 있습니다. 고유 한 행을 얻으려면 다음을 수행하십시오.

unique_rows = np.unique(original_array, axis=0)


12
이 기능에주의하십시오. 중복 행이 제거 된 배열을np.unique(list_cor, axis=0)습니다 . 원래 배열에서 고유 한 요소로 배열을 필터링하지 않습니다 . 예를 들어 여기를 참조 하십시오 .
Brad Solomon

행의 값 순서를 무시하고 고유 한 행을 원할 경우 먼저 열에서 원래 배열을 먼저 정렬 할 수 있습니다.original_array.sort(axis=1)
mangecoeur

140

또 다른 가능한 해결책

np.vstack({tuple(row) for row in a})

20
+1 이것은 명확하고 짧으며 파이썬입니다. 속도가 실제 문제가 아닌 한, 이러한 유형의 솔루션은이 질문 IMO에 대한 복잡하고 높은 투표 응답보다 우선해야합니다.
Bill Cheatham

3
우수한! 중괄호 또는 set () 함수가 트릭을 수행합니다.
Tian He

2
@Greg von Winckel 순서를 바꾸지 않는 무언가를 제안 할 수 있습니까?
Laschet Jain

예, 그러나 단일 명령에는 없습니다 : x = []; [x.append (tuple (r)) x에없는 if 튜플 (r)의 r에 대한]; a_unique = 배열 ​​(x);
그렉 폰 윙켈

1
FutureWarning을 피하려면 집합을 다음과 같은 목록으로 변환하십시오. np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]})) FutureWarning : 스택 할 배열은 목록 또는 튜플과 같은 "시퀀스"유형으로 전달되어야합니다. NumPy 1.16부터는 제너레이터와 같은 비 시퀀스 이터 러블에 대한 지원이 더 이상 사용되지 않으며 향후 오류가 발생합니다.
leermeester '12

111

구조적 배열을 사용하는 또 다른 옵션 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

3
고마워 이것은 내가 찾고있는 대답입니다.이 단계에서 무슨 일이 일어나고 있는지 설명 할 수 b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))있습니까?
Akavall

3
@Akavall np.void전체 행의 바이트 수인 데이터 유형의 크기 로 데이터 보기를 작성합니다 . 의 배열이 있고 np.uint8s로 볼 때 얻는 것과 비슷한 두 가지입니다.이 np.uint16두 열을 하나의 열로 결합하지만 더 유연합니다.
Jaime

3
@Jaime, 당신은 np.ascontiguousarray일반적으로 안전하기 위해 또는 비슷한 것을 추가 할 수 있습니까 (필요하지만 조금 더 제한적이라는 것을 알고 있습니다 ...). 보기가 예상대로 작동 하려면 행 이 연속적 이어야합니다 .
seberg 2016 년

2
@ConstantineEvans 최근에 추가 된 것입니다 : numpy 1.6에서 np.unique배열의 배열 에서 실행하려고하면 np.void해당 유형에 대해 병합되지 않은 mergesort와 관련된 오류 가 반환됩니다. 1.7에서 잘 작동합니다.
Jaime

9
이 방법이 부동 소수점 숫자에 사용되는 경우 -0.와 같지 않은 캐치가 +0.있지만, 요소 별 비교 -0.==+0.(ieee float 표준에 지정된대로)와 비교할 수 있습니다 . 참조 stackoverflow.com/questions/26782038/...
tom10

29

일련의 튜플 또는 다른 유사한 데이터 구조로 변환하는 데 드는 메모리 비용을 피하려면 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]]

이것은 실제로 튜플을 사용하는 것만 큼 느리게 보입니다. 이와 같이 구조화 된 배열을 정렬하는 것은 느립니다.
cge

3
@cge-더 큰 배열로 시도하십시오. 네, numpy 배열을 정렬하는 것은 목록을 정렬하는 것보다 느립니다. ndarray를 사용하는 대부분의 경우 속도는 주요 고려 사항이 아닙니다. 메모리 사용량입니다. 튜플 목록은 이 솔루션보다 훨씬 더 많은 메모리 를 사용 합니다. 메모리가 충분하더라도 상당히 큰 배열로 튜플 목록으로 변환하면 속도 이점보다 오버 헤드가 더 큽니다.
Joe Kington

@cge-아, 나는 당신이 사용하고있는 것을 보지 못했습니다 lexsort. 나는 당신이 튜플 목록을 사용하는 것을 언급하고 있다고 생각했습니다. 예, lexsort아마도이 경우 더 좋은 옵션 일 것입니다. 나는 그것을 잊어 버렸고 지나치게 복잡한 솔루션으로 뛰어 들었습니다.
Joe Kington

20

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)

이것이 내가 원하는 것을하기 위해 유형을 변경하는 유일한 방법이며, 튜플로 변경하는 목록 반복이 "반복되지 않음"으로 괜찮은지 확실하지 않습니다.


5
+1 이것은 명확하고 짧으며 파이썬입니다. 속도가 실제 문제가 아닌 한, 이러한 유형의 솔루션은이 질문 IMO에 대한 복잡하고 높은 투표 응답보다 우선해야합니다.
Bill Cheatham

나는 수용 된 솔루션보다 이것을 선호합니다. < 100호출 당 행 수만 있기 때문에 속도는 문제가되지 않습니다 . 이것은 고유 한 행을 수행하는 방법을 정확하게 설명합니다.
rayryeng

4
이것은 실제로 내 데이터 uniques에는 작동하지 않으며 고유 한 요소를 포함합니다. 잠재적으로 나는 예상되는 모양을 잘못 이해합니다. array여기서 더 정확할 수 있습니까?
FooBar

@ ryan-saxe 나는 이것이 pythonic 인 것을 좋아하지만 반환 된 행 uniques이 정렬되어 (따라서의 행과 다르기 때문에) 이것은 좋은 해결책이 아닙니다 array. B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
jmlarson

16

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

아주 좋아요! 참고로, 여러 개의 중간 사본을 만듭니다. (예를 들어 a[ind[1:]]사본 등) 반면에, 솔루션은 일반적으로 램이 다 떨어질 때까지 광산보다 2-3 배 빠릅니다.
Joe Kington

좋은 지적. a_sorted [1 :]는 a_sorted의 복사본이 아니기 때문에 인덱스 만 사용하여 중개 복사본을 꺼내려는 시도는 내 방법이 더 많은 메모리를 사용하고 배열의 정렬 된 복사본을 만드는 것보다 느리게 만듭니다. .
cge

무엇 dtype당신의 타이밍에? 나는 당신이 하나 잘못 생각합니다. 내 시스템 np.unique에서 내 답변에 설명 된대로 전화 하는 것이 두 가지 맛 중 하나를 사용하는 것보다 약간 빠릅니다 np.lexsort. 그리고 고유 항목을 찾기위한 배열의 모양이 약 5 배 빠릅니다 (10000, 100). np.unique일부 (사소한) 실행 시간을 잘라내는 작업 을 다시 구현하기로 결정하더라도 모든 행을 단일 객체로 축소 np.any하면 특히 열 수를 높이기 위해 열 비교 를 호출 하는 것보다 빠른 비교가 실행됩니다 .
Jaime

@ cge : 아마도 표준 'any'대신 'np.any'를 의미했을 것입니다.
M. Toya

@Jaime-나는 Joe Kington이 그의 대답에서했던 dtype것처럼 a.dtype, 단지 보고 있는 데이터의 데이터 유형 이라고 생각 합니다. 열이 많은 경우 빠르게 사용하는 또 다른 방법 (불완전한 방법) lexsort은 몇 개의 열만 정렬하는 것입니다. 이것은 완벽하게 정렬하기에 충분한 분산을 제공하는 열을 알아야하기 때문에 데이터에 따라 다릅니다. 예를 들어 a.shape = (60000, 500), 처음 3 개의 열을 기준으로 정렬하십시오 ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])). 시간 절약은 상당히 상당하지만 면책 조항은 모든 경우를 포착하지 못할 수도 있습니다. 데이터에 따라 다릅니다.
n1k31t4

9

@Greg pythonic answer의 또 다른 변형입니다.

np.vstack(set(map(tuple, a)))

9

나는 속도에 대한 제안 된 대안을 비교 즉, 놀랍게도, 무효 뷰 발견했습니다 unique솔루션도 조금 더 빠른 NumPy와의 기본보다 uniqueaxis인수. 속도를 찾고 있다면 원할 것입니다

numpy.unique(
    a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
    ).view(a.dtype).reshape(-1, a.shape[1])

여기에 이미지 설명을 입력하십시오


줄거리를 재현하는 코드 :

import numpy
import perfplot


def unique_void_view(a):
    return numpy.unique(
        a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
        ).view(a.dtype).reshape(-1, a.shape[1])


def lexsort(a):
    ind = numpy.lexsort(a.T)
    return a[ind[
        numpy.concatenate((
            [True], numpy.any(a[ind[1:]] != a[ind[:-1]], axis=1)
            ))
        ]]


def vstack(a):
    return numpy.vstack({tuple(row) for row in a})


def unique_axis(a):
    return numpy.unique(a, axis=0)


perfplot.show(
    setup=lambda n: numpy.random.randint(2, size=(n, 20)),
    kernels=[unique_void_view, lexsort, vstack, unique_axis],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    xlabel='len(a)',
    equality_check=None
    )

1
아주 좋은 대답, 하나의 사소한 점 : vstack_dict, dict을 사용하지 마십시오 . 중괄호는 설정된 이해이므로 동작은 거의 동일합니다 vstatck_set. , 이후 vstack_dict성능 라인이 이리저리 그래프없는, 그것은 단지에 포함되는 것 같습니다 vstack_set그들이 그렇게 비슷하기 때문에, 성능 그래프!
Akavall

답장을 보내 주셔서 감사합니다. vstack변형을 하나만 포함하도록 줄거리를 개선했습니다 .
Nico Schlömer

8

선형 대수 또는 벡터 공간 감지에서 부동 소수점 배열을 처리하는 사람이 없기 때문에 이러한 답변을 좋아하지 않았습니다. 공차 임계 값 https://stackoverflow.com/a/26867764/500207 을 가진 하나의 대답 은 임계 값을 요소 별 및 십진 정밀도로 가져 왔으며 일부 경우에는 작동하지만 수학적으로 일반적인 것은 아닙니다. 실제 벡터 거리.

내 버전은 다음과 같습니다.

from scipy.spatial.distance import squareform, pdist

def uniqueRows(arr, thresh=0.0, metric='euclidean'):
    "Returns subset of rows that are unique, in terms of Euclidean distance"
    distances = squareform(pdist(arr, metric=metric))
    idxset = {tuple(np.nonzero(v)[0]) for v in distances <= thresh}
    return arr[[x[0] for x in idxset]]

# With this, unique columns are super-easy:
def uniqueColumns(arr, *args, **kwargs):
    return uniqueRows(arr.T, *args, **kwargs)

위의 퍼블릭 도메인 함수 scipy.spatial.distance.pdist 사이의 유클리드 (사용자 정의 가능) 거리를 찾는 데 사용 합니다 . 그런 다음 각 거리를 thresh이전 거리와 비교하여 서로 속한 행을 찾고 threshthresh클러스터 에서 한 행만 반환합니다 .

암시 된 바와 같이, 거리 metric필요가 없을 Euclidean- pdist포함한 잡다한 거리를 계산할 수있다 cityblock(맨하탄 규범) 및cosine (벡터 사이의 각도 .

thresh=0(기본값) 인 경우 "고유 한"것으로 간주 되려면 행이 비트 단위 여야합니다. thresh스케일링 된 기계 정밀도를 위한 다른 좋은 값 , 즉 thresh=np.spacing(1)*1e3.


가장 좋은 답변입니다. 감사. 지금까지 작성된 가장 (수학적으로) 일반화 된 답변입니다. 행렬을 N 차원 공간에서 일련의 데이터 점 또는 샘플로 간주하고 동일하거나 유사한 점의 모음을 찾습니다 (유사성은 유클리드 거리 또는 다른 방법으로 정의 됨). 이러한 점은 데이터 점과 겹치거나 매우 가까운 이웃 일 수 있습니다. 마지막으로, 동일하거나 유사한 포인트의 모음은 동일한 세트에 속하는 포인트 (위의 답변에서 첫 번째 포인트) 중 하나로 대체됩니다. 이는 포인트 클라우드에서 중복성을 줄이는 데 도움이됩니다.
Sanchit

@Sanchit aha, 그것은 좋은 점 set입니다. 각 thresh크기의 이웃 을 대표 하는 "첫 번째"점을 선택하는 대신 (실제로 파이썬이 점을 저장하는 방법에 따라 다르기 때문에 실제로 무작위로 나올 수 있습니다 ) , 함수는 예를 들어, "중앙"또는 중심에 가장 가까운 점 등을 사용하여 점을 선택하는 방법을 지정할 수 있습니다.
Ahmed Fasih

확실한. 의심의 여지가 없습니다. 나는 이것이 당신의 프로그램이하고있는 것이기 때문에 첫 번째 요점을 언급했습니다.
Sanchit

단지 수정 — 각 thresh클러스터 에 대해 선택된 행 은 순서가 정해지지 않기 때문에 임의적 이라고 잘못 잘못 언급했습니다 set. 내 인생에 brainfart입니다 물론, set에있는 인덱스의 저장 튜플 thresh이 있으므로, -neighborhood findRows 하지 각각에 대해, 사실의 대가로 thresh-cluster, 그것의 첫 번째 행.
Ahmed Fasih

3

drop_duplicates팬더에서 사용하지 않는 이유 :

>>> timeit pd.DataFrame(image.reshape(-1,3)).drop_duplicates().values
1 loops, best of 3: 3.08 s per loop

>>> timeit np.vstack({tuple(r) for r in image.reshape(-1,3)})
1 loops, best of 3: 51 s per loop

나는 실제로이 대답을 좋아합니다. 물론, 그것은 numpy를 직접 사용하지 않지만, 나에게 빠르면서 이해하는 것이 가장 쉬운 방법입니다.
noctilux

3

numpy_indexed 패키지 (면책 조항 : 나는 그것의 저자)이 멋진에서 제이미에 의해 게시 솔루션 및 테스트 인터페이스, 플러스 더 많은 기능을 래핑 :

import numpy_indexed as npi
new_a = npi.unique(a)  # unique elements over axis=0 (rows) by default

1

np.unique는 튜플 목록이 제공됩니다.

>>> np.unique([(1, 1), (2, 2), (3, 3), (4, 4), (2, 2)])
Out[9]: 
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

목록의 목록으로 TypeError: unhashable type: 'list'


내 일을하지 않는 것 같습니다. 각 튜플은 두 개의 부동 숫자 대신 두 개의 문자열입니다.
mjp

작동하지 않으면 튜플이 아닌 요소 목록을 반환합니다.
Mohanad Kaleia

1

이 페이지의 답변을 바탕으로 MATLAB의 unique(input,'rows')기능 을 복제하는 기능과 고유성을 확인하기위한 허용 오차를 수용하는 추가 기능을 작성했습니다. 또한 인덱스 등 그 반환 c = data[ia,:]data = c[ic,:]. 불일치 또는 오류가 있으면보고하십시오.

def unique_rows(data, prec=5):
    import numpy as np
    d_r = np.fix(data * 10 ** prec) / 10 ** prec + 0.0
    b = np.ascontiguousarray(d_r).view(np.dtype((np.void, d_r.dtype.itemsize * d_r.shape[1])))
    _, ia = np.unique(b, return_index=True)
    _, ic = np.unique(b, return_inverse=True)
    return np.unique(b).view(d_r.dtype).reshape(-1, d_r.shape[1]), ia, ic

1

@Jaime의 훌륭한 대답 외에도 행을 축소하는 또 다른 방법은와 동일한 (C 연속적 a.strides[0]이라고 가정 a)하는 것입니다 a.dtype.itemsize*a.shape[0]. 더욱이void(n) 바로 가기입니다 dtype((void,n)). 우리는이 최단 버전에 마침내 도착합니다 :

a[unique(a.view(void(a.strides[0])),1)[1]]

에 대한

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

0

3D 이상의 다차원 중첩 배열과 같은 일반적인 용도로 다음을 시도하십시오.

import numpy as np

def unique_nested_arrays(ar):
    origin_shape = ar.shape
    origin_dtype = ar.dtype
    ar = ar.reshape(origin_shape[0], np.prod(origin_shape[1:]))
    ar = np.ascontiguousarray(ar)
    unique_ar = np.unique(ar.view([('', origin_dtype)]*np.prod(origin_shape[1:])))
    return unique_ar.view(origin_dtype).reshape((unique_ar.shape[0], ) + origin_shape[1:])

2D 데이터 세트를 충족시키는

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]])
unique_nested_arrays(a)

제공합니다 :

array([[0, 1, 1, 1, 0, 0],
   [1, 1, 1, 0, 0, 0],
   [1, 1, 1, 1, 1, 0]])

또한 다음과 같은 3D 배열도 있습니다.

b = np.array([[[1, 1, 1], [0, 1, 1]],
              [[0, 1, 1], [1, 1, 1]],
              [[1, 1, 1], [0, 1, 1]],
              [[1, 1, 1], [1, 1, 1]]])
unique_nested_arrays(b)

제공합니다 :

array([[[0, 1, 1], [1, 1, 1]],
   [[1, 1, 1], [0, 1, 1]],
   [[1, 1, 1], [1, 1, 1]]])

unique return_indexas Jaime을 사용하면 마지막 return줄이 더 단순 해집니다. ar오른쪽 축의 원래 색인을 만드십시오 .
hpaulj

0

이 답변들 중 어느 것도 나를 위해 일하지 않았습니다. 고유 한 행에 숫자가 아닌 문자열이 포함되어 있다고 가정합니다. 그러나 다른 스레드 의이 답변은 효과가있었습니다.

출처 : https://stackoverflow.com/a/38461043/5402386

.count () 및 .index () 목록의 메소드를 사용할 수 있습니다

coor = np.array([[10, 10], [12, 9], [10, 5], [12, 9]])
coor_tuple = [tuple(x) for x in coor]
unique_coor = sorted(set(coor_tuple), key=lambda x: coor_tuple.index(x))
unique_count = [coor_tuple.count(x) for x in unique_coor]
unique_index = [coor_tuple.index(x) for x in unique_coor]

0

실제로 mxn 숫자 numpy 배열을 mx 1 numpy 문자열 배열로 바꿀 수 있습니다. 다음 함수를 사용해보십시오 .numpy.unique 와 같이 count , inverse_idx 등을 제공합니다 .

import numpy as np

def uniqueRow(a):
    #This function turn m x n numpy array into m x 1 numpy array storing 
    #string, and so the np.unique can be used

    #Input: an m x n numpy array (a)
    #Output unique m' x n numpy array (unique), inverse_indx, and counts 

    s = np.chararray((a.shape[0],1))
    s[:] = '-'

    b = (a).astype(np.str)

    s2 = np.expand_dims(b[:,0],axis=1) + s + np.expand_dims(b[:,1],axis=1)

    n = a.shape[1] - 2    

    for i in range(0,n):
         s2 = s2 + s + np.expand_dims(b[:,i+2],axis=1)

    s3, idx, inv_, c = np.unique(s2,return_index = True,  return_inverse = True, return_counts = True)

    return a[idx], inv_, c

예:

A = np.array([[ 3.17   9.502  3.291],
  [ 9.984  2.773  6.852],
  [ 1.172  8.885  4.258],
  [ 9.73   7.518  3.227],
  [ 8.113  9.563  9.117],
  [ 9.984  2.773  6.852],
  [ 9.73   7.518  3.227]])

B, inv_, c = uniqueRow(A)

Results:

B:
[[ 1.172  8.885  4.258]
[ 3.17   9.502  3.291]
[ 8.113  9.563  9.117]
[ 9.73   7.518  3.227]
[ 9.984  2.773  6.852]]

inv_:
[3 4 1 0 2 4 0]

c:
[2 1 1 1 2]

-1

전체 numpy 행렬을 목록으로 가져온 다음이 목록에서 중복을 삭제하고 마지막으로 고유 목록을 numpy 행렬로 다시 반환하십시오.

matrix_as_list=data.tolist() 
matrix_as_list:
[[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]]

uniq_list=list()
uniq_list.append(matrix_as_list[0])

[uniq_list.append(item) for item in matrix_as_list if item not in uniq_list]

unique_matrix=np.array(uniq_list)
unique_matrix:
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

-3

가장 간단한 해결책은 행을 문자열로 만들어 단일 항목을 만드는 것입니다. 그런 다음 numpy를 사용하여 각 행의 고유성을 전체적으로 비교할 수 있습니다. 이 솔루션은 일반화가 가능하므로 다른 조합을 위해 어레이를 재구성하고 바꾸면됩니다. 제공된 문제에 대한 해결책은 다음과 같습니다.

import numpy as np

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

uniques, index = np.unique([str(i) for i in original], return_index=True)
cleaned = original[index]
print(cleaned)    

줄게:

 array([[0, 1, 1, 1, 0, 0],
        [1, 1, 1, 0, 0, 0],
        [1, 1, 1, 1, 1, 0]])

우편으로 내 노벨상을 보내


다른 인쇄 옵션과 같이 매우 비효율적이고 오류가 발생하기 쉽습니다. 다른 옵션이 분명히 바람직합니다.
Michael

-3
import numpy as np
original = 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]])
# create a view that the subarray as tuple and return unique indeies.
_, unique_index = np.unique(original.view(original.dtype.descr * original.shape[1]),
                            return_index=True)
# get unique set
print(original[unique_index])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.