用Python从零开始制作桶列表直方图

0 投票
1 回答
4207 浏览
提问于 2025-04-17 14:50

我正在做一个名为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 

这个代码让你可以选择一部分的数值,而不是整个范围。它通过添加一些特殊的“桶”来解决你的溢出问题,这些桶分别是负无穷大到最小值和最大值到正无穷大。我不知道这对你来说是否合适。

撰写回答