用Python从零开始制作桶列表直方图
我正在做一个名为Think Python的项目,其中有一个练习,要求你写一个函数,完成以下任务:
- 接收两个参数:
L
(一个数字列表)和n
(一个整数) - 返回一个直方图,形式是一个包含
n
个子列表的列表- 每个子列表代表数字
L
所覆盖范围的一个小区间,并包含一个整数,表示有多少个L
中的元素落在这个小区间内
- 每个子列表代表数字
所以我们要看一组数字,把这个范围分成n
个相等的区间,然后用这些区间来构建一个直方图。在这个练习之前的部分展示了如何处理在[0.0, 1.0)区间内的随机浮点数列表,方法是查看一个元素在这个区间中的位置(也就是它的值),然后把这个值乘以n
,并转换成整数(在这个过程中会截断)。这样就得到了一个在[0, n)范围内的整数,作为合适的区间索引。
这里的不同之处在于,我们不是在一个预先设定的(而且方便的)区间内工作。我计算我的区间为max(L) - min(L)
,但还需要加一点额外的值,否则L
中的最大元素会得到一个索引为n(这超出了范围),而它应该得到的是n - 1。我把这个额外的值叫做extraBit
。
def histogram(L, n):
hist = [0] * numBuckets
minVal = min(L)
maxVal = max(L)
extraBit = .0000000000001
interval = (maxVal - minVal) + extraBit
for i in L:
placement = (i - minVal) / interval
index = int(placement * numBuckets)
hist[index] = hist[index] + 1
return hist
有没有更优雅的方法来实现这个呢?
1 个回答
2
我上周写了自己的代码:
def frequency_count(itt, nr_bins, minn=None, maxx=None):
ret = []
if minn == None:
minn = min(itt)
if maxx == None:
maxx = max(itt)
binsize = (maxx - minn) / float(nr_bins) #man, do I hate int division
#construct bins
ret.append([float("-infinity"), minn, 0]) #-inf -> min
for x in range(0, nr_bins):
start = minn + x * binsize
ret.append([start, start+binsize, 0])
ret.append([maxx, float("infinity"), 0]) #maxx -> inf
#assign items to bin
for item in itt:
for binn in ret:
if binn[0] <= item < binn[1]:
binn[2] += 1
return ret
这个代码让你可以选择一部分的数值,而不是整个范围。它通过添加一些特殊的“桶”来解决你的溢出问题,这些桶分别是负无穷大到最小值和最大值到正无穷大。我不知道这对你来说是否合适。