高效,快速的numpy直方图

时间:2014-07-01 17:47:51

标签: python arrays performance numpy histogram

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

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

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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

程序:

  • 计算每个bin的整数索引(例如,文件中第一天的17 x天数+(整数 - 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 ms内完成。但是,实际的实现在很大程度上取决于时间戳的形式;有些更快计算,有些更慢。

但是,如果需要的数据达到每日水平,我怀疑是否有任何其他分箱方法会更快。

如果你想对(一年一次,一周一周等)或其他一些分类方法有不同的观点,我对你的问题并不十分了解。在任何情况下归结为将相关行汇总在一起。

答案 2 :(得分:1)

这是一个解决方案,使用以下链接中的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包,它也可能是这个问题的优雅解决方案。