에 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()
함수를 있습니다)
에 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)",
)
equality_check=array_sorteq
을 추가하여 코드를 실행할 수있었습니다 perfplot.show()
. 오류를 발생시킨 원인은 (파이썬 2에서) pd.value_counts
(정렬 = 거짓으로도)였습니다.
팬더 모듈 사용 :
>>> 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에 의한 정렬에 있습니다.
AttributeError: 'numpy.ufunc' object has no attribute 'at'
np.bincount(inverse)
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]))
이미 답변을 받았지만을 사용하는 다른 접근법을 제안합니다 numpy.histogram
. 이러한 함수는 시퀀스가 주어지면 bin으로 그룹화 된 요소의 빈도를 반환합니다 .
그럼에도 불구하고 : 숫자가 정수이기 때문에이 예제에서 작동합니다. 그들이 실제 숫자라면,이 솔루션은 멋지게 적용되지 않을 것입니다.
>>> from numpy import histogram
>>> y = histogram (x, bins=x.max()-1)
>>> y
(array([5, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1]),
array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.,
12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22.,
23., 24., 25.]))
import pandas as pd
import numpy as np
x = np.array( [1,1,1,2,2,2,5,25,1,1] )
print(dict(pd.Series(x).value_counts()))
{1 : 5, 2 : 3, 5 : 1, 25 : 1}
collections.Counter(x)
또한 동일한 결과를 제공합니다. OP가 R table
함수 와 유사한 출력을 원한다고 생각합니다 . 유지하는 Series
것이 더 유용 할 수 있습니다.
pd.Series(x).reshape(-1)
다차원 배열 인 경우 전송해야 합니다.
Eelco Hoogendoorn의 답변과 비슷하지만 상당히 빠른 (내 컴퓨터의 5 요소) 고유 한 비 정수 를 계산 weave.inline
하기 위해 numpy.unique
약간의 c 코드와 결합 했습니다.
import numpy as np
from scipy import weave
def count_unique(datain):
"""
Similar to numpy.unique function for returning unique members of
data, but also returns their counts
"""
data = np.sort(datain)
uniq = np.unique(data)
nums = np.zeros(uniq.shape, dtype='int')
code="""
int i,count,j;
j=0;
count=0;
for(i=1; i<Ndata[0]; i++){
count++;
if(data(i) > data(i-1)){
nums(j) = count;
count = 0;
j++;
}
}
// Handle last value
nums(j) = count+1;
"""
weave.inline(code,
['data', 'nums'],
extra_compile_args=['-O2'],
type_converters=weave.converters.blitz)
return uniq, nums
프로필 정보
> %timeit count_unique(data)
> 10000 loops, best of 3: 55.1 µs per loop
Eelco의 순수한 numpy
버전 :
> %timeit unique_count(data)
> 1000 loops, best of 3: 284 µs per loop
노트
여기에 중복성이 있습니다 ( unique
정렬도 수행 함) unique
.c 코드 루프 안에 기능 을 넣어 코드를 더 최적화 할 수 있음을 의미합니다 .
오래된 질문이지만 벤치 테스트를 기반으로 가장 빠른 것으로 내 자신의 솔루션을 제공하고 싶습니다. 입력 list
대신 표준으로 사용하십시오 np.array
(또는 먼저 목록으로 전송).
당신도 그것을 발견하면 그것을 확인하십시오 .
def count(a):
results = {}
for x in a:
if x not in results:
results[x] = 1
else:
results[x] += 1
return results
예를 들어
>>>timeit count([1,1,1,2,2,2,5,25,1,1]) would return:
100000 루프, 루프 당 최고 3 : 2.26 µs
>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]))
100000 루프, 루프 당 3 : 3.8 µs 최고
>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]).tolist())
100000 루프, 루프 당 최고 3 : 5.85 µs
허용 된 답변은 느려질 수 있으며 scipy.stats.itemfreq
솔루션은 훨씬 나쁩니다.
보다 심도있는 테스트는 공식화 된 기대치를 확인하지 못했습니다 .
from zmq import Stopwatch
aZmqSTOPWATCH = Stopwatch()
aDataSETasARRAY = ( 100 * abs( np.random.randn( 150000 ) ) ).astype( np.int )
aDataSETasLIST = aDataSETasARRAY.tolist()
import numba
@numba.jit
def numba_bincount( anObject ):
np.bincount( anObject )
return
aZmqSTOPWATCH.start();np.bincount( aDataSETasARRAY );aZmqSTOPWATCH.stop()
14328L
aZmqSTOPWATCH.start();numba_bincount( aDataSETasARRAY );aZmqSTOPWATCH.stop()
592L
aZmqSTOPWATCH.start();count( aDataSETasLIST );aZmqSTOPWATCH.stop()
148609L
참조 작은 데이터 세트에 영향을 미치는 캐시 및 기타 RAM 내 부작용에 대한 아래의 의견은 대규모 반복 테스트 결과입니다.
numpy
반드시 갈 길은 아니기 때문에 정말 좋습니다 .
이와 같은 일이해야합니다.
#create 100 random numbers
arr = numpy.random.random_integers(0,50,100)
#create a dictionary of the unique values
d = dict([(i,0) for i in numpy.unique(arr)])
for number in arr:
d[j]+=1 #increment when that value is found
또한 독특한 요소 를 효율적으로 계산하는 이전 게시물은 내가 빠진 것이 아니라면 귀하의 질문과 매우 유사합니다.
다차원 주파수 카운트, 즉 카운트 어레이.
>>> print(color_array )
array([[255, 128, 128],
[255, 128, 128],
[255, 128, 128],
...,
[255, 128, 128],
[255, 128, 128],
[255, 128, 128]], dtype=uint8)
>>> np.unique(color_array,return_counts=True,axis=0)
(array([[ 60, 151, 161],
[ 60, 155, 162],
[ 60, 159, 163],
[ 61, 143, 162],
[ 61, 147, 162],
[ 61, 162, 163],
[ 62, 166, 164],
[ 63, 137, 162],
[ 63, 169, 164],
array([ 1, 2, 2, 1, 4, 1, 1, 2,
3, 1, 1, 1, 2, 5, 2, 2,
898, 1, 1,
collections.Counter(x)
충분?