【问题标题】:How to count how many data points fall in a bin如何计算一个 bin 中有多少数据点
【发布时间】:2014-07-23 18:48:18
【问题描述】:

我已经设置了我的 bin 的参数,我想找到当数据点落在特定 bin 的范围内时如何向 bin 添加一个,基本上计算每个 bin 范围内有多少数据点,这样当我绘制它时,我可以将其用作“频率”。

我的垃圾箱范围由以下人员设置:

 bins = [(i*bin_width, (i+1)*bin_width) for i in range(num_bins)]

我的数据看起来像:

2.55619101399
2.55619101399
2.55619101399
3.615
4.42745271008
2.55619101399
2.55619101399
2.55619101399
4.42745271008
3.615
2.55619101399
4.42745271008
5.71581687075
5.71581687075
3.615
2.55619101399
2.55619101399
2.55619101399
2.55619101399
2.55619101399

【问题讨论】:

  • 听起来你在问如何做直方图,或者我错过了什么?查找“直方图”...
  • 不,我了解如何制作直方图,但这会自动计算 bin 中的频率吗?
  • 我想我真的不明白你在问什么......“垃圾箱中的点数”正是直方图给你的。 “频率”是什么意思?
  • 但直方图会绘制它,我不想绘制每个 bin 的数据点数,我想在绘制之前操纵该数据,这就是为什么我希望能够拥有一个每个垃圾箱中的计数器。
  • @Wana_B3_Nerd:我很确定 Ajean 建议的是 NumPy.histogram,而不是 matplotlib.histogram

标签: python sorting bin


【解决方案1】:

由于您使用的是 NumPy,您 (a) 不应该尝试创建列表并循环它们而不是使用数组,并且 (b) 应该查看您想要做的事情是否已经内置(或在 SciPy 或 Pandas 或其他基于 NumPy 构建的库中可用),因为通常是这样。

numpy.histogram 正是您想要的。

它需要一个总宽度而不是一个 bin 宽度,但除此之外,插入你已经拥有的值并取回你想要的值是微不足道的:

hist, edges = np.histogram(
    data_points,
    bins=num_bins,
    range=(0, bin_width*num_bins),
    density=False)

hist 数组将包含每个 bin 的计数(就像我的另一个答案中的 bin_counts),这是您想要后处理并最终绘制图表的内容。

edges,您可能需要也可能不需要。它与原始问题中的bins 信息相同,但格式不同——而不是[(0, .1), (.1, .2), (.2, .3)],而是[0, .1, .2, .3]

【讨论】:

    【解决方案2】:

    嗯,首先,您的每个 bins 只是该 bin 的开始值和结束值的元组,因此无法向其中添加任何内容。您可以将每个bin 更改为[start, stop, 0] 的列表,而不是(start, stop) 的元组,或者甚至更好的是一个对象。或者,您也可以保留一个单独的 bin_counts 列表,与 bins 列表平行,并在需要时将它们添加到 zip 上。

    接下来,如果每个 bin 从i * bin_width(i+1) * bin_width,那么如何从数据值中获取i 值?这很简单:乘法的反义词是除法,所以它只是data_point // bin_width

    所以:

    bin_counts = [0 for bin in bins]
    for data_point in data_points:
        bin_number = data_point // bin_width
        bin_counts[bin_number] += 1
    

    显示其他选项之一,因为我认为您是在 cmets 中询问的:

    bins = [[i*bin_width, (i+1)*bin_width, 0] for i in range(num_bins)]
    for data_point in data_points:
        bin_number = data_point // bin_width
        bins[bin_number][2] += 1
    

    这里,每个 bin 是一个 [start, stop, count] 列表,而不是一个 (start, stop) bin 列表和一个单独的 count 值列表。

    【讨论】:

    • 所以我对创建垃圾箱的方式有什么问题感到有些困惑,您的解决方案是:bins = list[(i*bin_width, (i+1)*bin_width) for i in range(num_bins),0] ?
    • @Wana_B3_Nerd:只要您希望 bins 成为 (start, stop) 值的数组,您创建垃圾箱的方式就没有任何错误。如果您希望它们与众不同,那么您当然应该创建不同的东西。
    • 好的,所以如果我想将 bin 设置为列表格式,我应该取消“for I in range(num_bins)”还是应该看起来像我在第一条评论中的格式。
    • @Wana_B3_Nerd:我不太明白你在问什么。您的第一条评论中的格式甚至不是有效的 Python,而仅删除 for i in range(num_bins) 仅意味着您将拥有一个 (start, stop) bin 的列表,而不是其中的 num_bins 的列表……我更新的答案了吗帮忙?
    • 是的,它有帮助,但是当我运行它时出现错误:TypeError: 'numpy.float64' object is not iterable
    【解决方案3】:
    from collections import Counter
    
    frequency_data = Counter()
    
        for d in data:
            new_bins = bins
            median = len(new_bins)/2
            while not new_bins[median][0] < d < new_bins[median][1]:
                if d < new_bins[median][0]:
                    new_bins = new_bins[:median]
                elif d > new_bins[median][1]:
                    new_bins = new_bins[median:]
                median = len(new_bins)/2
            frequency_data[new_bins[median]] += 1
    

    【讨论】:

    • 为什么要找到 O(N) 而不是 O(1)?当你有一个连续的索引作为你的键时,为什么要使用字典?既然可以在同一个模块中使用Counter,为什么还要使用defaultdict 来创建Counter
    • 我担心在列表中使用连续索引将无法处理小数大小的 bin。例如 (2.3, 2.4),大小为 0.1。
    • 而默认dict的原因是如果没有找到它会添加一个查询键,而Counter没有。
    • if bin[0] &lt; d &lt; bin[1]。此外,您有更好的选择来查找要放入项目的 bin。您可以在 O(logn) 时间内进行二进制搜索,或者您可以找出一种方法来创建适当的键并使用 dict 进行 O(1) 查找。
    • 回复:“[defaultdict] 如果没有找到它,则添加一个查询键,Counter 没有”。我不知道你的意思。计数器似乎以您所说的方式工作。 ` >>> from collections import Counter >>> c = Counter() >>> c["a"] += 4 >>> c Counter({'a': 4})`
    猜你喜欢
    • 2019-07-24
    • 1970-01-01
    • 2012-08-16
    • 2019-02-16
    • 2018-04-12
    • 2021-05-12
    • 2017-10-24
    • 2021-12-26
    • 2011-05-05
    相关资源
    最近更新 更多