【问题标题】:assigning points to bins将点分配给 bin
【发布时间】:2011-01-09 19:24:27
【问题描述】:

将数值分箱到一定范围内的好方法是什么?例如,假设我有一个值列表,我想按它们的范围将它们放入 N 个 bin 中。现在,我做这样的事情:

from scipy import *
num_bins = 3 # number of bins to use
values = # some array of integers...
min_val = min(values) - 1
max_val = max(values) + 1
my_bins = linspace(min_val, max_val, num_bins)
# assign point to my bins
for v in values:
  best_bin = min_index(abs(my_bins - v))

其中 min_index 返回最小值的索引。这个想法是,您可以通过查看它与哪个 bin 的差异最小来找到该点所在的 bin。

但我认为这有奇怪的边缘情况。我正在寻找的是一个很好的垃圾箱表示,理想情况下是半封闭半开的垃圾箱(这样就无法将一个点分配给两个垃圾箱),即

bin1 = [x1, x2)
bin2 = [x2, x3)
bin3 = [x3, x4)
etc...

使用 numpy/scipy 在 Python 中执行此操作的好方法是什么?我在这里只关心对整数值进行分箱。

非常感谢您的帮助。

【问题讨论】:

  • 附带说明:如果 matplotlib 具有此功能,除了 scipy/numpy 之外,我更愿意使用它。我猜像'hist'这样的函数必须做这样的事情,除了这里我不是在寻找任何绘图。

标签: python numpy scipy binning


【解决方案1】:

numpy.histogram() 完全符合您的要求。

函数签名是:

numpy.histogram(a, bins=10, range=None, normed=False, weights=None, new=None)

我们最感兴趣的是abinsa 是需要分箱的输入数据。 bins 可以是多个 bin(您的 num_bins),也可以是一系列标量,表示 bin 边缘(半开)。

import numpy
values = numpy.arange(10, dtype=int)
bins = numpy.arange(-1, 11)
freq, bins = numpy.histogram(values, bins)
# freq is now [0 1 1 1 1 1 1 1 1 1 1]
# bins is unchanged

引用documentation

除了最后一个(最右边的)垃圾箱外,所有垃圾箱都是半开的。换句话说,如果bins 是:

[1, 2, 3, 4]

那么第一个bin是[1, 2)(包括1,但不包括2),第二个是[2, 3)。然而,最后一个 bin 是 [3, 4]包括 4.

编辑:您想知道每个元素在您的 bin 中的索引。为此,您可以使用numpy.digitize()。如果你的垃圾箱是完整的,你也可以使用numpy.bincount()

>>> values = numpy.random.randint(0, 20, 10)
>>> values
array([17, 14,  9,  7,  6,  9, 19,  4,  2, 19])
>>> bins = numpy.linspace(-1, 21, 23)
>>> bins
array([ -1.,   0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,
        10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.,
        21.])
>>> pos = numpy.digitize(values, bins)
>>> pos
array([19, 16, 11,  9,  8, 11, 21,  6,  4, 21])

由于区间在上限上打开,因此指数是正确的:

>>> (bins[pos-1] == values).all()
True
>>> import sys
>>> for n in range(len(values)):
...     sys.stdout.write("%g <= %g < %g\n"
...             %(bins[pos[n]-1], values[n], bins[pos[n]]))
17 <= 17 < 18
14 <= 14 < 15
9 <= 9 < 10
7 <= 7 < 8
6 <= 6 < 7
9 <= 9 < 10
19 <= 19 < 20
4 <= 4 < 5
2 <= 2 < 3
19 <= 19 < 20

【讨论】:

  • 感谢您的回答——但我认为直方图仍然与我想要的不同。我对任何垃圾箱的频率不感兴趣,我只想知道每个点属于哪个垃圾箱。直方图似乎没有返回该信息,对吧?
  • 哦,那你应该看看numpy.digitize()
【解决方案2】:

这在使用广播的 numpy 中相当简单——我下面的示例是四行代码(不计算创建 bin 和数据点的前两行,这当然是通常会提供的。)

import numpy as NP
# just creating 5 bins at random, each bin expressed as (x, y, z) although, this code
# is not limited by bin number or bin dimension
bins = NP.random.random_integers(10, 99, 15).reshape(5, 3) 
# creating 30 random data points
data = NP.random.random_integers(10, 99, 90).reshape(30, 3)
# for each data point i want the nearest bin, but before i can generate a distance
# matrix, i need to 'conform' the array dimensions
# 'broadcasting' is an excellent and concise way to do this
bins = bins[:, NP.newaxis, :]
data2 = data[NP.newaxis, :, :]
# now i can calculate the distance matrix
dist_matrix = NP.sqrt(NP.sum((data - bins)**2, axis=-1)) 
bin_assignments = NP.argmin(dist_matrix, axis=0)

'bin_assignments' 是一维索引数组,由 0 到 4 的整数值组成,对应于五个 bin - 上述“数据”矩阵中 30 个原始点中的每一个的 bin 分配。

【讨论】:

  • 这个答案我不是很懂,你能解释的更好吗?
猜你喜欢
  • 2015-10-11
  • 2019-10-04
  • 1970-01-01
  • 2019-03-07
  • 2020-01-31
  • 2015-03-22
  • 2021-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多