2017-10-04 1 views
1

np.unique()를 실행하면 배열을 평평하게 만들고 배열을 정렬 한 다음 고유 한 값을 찾습니다. 모양이있는 배열 (10, 3000, 3000)을 가지고있을 때, 유니크를 찾는 데는 약 1 초가 걸리지 만, np.unique()를 여러 번 호출해야하므로 빠르게 추가됩니다. 배열의 고유 숫자의 총 개수 만 신경 쓰므로 정렬은 시간 낭비처럼 보입니다.NumPy/Python

np.unique() 이외의 큰 배열에서 고유 값의 총 개수를 찾는 더 빠른 방법이 있습니까?

+0

(예를 들어, 'a.dtype'은 무엇입니까?)? –

+0

@WarrenWeckesser uint8 – onepint16oz

+4

팬더의 고유 기능이 정렬되지 않으므로 속도가 빠릅니다. 다음을 확인하십시오 : https://pandas.pydata.org/pandas-docs/stable/generated/pandas.unique.html – ayhan

답변

5

다음은 np.unique보다 빠른 dtype np.uint8 인 배열에서 작동하는 방법입니다.

먼저 작동하는 배열을 생성 : np.unique를 사용하여 고유 값을 찾은 후에 비교 용

In [128]: a = np.random.randint(1, 128, size=(10, 3000, 3000)).astype(np.uint8) 

:

In [129]: u = np.unique(a) 

여기서 빠른 방법이다; 우리가 같은 결과를 얻었다 것을

In [130]: q = np.zeros(256, dtype=int) 

In [131]: q[a.ravel()] = 1 

In [132]: v = np.nonzero(q)[0] 

확인 : v는 결과를 포함

In [133]: np.array_equal(u, v) 
Out[133]: True 

타이밍 :

그래서
In [134]: %timeit u = np.unique(a) 
2.86 s ± 9.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

In [135]: %timeit q = np.zeros(256, dtype=int); q[a.ravel()] = 1; v = np.nonzero(q) 
300 ms ± 5.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

대체 방법 np.unique()에 2.86 초, 0.3 초 .

+0

이것은 완벽하게 작동했습니다. 감사. 그것은 또한 정렬 된 고유 배열을 반환하는 데에도 사용할 수있는 것 같습니다. 나는 numpy가 그들이했던 방식으로 그들의 독특한()을 구현하기로 결정한 이유를 궁금해. – onepint16oz

+0

'numpy.unique'는 임의의 데이터 유형 (다양한 정수 및 부동 소수점 유형, 복합 유형 및 구조화 된 배열 모두)의 배열을 처리 할 수 ​​있습니다. 'numpy.unique'가이 메소드를 특별한 경우로 사용하여 하나의 (그리고 아마도 두 개의) 바이트 정수 타입을 처리하는 것이 가능할 것 같아 보입니다. –

3

범위가 uint8 인 범위로 제한하고 빈 값으로 np.bincount으로 계산 한 다음 단순히 0이 아닌 개수를 계산할 수 있습니다. np.bincount1D 배열을 필요로하기 때문에 np.ravel()으로 입력을 평평하게 한 다음 bincount으로 입력합니다.

따라서 구현 될 -

(np.bincount(a.ravel())!=0).sum() 

런타임 테스트

도우미 함수 고유 번호의 다양한 수의 입력 배열 만들 -

def create_input(n_unique): 
    unq_nums = np.random.choice(np.arange(256), n_unique,replace=0) 
    return np.random.choice(unq_nums, (10,3000,3000)).astype(np.uint8) 

다른 접근법 (들) :

제안 된 방법의 443,210

검증 -

In [141]: a = create_input(n_unique=120) 

In [142]: len(np.unique(a)) 
Out[142]: 120 

In [143]: (np.bincount(a.ravel())!=0).sum() 
Out[143]: 120 

타이밍 - 배열의 데이터 유형은 무엇

In [124]: a = create_input(n_unique=128) 

In [125]: %timeit len(np.unique(a)) # Original soln 
    ...: %timeit assign_method(a) # @Warren Weckesser's soln 
    ...: %timeit (np.bincount(a.ravel())!=0).sum() 
    ...: 
1 loop, best of 3: 3.09 s per loop 
1 loop, best of 3: 394 ms per loop 
1 loop, best of 3: 209 ms per loop 

In [126]: a = create_input(n_unique=256) 

In [127]: %timeit len(np.unique(a)) # Original soln 
    ...: %timeit assign_method(a) # @Warren Weckesser's soln 
    ...: %timeit (np.bincount(a.ravel())!=0).sum() 
    ...: 
1 loop, best of 3: 3.46 s per loop 
1 loop, best of 3: 378 ms per loop 
1 loop, best of 3: 212 ms per loop 
+0

니스. 나는 또한 bincount로 실험했지만, 느린 것으로 보였다. 실제로 코드를 사용할 때'assign_method (a)'는 295ms,'(np.bincount (a.ravel())! = 0) .sum()'은 425ms가됩니다. 그림을 이동. –

+0

@WarrenWeckesser 하드웨어 (CPU, RAM) 일 수 있습니다. 나는 Intel i7-6700HQ, 16GB RAM을 사용 중입니다. 하지만, 당신의 생각을 재현 할 수 있습니다 : https://ideone.com/WDWq9j – Divakar

+0

저는 "늦은 2013"Macbook Pro, 2.6 GHz Intel Core i7,16 GB 1600 MHz DDR3을 사용하고 있습니다. 또한 : 파이썬 3.5.2, numpy 1.13.1. –