2013-05-02 3 views
27

정수 (양수 또는 음수)가 포함 된 2D 배열이 있습니다. 각 행은 특정 공간 사이트에 대한 시간 경과에 따른 값을 나타내지 만 각 열은 주어진 시간 동안 다양한 공간 사이트 값을 나타냅니다. 어레이가 같은 경우numpy 배열로 모드를 찾는 가장 효율적인 방법

: 그래서

1 3 4 2 2 7 
5 2 2 1 4 1 
3 3 2 2 1 1 

결과는 모드에 대한 복수의 값이있는 경우, (무작위) 중 어느 하나가 모드로 설정할 수있는 것을

1 3 2 2 2 1 

참고되어야 .

한 번에 하나씩 모드를 찾는 열을 반복 할 수 있지만 numpy가이를 수행하는 내장 함수가있을 수 있기를 바랬습니다. 또는 반복하지 않고 효율적으로 찾을 수있는 트릭이있는 경우. (@ tom10의 의견에 의해 영감을)

+0

http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mstats.mode.html이 있으며 답변은 http://stackoverflow.com/questions/6252280/find입니다. 가장 빈번한 -number-in-numpy-vector – tom10

+1

@ tom10 : 당신은 [scipy.stats.mode()] (http : //docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mode.html # scipy.stats.mode), 맞습니까? 다른 하나는 마스크 된 배열을 출력하는 것 같습니다. – fgb

+0

@fgb : 맞습니다. 정정 해 주셔서 감사합니다 (귀하의 답변에 +1). – tom10

답변

52

확인 scipy.stats.mode() :

import numpy as np 
from scipy import stats 

a = np.array([[1, 3, 4, 2, 2, 7], 
       [5, 2, 2, 1, 4, 1], 
       [3, 3, 2, 2, 1, 1]]) 

m = stats.mode(a) 
print(m) 

출력 : 당신이 볼 수 있듯이

ModeResult(mode=array([[1, 3, 2, 2, 1, 1]]), count=array([[1, 2, 2, 2, 1, 2]])) 

, 그것은 모두 반환하는 모드뿐만 아니라 계산됩니다. 당신은 m[0]를 통해 직접 모드를 선택할 수 있습니다

print(m[0]) 

출력 :

[[1 3 2 2 1 1]] 
+3

그래서 numpy는 그 자체로 그러한 기능을 지원하지 않습니까? – Nik

+1

분명히 아니지만, [scipy의 구현은 numpy에만 의존합니다.] (http://stackoverflow.com/questions/12399107/alternative-to-scipy-mode-function-in-numpy), 그래서 당신은 그 코드를 당신의 컴퓨터에 복사 할 수 있습니다. 자신의 기능. – fgb

+5

장래에 이것을 보려는 사람들을 위해, 단지'import scipy.stats'가 필요합니다. 단순히'import scipy'를 할 때 포함되지 않습니다. – ffledgling

10

이 까다로운 문제를 축을 따라 모드를 계산하기 위해 많은 밖에 없기 때문이다. 이 솔루션은 1 차원 어레이의 경우 곧 바로 사용할 수 있습니다. numpy.bincountnumpy.unique이고 return_counts 인수는 True입니다. 가장 일반적으로 볼 수있는 n 차원 함수는 scipy.stats.mode입니다. 특히 많은 고유 값을 갖는 대형 배열의 경우에는 속도가 매우 느립니다. 솔루션으로, 나는이 기능을 개발했습니다, 그리고 많이 사용 :

import numpy 

def mode(ndarray, axis=0): 
    # Check inputs 
    ndarray = numpy.asarray(ndarray) 
    ndim = ndarray.ndim 
    if ndarray.size == 1: 
     return (ndarray[0], 1) 
    elif ndarray.size == 0: 
     raise Exception('Cannot compute mode on empty array') 
    try: 
     axis = range(ndarray.ndim)[axis] 
    except: 
     raise Exception('Axis "{}" incompatible with the {}-dimension array'.format(axis, ndim)) 

    # If array is 1-D and numpy version is > 1.9 numpy.unique will suffice 
    if all([ndim == 1, 
      int(numpy.__version__.split('.')[0]) >= 1, 
      int(numpy.__version__.split('.')[1]) >= 9]): 
     modals, counts = numpy.unique(ndarray, return_counts=True) 
     index = numpy.argmax(counts) 
     return modals[index], counts[index] 

    # Sort array 
    sort = numpy.sort(ndarray, axis=axis) 
    # Create array to transpose along the axis and get padding shape 
    transpose = numpy.roll(numpy.arange(ndim)[::-1], axis) 
    shape = list(sort.shape) 
    shape[axis] = 1 
    # Create a boolean array along strides of unique values 
    strides = numpy.concatenate([numpy.zeros(shape=shape, dtype='bool'), 
           numpy.diff(sort, axis=axis) == 0, 
           numpy.zeros(shape=shape, dtype='bool')], 
           axis=axis).transpose(transpose).ravel() 
    # Count the stride lengths 
    counts = numpy.cumsum(strides) 
    counts[~strides] = numpy.concatenate([[0], numpy.diff(counts[~strides])]) 
    counts[strides] = 0 
    # Get shape of padded counts and slice to return to the original shape 
    shape = numpy.array(sort.shape) 
    shape[axis] += 1 
    shape = shape[transpose] 
    slices = [slice(None)] * ndim 
    slices[axis] = slice(1, None) 
    # Reshape and compute final counts 
    counts = counts.reshape(shape).transpose(transpose)[slices] + 1 

    # Find maximum counts and return modals/counts 
    slices = [slice(None, i) for i in sort.shape] 
    del slices[axis] 
    index = numpy.ogrid[slices] 
    index.insert(axis, numpy.argmax(counts, axis=axis)) 
    return sort[index], counts[index] 

결과 :

In [2]: a = numpy.array([[1, 3, 4, 2, 2, 7], 
         [5, 2, 2, 1, 4, 1], 
         [3, 3, 2, 2, 1, 1]]) 

In [3]: mode(a) 
Out[3]: (array([1, 3, 2, 2, 1, 1]), array([1, 2, 2, 2, 1, 2])) 

일부 벤치 마크 :

In [4]: import scipy.stats 

In [5]: a = numpy.random.randint(1,10,(1000,1000)) 

In [6]: %timeit scipy.stats.mode(a) 
10 loops, best of 3: 41.6 ms per loop 

In [7]: %timeit mode(a) 
10 loops, best of 3: 46.7 ms per loop 

In [8]: a = numpy.random.randint(1,500,(1000,1000)) 

In [9]: %timeit scipy.stats.mode(a) 
1 loops, best of 3: 1.01 s per loop 

In [10]: %timeit mode(a) 
10 loops, best of 3: 80 ms per loop 

In [11]: a = numpy.random.random((200,200)) 

In [12]: %timeit scipy.stats.mode(a) 
1 loops, best of 3: 3.26 s per loop 

In [13]: %timeit mode(a) 
1000 loops, best of 3: 1.75 ms per loop 

편집 : 제공을 배경의 더 접근 방식을보다 메모리 효율적으로 변경했습니다.

3

this method으로 확장하면 appl 분포의 중심에서 얼마나 멀리 떨어져 있는지 확인하기 위해 실제 배열의 인덱스가 필요할 수있는 데이터 모드를 찾는 것입니다. 렌 때

(_, idx, counts) = np.unique(a, return_index=True, return_counts=True) 
index = idx[np.argmax(counts)] 
mode = a[index] 

그것은 당신이 당신의 표준 편차 안에 들어 있는지를 체크 할 수있다 실제로 데이터의 중앙 유통의 대표 인 경우도 검증하기 위해, 1> (np.argmax (카운트)) 모드를 폐기하는 것을 잊지 마십시오 간격.

관련 문제