に 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()
。エラーを引き起こしていたのはpd.value_counts
(Python 2で)(sort = Falseを使用した場合でも)です。
pandasモジュールの使用:
>>> 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
ます。シーケンスが指定されたこのような関数は、ビンにグループ化された要素の頻度を返します。
ただし注意してください:数値は整数であるため、この例では機能します。それらが実数の場合、このソリューションはうまく適用されません。
>>> 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の因数)である一意の非整数をカウントするために、以前は少しのcコードweave.inline
と組み合わせnumpy.unique
ていました。
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:ループあたり8.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)
十分?