【问题标题】:efficient, fast numpy histograms高效、快速的 numpy 直方图
【发布时间】:2014-08-22 09:00:27
【问题描述】:

我有一个 2D numpy 数组,由 ca. 15'000'000 个数据点。每个数据点都有一个时间戳和一个整数值(40 到 200 之间)。我必须创建数据点分布的直方图(16 个箱:40-49、50-59 等),按年份、当年的月份、当年的周和当月的天排序。

现在,我想知道实现此目的最有效的方法是什么。考虑到阵列的大小,性能是一个突出的考虑因素。我正在考虑嵌套“for”循环,按年、按月等分解数组。但我读到 numpy 数组具有很高的内存效率,并且有各种技巧可以快速处理。所以我想知道是否有更快的方法来做到这一点。您可能已经意识到,我是一名业余程序员(“现实生活”中的分子生物学家),我的问题可能相当幼稚。

【问题讨论】:

    标签: python arrays performance numpy histogram


    【解决方案1】:

    首先,填写您的 16 个垃圾箱,完全不考虑日期。 然后,按日期对每个 bin 中的元素进行排序。 现在,您可以使用二分搜索在每个 bin 中有效地定位给定的年/月/周。

    【讨论】:

      【解决方案2】:

      为了做到这一点,numpynumpy.bincount 中有一个函数。它的速度非常快。它是如此之快,以至于您可以为每个整数(161 个 bin)和天(可能 30000 个不同的天?)创建一个 bin,从而产生几百万个 bin。

      程序:

      • 计算每个 bin 的整数索引(例如 17 x 从文件第一天算起的天数 + (integer - 40)//10)
      • 运行np.bincount
      • 重塑为正确的形状(天数,17)

      现在您有了分箱数据,然后可以将这些数据集中到时间维度中所需的任何分箱中。

      在不知道输入数据形式的情况下,整数 bin 计算代码可能是这样的:

      # let us assume we have the data as:
      #   timestamps: 64-bit integer (seconds since something)
      #   values: 8-bit unsigned integer with integers between 40 and 200
      
      # find the first day in the sample
      first_day = np.min(timestamps) / 87600
      
      # we intend to do this but fast:
      indices = (timestamps / 87600 - first_day) * 17 + ((values - 40) / 10)
      
      # get the bincount vector
      b = np.bincount(indices)
      
      # calculate the number of days in the sample
      no_days = (len(b) + 16) / 17
      
      # reshape b
      b.resize((no_days, 17))
      

      需要注意的是b中的第一天和最后一天取决于数据。在测试中,大部分时间都花在计算指数上(使用 i7 处理器大约需要 400 毫秒)。如果需要减少,可以使用numexpr 模块在大约 100 毫秒内完成。然而,实际的实现很大程度上取决于时间戳的形式。有些计算速度更快,有些计算速度较慢。

      但是,如果每天需要数据,我怀疑是否有任何其他分箱方法会更快。

      如果您想对(逐年、逐周等)或其他一些分箱方法有不同的看法,我不太了解您的问题。无论如何,归结为将相关行加在一起。

      【讨论】:

        【解决方案3】:

        这是一个解决方案,它使用了以下链接中的 group_by 功能: http://pastebin.com/c5WLWPbp

        import numpy as np
        
        dates = np.arange('2004-02', '2005-05', dtype='datetime64[D]')
        
        np.random.shuffle(dates)
        
        values = np.random.randint(40,200, len(dates))
        
        years  = np.array(dates, dtype='datetime64[Y]')
        months = np.array(dates, dtype='datetime64[M]')
        weeks  = np.array(dates, dtype='datetime64[W]')
        
        
        from grouping import group_by
        
        bins = np.linspace(40,200,17)
        
        for m, g in zip(group_by(months)(values)):
            print m
            print np.histogram(g, bins=bins)[0]
        

        或者,你可以看看 pandas 包,它可能也有一个优雅的解决这个问题的方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-29
          • 2016-12-21
          • 2011-10-10
          • 1970-01-01
          • 2015-10-20
          • 1970-01-01
          相关资源
          最近更新 更多