Python numpy:数组中唯一值的最有效频率计数

Python numpy:数组中唯一值的最有效频率计数,python,arrays,performance,numpy,Python,Arrays,Performance,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()函数)像这样的东西应该可以: #create 100 random numbers arr = numpy.random.random_integer

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()
函数)

像这样的东西应该可以:

#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

另外,上一篇文章似乎与你的问题非常相似,除非我遗漏了什么。

看看
np.bincount

然后:

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


或者您希望如何组合计数和唯一值。

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 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]])

原始答复:

你可以用


这是迄今为止最普遍和最有效的解决方案;很惊讶它还没有发布

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完成的排序。

计算唯一的非整数-与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
Eelco的纯
numpy
版本:

> %timeit unique_count(data)
> 1000 loops, best of 3: 284 µs per loop
注意

这里有冗余(
unique
也执行排序),这意味着可以通过将
unique
功能放在c-code循环中进一步优化代码

使用熊猫模块:

>>> 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

老问题,但我想提供我自己的最快解决方案,根据我的台架测试,使用普通的
列表
而不是
np.array
作为输入(或首先转移到列表)

如果您也遇到它,请查看它

def count(a):
    results = {}
    for x in a:
        if x not in results:
            results[x] = 1
        else:
            results[x] += 1
    return results
比如说,

100000个回路,最佳3个:每个回路2.26µs

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]))
>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]).tolist())
100000个回路,最好为3个:每个回路8.8µs

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]))
>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]).tolist())
100000个回路,最好为3个:每个回路5.85µs

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]))
>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]).tolist())
而被接受的答案会更慢,
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 1.9开始,最简单和最快的方法是简单使用,现在它有一个
返回计数
关键字参数:

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

我对此也很感兴趣,所以我做了一些性能比较(使用,我的一个宠物项目)。结果:

y=np.bincount(a)
ii=np.非零(y)[0]
out=np.vstack((ii,y[ii]).T
是目前为止最快的。(请注意日志缩放。)


生成绘图的代码:

将numpy导入为np
作为pd进口熊猫
导入性能图
从scipy.stats导入itemfreq
def bincount(a):
y=np.bincount(a)
ii=np.非零(y)[0]
返回np.vstack((ii,y[ii]).T
def唯一(a):
unique,counts=np.unique(a,return\u counts=True)
返回np.asarray((唯一,计数)).T
def唯一_计数(a):
unique,inverse=np.unique(a,返回值_inverse=True)
count=np.zero(len(唯一),dtype=int)
np.add.at(计数,倒数,1)
返回np.vstack((唯一,计数)).T
定义值计数(a):
out=局部放电值\计数(局部放电系列(a))
out.sort\u索引(inplace=True)
out=np.stack([out.keys().values,out.values]).T
返回
perfplot.show(
setup=lambda n:np.random.randint(0,1000,n),
内核=[bincount,unique,itemfreq,unique\u count,pandas\u value\u counts],
n_范围=[2**k表示范围(26)中的k],
xlabel=“len(a)”,
)
这将为您提供: {1:5,2:3,5:1,25:1}

将熊猫作为pd导入
将numpy作为np导入
打印(pd.Series(数组的名称)。值计数()

多维频率计数,即计数阵列

>>> 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,  
从集合导入计数器
x=数组([1,1,1,2,2,5,25,1,1])
模式=计数器。最常见(1)[0][0]

大多数简单的问题变得复杂,因为在各种python库中缺少简单的功能,如R中的order(),它以降序和降序给出统计结果。但是,如果我们设想python中的所有这些统计顺序和参数都很容易在熊猫身上找到,那么我们可以比在100个不同的地方寻找更快的结果。此外,R和熊猫的发展是齐头并进的,因为它们是为同样的目的而创造的。为了解决这个问题,我使用了以下代码:

unique, counts = np.unique(x, return_counts=True)
d = {'unique':unique, 'counts':count}  # pass the list to a dictionary
df = pd.DataFrame(d) #dictionary object can be easily passed to make a dataframe
df.sort_values(by = 'count', ascending=False, inplace = True)
df = df.reset_index(drop=True) #optional only if you want to use it further

链接的问题有点类似,但看起来他在处理更复杂的数据类型。嗨,如果x元素的数据类型不是int,这就不起作用。如果它们不是非负int,这就不起作用,如果int被隔开,空间效率会非常低。对于numpy版本1.10,我发现,对于整数计数,它比np.unique快6倍左右。另外,请注意,如果给出正确的参数,它也会计算负整数。@Manoj:My元素x是数组。我正在测试jme的解决方案。不起作用:
AttributeError:
>>> 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,  
unique, counts = np.unique(x, return_counts=True)
d = {'unique':unique, 'counts':count}  # pass the list to a dictionary
df = pd.DataFrame(d) #dictionary object can be easily passed to make a dataframe
df.sort_values(by = 'count', ascending=False, inplace = True)
df = df.reset_index(drop=True) #optional only if you want to use it further