307

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

4

16 回答 16

644

从 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
于 2014-09-19T22:54:29.887 回答
192

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

或者您想结合计数和唯一值。

于 2012-05-24T16:35:46.820 回答
150

更新:原始答案中提到的方法已弃用,我们应该改用新方法:

>>> 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.]])
于 2013-08-13T05:41:20.767 回答
63

我也对此感兴趣,所以我做了一些性能比较(使用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), dtype=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


b = perfplot.bench(
    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)],
    xlabel="len(a)",
)
b.save("out.png")
b.show()
于 2017-03-29T14:30:52.380 回答
41

使用熊猫模块:

>>> 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
于 2014-07-30T10:25:22.230 回答
19

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

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

于 2014-01-14T21:53:12.583 回答
15

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]))
于 2012-05-24T17:22:05.143 回答
8

即使已经回答了,我还是建议使用不同的方法来使用numpy.histogram. 这样的函数给定一个序列,它返回其元素在 bins 中分组的频率。

但请注意:它在此示例中有效,因为数字是整数。如果他们是实数,那么这个解决方案就不会很好地适用。

>>> 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.]))
于 2012-11-05T12:22:22.287 回答
5

老问题,但我想根据我的基准测试提供我自己的解决方案,结果证明是最快的,使用普通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

参考。下面评论缓存和其他影响小数据集大量重复测试结果的内存中副作用。

于 2014-08-19T06:50:47.687 回答
5
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}

于 2017-05-18T07:56:45.687 回答
4

要计算唯一的非整数- 类似于 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 代码循环中来进一步优化代码。

于 2014-04-28T14:59:45.637 回答
2
import pandas as pd
import numpy as np

print(pd.Series(name_of_array).value_counts())
于 2018-05-31T04:48:13.743 回答
2

多维频率计数,即计数数组。

>>> 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,  
于 2019-06-12T10:30:22.367 回答
1
from collections import Counter
x = array( [1,1,1,2,2,2,5,25,1,1] )
mode = counter.most_common(1)[0][0]
于 2020-03-02T16:16:27.890 回答
1

大多数简单的问题变得复杂,因为在各种 python 库中都缺少像 R 中的 order() 这样的简单功能,它可以同时给出统计结果和降序。但是,如果我们设想一下,python 中的所有这些统计排序和参数都可以在 pandas 中轻松找到,我们可以比查看 100 个不同的地方更快地得出结果。此外,R 和 pandas 的开发齐头并进,因为它们的创建目的相同。为了解决这个问题,我使用下面的代码让我在任何地方都能找到:

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
于 2020-08-26T08:14:26.173 回答
0

像这样的事情应该这样做:

#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

此外, 除非我遗漏了什么,否则之前关于有效计算独特元素的帖子似乎与您的问题非常相似。

于 2012-05-24T16:32:11.543 回答