【问题标题】:vectorized approach to binning with numpy/scipy in Python在 Python 中使用 numpy/scipy 进行分箱的矢量化方法
【发布时间】:2011-02-14 20:13:43
【问题描述】:

我正在使用 np.digitize 将 Python 中的二维数组(x x y)分箱到其 x 值的箱中(在“箱”中给出):

elements_to_bins = digitize(vals, bins)

其中“vals”是一个二维数组,即:

 vals = array([[1, v1], [2, v2], ...]). 

elements_to_bins 只是说明每个元素属于哪个 bin。然后我想要做的是获取一个列表,其长度是“bins”中的 bin 数量,并且每个元素返回落入该 bin 的“vals”的 y 维度。我现在就是这样做的:

points_by_bins = []
for curr_bin in range(min(elements_to_bins), max(elements_to_bins) + 1):
    curr_indx = where(elements_to_bins == curr_bin)[0]
    curr_bin_vals = vals[:, curr_indx]
    points_by_bins.append(curr_bin_vals)

有没有更优雅/更简单的方法来做到这一点?我所需要的只是落入每个 bin 的 y 值列表的列表。

谢谢。

【问题讨论】:

  • 如果其中一个答案解决了您的问题,请将其标记为已接受(绿色复选标记)! :)

标签: python arrays numpy scipy


【解决方案1】:

如果我正确理解您的问题:

vals = array([[1, 10], [1, 11], [2, 20], [2, 21], [2, 22]])  # Example

(x, y) = vals.T  # Shortcut
bin_limits = range(min(x)+1, max(x)+2)  # Other limits could be chosen
points_by_bin = [ [] for _ in bin_limits ]  # Final result
for (bin_num, y_value) in zip(searchsorted(bin_limits, x, "right"), y):  # digitize() finds the correct bin number
    points_by_bin[bin_num].append(y_value)

print points_by_bin  # [[10, 11], [20, 21, 22]]

Numpy 的快速数组操作searchsorted() 用于最大效率。然后将值一一相加(因为最终结果不是矩形数组,Numpy 对此无能为力)。此解决方案应该比循环中的多个where() 调用更快,后者会强制 Numpy 多次重新读取 same 数组。

【讨论】:

  • numpy.searchsorted 出于性能原因应该首选数字化:github.com/numpy/numpy/issues/2656
  • @Alleo:非常好的观点(对于digitize() 的当前实现)。我更新了答案。
【解决方案2】:

这将返回一个类似于 IDL HISTOGRAM 的 Reverse_Indices 的数据结构:

ovec = np.argsort(vals)
ivec = np.searchsorted(vals, bin_limits, sorter=ovec)

那么落入bin#i的元素列表就是

ovec[ ivec[i] : ivec[i+1] ]

(我的快速计时测试表明这比 EOL 的算法快 5 倍,因为它不需要创建不同大小的列表)

【讨论】:

    【解决方案3】:

    bin 键是否只是整数,没有 binning,就像你的例子一样?然后你可以这样做,没有 numpy:

    from collections import defaultdict
    bins = defaultdict(list)  # or [ [] ...] as in EOL
    
    vals = [[1, 10], [1, 11], [2, 20], [2, 21], [2, 22]]  # nparray.tolist()
    for nbin, val in vals:
        bins[nbin].append(val)
    
    print "bins:", bins
    # defaultdict(<type 'list'>, {1: [10, 11], 2: [20, 21, 22]})
    

    【讨论】:

    • +1:这对我来说看起来不错,除了空箱不包含空列表(可以用 defaultdict 修复)这一事实。但是,也许原始海报有更通用的垃圾箱?
    猜你喜欢
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    • 2011-02-09
    • 2023-03-10
    • 2011-10-16
    • 1970-01-01
    相关资源
    最近更新 更多