我正在尝试计算numpy数组中的唯一值。
import numpy as np
from collections import defaultdict
import scipy.stats
import time
x = np.tile([1,2,3,4,5,6,7,8,9,10],20000)
for i in [44,22,300,403,777,1009,800]:
x[i] = 11
def getCounts(x):
counts = defaultdict(int)
for item in x:
counts[item] += 1
return counts
flist = [getCounts, scipy.stats.itemfreq]
for f in flist:
print f
t1 = time.time()
y = f(x)
t2 = time.time()
print y
print '%.5f sec' % (t2-t1)
我一开始找不到内置函数,所以我写了getCounts()
;然后我找到了scipy.stats.itemfreq
,所以我想用它代替。但它很慢!这是我在电脑上得到的。与这么简单的手写功能相比,为什么这么慢?
<function getCounts at 0x0000000013C78438>
defaultdict(<type 'int'>, {1: 19998, 2: 20000, 3: 19999, 4: 19999, 5: 19999, 6: 20000, 7: 20000, 8: 19999, 9: 20000, 10: 19999, 11: 7})
0.04700 sec
<function itemfreq at 0x0000000013C5D208>
[[ 1.00000000e+00 1.99980000e+04]
[ 2.00000000e+00 2.00000000e+04]
[ 3.00000000e+00 1.99990000e+04]
[ 4.00000000e+00 1.99990000e+04]
[ 5.00000000e+00 1.99990000e+04]
[ 6.00000000e+00 2.00000000e+04]
[ 7.00000000e+00 2.00000000e+04]
[ 8.00000000e+00 1.99990000e+04]
[ 9.00000000e+00 2.00000000e+04]
[ 1.00000000e+01 1.99990000e+04]
[ 1.10000000e+01 7.00000000e+00]]
2.04100 sec
答案 0 :(得分:18)
如果您可以使用numpy 1.9,则可以将numpy.unique
与参数return_counts=True
一起使用。即。
unique_items, counts = np.unique(x, return_counts=True)
事实上,itemfreq
已更新为使用np.unique
,但scipy目前支持numpy版本回1.5,因此它不使用return_counts
参数。
以下是scipy 0.14中itemfreq
的完整实现:
def itemfreq(a):
items, inv = np.unique(a, return_inverse=True)
freq = np.bincount(inv)
return np.array([items, freq]).T
答案 1 :(得分:3)
首先,time.time
是在计时时使用的错误函数,因为它测量的是挂钟时间,而不是cpu时间(参见this question)。理想情况下,您可以使用timeit
模块,但time.clock
也更好。
此外,您似乎可能正在使用过时版本的scipy。我使用的是Python 3.4和scipy 0.14.0,这些是我的时间:
x = np.tile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 20000)
for i in [44, 22, 300, 403, 777, 1009, 800]:
x[i] = 11
%timeit getCounts(x)
# 10 loops, best of 3: 55.6 ms per loop
%timeit scipy.stats.itemfreq(x)
# 10 loops, best of 3: 20.8 ms per loop
%timeit collections.Counter(x)
# 10 loops, best of 3: 39.9 ms per loop
%timeit np.unique(x, return_counts=True)
# 100 loops, best of 3: 4.13 ms per loop
答案 2 :(得分:0)
感谢您的回复。我不能使用numpy 1.9或scipy 0.14,因为我的应用程序中存在一些模块冲突,但看起来新的scipy.stats.itemfreq要快得多:
import numpy as np
from collections import defaultdict, Counter
import scipy.stats
import time
import timeit
x = np.tile([1,2,3,4,5,6,7,8,9,10],20000)
for i in [44,22,300,403,777,1009,800]:
x[i] = 11
def getCounts(x):
counts = defaultdict(int)
for item in x:
counts[item] += 1
return counts
def itemfreq_scipy14(x):
'''this is how itemfreq works in 0.14:
https://github.com/scipy/scipy/commit/7e04d6630f229693cca3522b62aa16226f174053
'''
items, inv = np.unique(x, return_inverse=True)
freq = np.bincount(inv)
return np.array([items, freq]).T
flist = [getCounts, scipy.stats.itemfreq, np.bincount, itemfreq_scipy14, Counter]
for f in flist:
print f
print timeit.timeit(lambda: f(x),number=3)
在我的电脑上产生:
<function getCounts at 0x0000000013F8EB38>
0.148138969181
<function itemfreq at 0x0000000013C5D208>
6.15385023664
<built-in function bincount>
0.00313706656675
<function itemfreq_scipy14 at 0x0000000013F8EDD8>
0.0757223407165
<class 'collections.Counter'>
0.255281199559
答案 3 :(得分:0)
对于懒惰者:
import pandas as pd
pd.Series( my_list_or_array ).nunique()