【问题标题】:fast categorization (binning)快速分类(分箱)
【发布时间】:2012-05-28 01:08:48
【问题描述】:

我有大量的条目,每一个都是浮点数。这些数据x 可以通过迭代器访问。我需要使用10<y<=2020<y<=50、...之类的选择对所有条目进行分类,其中y 是来自其他可迭代对象的数据。条目的数量远远超过选择的数量。最后我想要一个字典,比如:

{ 0: [all events with 10<x<=20],
  1: [all events with 20<x<=50], ... }

或类似的东西。比如我在做:

for x, y in itertools.izip(variable_values, binning_values):
    thebin = binner_function(y)
    self.data[tuple(thebin)].append(x)

一般y 是多维的。

这很慢,是否有更快的解决方案,例如使用 numpy?我认为问题来自我正在使用的list.append 方法,而不是来自binner_function

【问题讨论】:

  • 你看过numpy.histogram()吗? docs.scipy.org/doc/numpy/reference/generated/…
  • binner_function 必须是通用的吗?如果您发布了它的实现,我们也许可以编写一个更有效的版本,可能带有 dict/list 理解。
  • numpy.histogram 不好:它只返回每个类别的计数

标签: python optimization numpy binning


【解决方案1】:

np.searchsorted 是你的朋友。正如我在同一主题的另一个答案中读到的,目前它比数字化要快一点,并且做同样的工作。

http://docs.scipy.org/doc/numpy/reference/generated/numpy.searchsorted.html

【讨论】:

    【解决方案2】:

    在 numpy 中获取分配的快速方法是使用 np.digitize:

    http://docs.scipy.org/doc/numpy/reference/generated/numpy.digitize.html

    您仍然需要将生成的作业分成几组。如果xy 是多维的,则必须先展平数组。然后,您可以获得唯一的 bin 分配,然后与 np.where 一起迭代这些分配以将分配分成组。如果 bin 的数量远小于需要 bin 的元素数量,这可能会更快。

    作为一个微不足道的示例,您需要针对您的特定问题进行调整/详细说明(但希望足以让您开始使用 numpy 解决方案):

    In [1]: import numpy as np
    
    In [2]: x = np.random.normal(size=(50,))
    
    In [3]: b = np.linspace(-20,20,50)
    
    In [4]: assign = np.digitize(x,b)
    
    In [5]: assign
    Out[5]: 
    array([23, 25, 25, 25, 24, 26, 24, 26, 23, 24, 25, 23, 26, 25, 27, 25, 25,
           25, 25, 26, 26, 25, 25, 26, 24, 23, 25, 26, 26, 24, 24, 26, 27, 24,
           25, 24, 23, 23, 26, 25, 24, 25, 25, 27, 26, 25, 27, 26, 26, 24])
    
    In [6]: uid = np.unique(assign)
    
    In [7]: adict = {}
    
    In [8]: for ii in uid:
       ...:     adict[ii] = np.where(assign == ii)[0]
       ...:     
    
    In [9]: adict
    Out[9]: 
    {23: array([ 0,  8, 11, 25, 36, 37]),
     24: array([ 4,  6,  9, 24, 29, 30, 33, 35, 40, 49]),
     25: array([ 1,  2,  3, 10, 13, 15, 16, 17, 18, 21, 22, 26, 34, 39, 41, 42, 45]),
     26: array([ 5,  7, 12, 19, 20, 23, 27, 28, 31, 38, 44, 47, 48]),
     27: array([14, 32, 43, 46])}
    

    关于处理扁平化然后取消扁平化 numpy 数组,请参阅: http://docs.scipy.org/doc/numpy/reference/generated/numpy.unravel_index.html

    http://docs.scipy.org/doc/numpy/reference/generated/numpy.ravel_multi_index.html

    【讨论】:

    • 在我的代码中,我只循环了一次数据。在您的代码中,您在第 4 行有一个循环,在第 8 行有一个随机访问。另外请记住 x 是一个迭代器而不是 np.array
    • @wiso,但是在 python 中循环与在 numpy 方法内部循环之间存在很大差异,该方法对 c 中的数据进行循环。此外,您可以使用 np.fromiter 从迭代器创建数组。将您的方法与我发布的某个版本的时间进行比较,然后自己看看哪个更快。我只是提供一个建议
    • 顺便说一句,在最终字典中,我想要 x 值,而不是索引
    • @wiso,无意冒犯,但您不应该期望为您提供完整的解决方案。使用索引来提取值是非常简单的。我正在为您提供一个框架来考虑一个 numpy 解决方案。您需要做一些工作。 . .
    • 你的速度是对的,关键是我正在做多维分箱,所以总箱数可以是~100,项目数~1E6
    猜你喜欢
    • 2011-12-31
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多