【问题标题】:Python - Count occurrences of certain ranges in a listPython - 计算列表中某些范围的出现次数
【发布时间】:2018-09-09 06:56:47
【问题描述】:

所以基本上我想计算一个浮点出现在给定列表中的次数。例如:由用户输入成绩列表(总分100分),并以十个为一组进行排序。 0-10、10-20、20-30 等)的分数出现了多少次?比如考试成绩分布。我知道我可以使用 count 功能,但由于我不是在寻找特定的数字,所以我遇到了麻烦。有没有办法结合计数和范围?感谢您的帮助。

【问题讨论】:

    标签: python list count range histogram


    【解决方案1】:
    decs = [int(x/10) for x in scores]
    

    从 0-9 -> 0、10-19 -> 1 等范围内映射分数。然后只计算 0、1、2、3 等的出现次数(通过 collections.Counter 之类的东西),并从那里映射回范围。

    【讨论】:

    • 技术上有所不同 - x//10 将生成 float 结果,而 int(x/10) 将生成 int
    • 当然,@RaymondHettinger - 但我没有说任何关于 list.count 的事情,所以我不知道你为什么提到这个。
    • 是的,它们是不同的,但我认为// 非常棒,所以我会随时提出来。
    【解决方案2】:

    此方法使用二分法,效率更高,但需要您先对分数进行排序。

    from bisect import bisect
    import random
    
    scores = [random.randint(0,100) for _ in xrange(100)]
    bins = [20, 40, 60, 80, 100]
    
    scores.sort()
    counts = []
    last = 0
    for range_max in bins:
        i = bisect(scores, range_max, last)
        counts.append(i - last)
        last = i
    

    我不希望您为此安装 numpy,但如果您已经拥有 numpy,则可以使用 numpy.histogram

    更新

    首先,使用 bisect 更加灵活。使用 [i//n for i in scores] 要求所有 bin 的大小相同。使用 bisect 允许 bin 具有任意限制。 i//n 也表示范围是 [lo, hi)。使用 bisect 范围是 (lo, hi] 但如果你想要 [lo, hi) 可以使用 bisect_left。

    第二个平分速度更快,请参阅下面的时间安排。我已经用较慢的 sorted(scores) 替换了 scores.sort() 因为排序是最慢的步骤,我不想用预先排序的数组来偏差时间,但是 OP 说他/她的数组已经在这种情况下,对分进行排序可能更有意义。

    setup="""
    from bisect import bisect_left
    import random
    from collections import Counter
    
    def histogram(iterable, low, high, bins):
        step = (high - low) / bins
        dist = Counter(((x - low + 0.) // step for x in iterable))
        return [dist[b] for b in xrange(bins)]
    
    def histogram_bisect(scores, groups):
        scores = sorted(scores)
        counts = []
        last = 0
        for range_max in groups:
            i = bisect_left(scores, range_max, last)
            counts.append(i - last)
            last = i
        return counts
    
    def histogram_simple(scores, bin_size):
        scores = [i//bin_size for i in scores]
        return [scores.count(i) for i in range(max(scores)+1)]
    
    scores = [random.randint(0,100) for _ in xrange(100)]
    bins = range(10, 101, 10)
    """
    from timeit import repeat
    t = repeat('C = histogram(scores, 0, 100, 10)', setup=setup, number=10000)
    print min(t)
    #.95
    t = repeat('C = histogram_bisect(scores, bins)', setup=setup, number=10000)
    print min(t)
    #.22
    t = repeat('histogram_simple(scores, 10)', setup=setup, number=10000)
    print min(t)
    #.36
    

    【讨论】:

    • 我同意@amber。在这里使用 bisect 是一种浪费,因为您可以对均匀间隔的 bin 使用简单的除法。
    • 我认为 @RaymondHettinger 和我正在考虑 bisect 的不同用法,而不是您在这里最终所做的(即,使用 bisect 来查找单个分数进入哪个 bin,是一种浪费)。对于大量的分数,你是对的,二分法可能是有效的。
    【解决方案3】:

    要对数据进行分组,请将其除以间隔宽度。要计算每组中的数量,请考虑使用collections.Counter。这是一个带有文档和测试的示例:

    from collections import Counter
    
    def histogram(iterable, low, high, bins):
        '''Count elements from the iterable into evenly spaced bins
    
            >>> scores = [82, 85, 90, 91, 70, 87, 45]
            >>> histogram(scores, 0, 100, 10)
            [0, 0, 0, 0, 1, 0, 0, 1, 3, 2]
    
        '''
        step = (high - low + 0.0) / bins
        dist = Counter((float(x) - low) // step for x in iterable)
        return [dist[b] for b in range(bins)]
    
    if __name__ == '__main__':
        import doctest
        print doctest.testmod()
    

    【讨论】:

    • 我看起来你对之前写的所有四个答案都投了反对票。如果是这种情况,那么我会说,尽管您的答案可能是最好的,但也许并非所有其他答案都值得被否决,因为它们毕竟可能有用(即使它们都不是最好的)。
    • 感谢您的回复。我正在尝试实施您的解决方案,但遇到了数学运算符的问题。例如, step 和 dist 变量不适用于字符串。抱歉,如果我听起来像个菜鸟(这是因为我是),但有没有办法将分数强制列在列表中?我输入的是 11,48,13,9,4。这是默认的字符串吗?
    • 对多个 cmets 感到抱歉。这是我正在使用的内容:'from collections import Counter defgradeDistribution(examScores, low, high, bins): step = (high - int(low) + 0.0) / bins dist = Counter((x - int(low) ) // step for x in ExamScores) return [dist[b] for b in range(bins)]examScores=[raw_input("please enter scores")]gradeDistribution(examScores, 0, 100, 10)' 错误信息 I '得到的是:TypeError: unsupported operand type(s) for -: 'str' and 'int' 感谢任何人提供的任何见解。
    • @user1246457 发生这种情况时,您应该更新您的问题,如果您希望确保特定人员收到更新通知,您可以留下简短的评论。这样您就不会达到评论限制,并且您的代码可以阅读。当用户输入分数时,它们被存储为字符串。您应该在调用直方图函数之前将它们转换为浮点数或整数,方法是执行 [float(i) for i in examScores] 之类的操作。
    • 编辑了答案以包含来自字符串输入的 float 转换。
    【解决方案4】:

    如果你对使用外部库 NumPy 没问题,那么你只需要调用numpy.histogram():

    >>> data = [82, 85, 90, 91, 70, 87, 45]
    >>> counts, bins = numpy.histogram(data, bins=10, range=(0, 100))
    >>> counts
    array([0, 0, 0, 0, 1, 0, 0, 1, 3, 2])
    >>> bins
    array([   0.,   10.,   20.,   30.,   40.,   50.,   60.,   70.,   80.,
             90.,  100.])
    

    【讨论】:

      猜你喜欢
      • 2017-11-13
      • 1970-01-01
      • 1970-01-01
      • 2017-03-19
      • 2017-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多