[python] numpy : 배열에서 고유 한 값에 대한 가장 효율적인 빈도 수

numpy / scipy,가 효율적으로 배열에서 고유 값에 대한 주파수 카운트를 얻을 수있는 방법은?

이 라인을 따라 뭔가 :

x = array( [1,1,1,2,2,2,5,25,1,1] )
y = freq_count( x )
print y

>> [[1, 5], [2,3], [5,1], [25,1]]

(당신을 위해, R 사용자는 기본적으로 table() 함수를 있습니다)



답변

살펴보십시오 np.bincount:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html

import numpy as np
x = np.array([1,1,1,2,2,2,5,25,1,1])
y = np.bincount(x)
ii = np.nonzero(y)[0]

그리고:

zip(ii,y[ii])
# [(1, 5), (2, 3), (5, 1), (25, 1)]

또는:

np.vstack((ii,y[ii])).T
# array([[ 1,  5],
         [ 2,  3],
         [ 5,  1],
         [25,  1]])

또는 카운트와 고유 값을 결합하려고합니다.


답변

Numpy 1.9부터 가장 쉽고 빠른 방법은 단순히 키워드 인수를 numpy.unique갖는을 사용하는 것입니다 return_counts.

import numpy as np

x = np.array([1,1,1,2,2,2,5,25,1,1])
unique, counts = np.unique(x, return_counts=True)

print np.asarray((unique, counts)).T

다음을 제공합니다.

 [[ 1  5]
  [ 2  3]
  [ 5  1]
  [25  1]]

다음과의 빠른 비교 scipy.stats.itemfreq:

In [4]: x = np.random.random_integers(0,100,1e6)

In [5]: %timeit unique, counts = np.unique(x, return_counts=True)
10 loops, best of 3: 31.5 ms per loop

In [6]: %timeit scipy.stats.itemfreq(x)
10 loops, best of 3: 170 ms per loop


답변

업데이트 : 원래 답변에 언급 된 방법은 더 이상 사용되지 않으므로 대신 새로운 방법을 사용해야합니다.

>>> import numpy as np
>>> x = [1,1,1,2,2,2,5,25,1,1]
>>> np.array(np.unique(x, return_counts=True)).T
    array([[ 1,  5],
           [ 2,  3],
           [ 5,  1],
           [25,  1]])

원래 답변 :

scipy.stats.itemfreq 를 사용할 수 있습니다

>>> from scipy.stats import itemfreq
>>> x = [1,1,1,2,2,2,5,25,1,1]
>>> itemfreq(x)
/usr/local/bin/python:1: DeprecationWarning: `itemfreq` is deprecated! `itemfreq` is deprecated and will be removed in a future version. Use instead `np.unique(..., return_counts=True)`
array([[  1.,   5.],
       [  2.,   3.],
       [  5.,   1.],
       [ 25.,   1.]])


답변

나는 이것에 관심이 있었기 때문에 약간의 성능 비교 ( perfplot , 내 애완 동물 프로젝트 사용 )를 수행했습니다. 결과:

y = np.bincount(a)
ii = np.nonzero(y)[0]
out = np.vstack((ii, y[ii])).T

훨씬 빠릅니다. (로그 스케일링에 유의하십시오.)

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


플롯을 생성하는 코드 :

import numpy as np
import pandas as pd
import perfplot
from scipy.stats import itemfreq


def bincount(a):
    y = np.bincount(a)
    ii = np.nonzero(y)[0]
    return np.vstack((ii, y[ii])).T


def unique(a):
    unique, counts = np.unique(a, return_counts=True)
    return np.asarray((unique, counts)).T


def unique_count(a):
    unique, inverse = np.unique(a, return_inverse=True)
    count = np.zeros(len(unique), np.int)
    np.add.at(count, inverse, 1)
    return np.vstack((unique, count)).T


def pandas_value_counts(a):
    out = pd.value_counts(pd.Series(a))
    out.sort_index(inplace=True)
    out = np.stack([out.keys().values, out.values]).T
    return out


perfplot.show(
    setup=lambda n: np.random.randint(0, 1000, n),
    kernels=[bincount, unique, itemfreq, unique_count, pandas_value_counts],
    n_range=[2 ** k for k in range(26)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)


답변

팬더 모듈 사용 :

>>> import pandas as pd
>>> import numpy as np
>>> x = np.array([1,1,1,2,2,2,5,25,1,1])
>>> pd.value_counts(x)
1     5
2     3
25    1
5     1
dtype: int64


답변

이것은 가장 일반적이고 성능이 뛰어난 솔루션입니다. 아직 게시되지 않았습니다.

import numpy as np

def unique_count(a):
    unique, inverse = np.unique(a, return_inverse=True)
    count = np.zeros(len(unique), np.int)
    np.add.at(count, inverse, 1)
    return np.vstack(( unique, count)).T

print unique_count(np.random.randint(-10,10,100))

현재 허용되는 답변과 달리 긍정적 인 정수뿐만 아니라 정렬 가능한 모든 데이터 유형에서 작동하며 최적의 성능을 제공합니다. 유일한 중요한 비용은 np.unique에 의한 정렬에 있습니다.


답변

numpy.bincount아마도 최선의 선택 일 것입니다. 배열에 작은 고밀도 정수 이외의 것이 포함되어 있으면 다음과 같이 감싸는 것이 유용 할 수 있습니다.

def count_unique(keys):
    uniq_keys = np.unique(keys)
    bins = uniq_keys.searchsorted(keys)
    return uniq_keys, np.bincount(bins)

예를 들면 다음과 같습니다.

>>> x = array([1,1,1,2,2,2,5,25,1,1])
>>> count_unique(x)
(array([ 1,  2,  5, 25]), array([5, 3, 1, 1]))