Scipy:在循环中逐个事件地填充DB中的直方图读数

时间:2012-11-14 10:29:07

标签: python numpy scipy

您有时不希望在创建巨大列表后填充直方图。您想要读取数据库并按事件填充直方图事件。例如:

collection = db["my_collection"]
for event in collection.find():
   histogram.fill(event['a_number'])

所以,如果我在集合中有10Bn条目,我可以填写我需要的任何直方图进行分析而不将所有数据都放在内存中。

我已经完成了构建我自己的fill_histogram函数,但我认为应该有一些可以使用的东西...... 20世纪80年代开发的HBOOK FORTRAN库有“HFILL”作为其最常用的子程序:)

顺便说一下,这是一个为numpy.histogram工作的函数,但我找不到numpy:

def hfill(histogram, datum, weight=1):
'''
Bin the right bin in a numpy histogram for datum, with weight.
If datum is outside histogram's bins' range, histogram does not change
'''
for idx, b in enumerate(histogram[1]):
    if idx > 0:
        if (datum < b and datum >= histogram[1][0]) or (datum <= b and idx == len(histogram[1]) - 1):
            histogram[0][idx - 1] += int(weight)
            break

3 个答案:

答案 0 :(得分:2)

尽管这条消息是在一段时间后发布的,但我想我会提到一些有用的工具,与HBOOK / PAW一样,用于你正在做的事情。我发现没有其他好的Python替代品来处理大量的内存不足数据。

  • PyROOT将整个ROOT框架暴露给Python,因此您可以使用其TH1 / 2/3和THnSparse变体(请参阅http://root.cern.ch/drupal/content/pyroot和一般ROOT文档)。假设您安装了具有python支持的ROOT并且具有某种类型的“事件”(例如ROOT的TTree / TChain,它针对大型数据集进行了优化),逐个事件填充将看起来像这样:

    from ROOT import TH1F
    nbins, lo, hi = 100, -3, 3
    hist = TH1F('hist', 'my hist', nbins, lo, hi)
    for evt in events:
        hist.Fill(evt.somevalue)
    # render the histogram on a TCanvas (active if present, new otherwise)
    hist.Draw()
    
  • rootpy进一步“pythonizes”ROOT接口(参见http://rootpy.org)。在上述假设和假设安装rootpy的情况下,只有上述代码段的前两行会更改为:

    from rootpy.plotting import Hist
    hist = Hist(nbins, lo, hi)
    

我一直在使用ROOT和PyROOT很长时间,并且最近尝试使用rootpy来更好地与一些SciPy工具集成。 rootpy与matplotlib的集成也很不错,特别是如果你想让直方图出现在IPython笔记本中,例如:

from rootpy.plotting import Hist
import rootpy.plotting.root2matplotlib as rplt
import matplotlib.pyplot as plt

hist = Hist(100, -3, 3)
hist.FillRandom('gaus')
fig = plt.figure(figsize=(7, 5), dpi=100, facecolor='white')
rplt.errorbar(hist, xerr=False, emptybins=False)
plt.show()

上面的代码片段可以作为最小的测试,看看是否安装了ROOt,PyROOT,rootpy和matplotlib。

答案 1 :(得分:1)

我通常使用一个简单的包装器来解决这个问题的常规numpy.histogram

import numpy as np

class Hist1D(object):

    def __init__(self, nbins, xlow, xhigh):
        self.nbins = nbins
        self.xlow  = xlow
        self.xhigh = xhigh
        self.hist, edges = np.histogram([], bins=nbins, range=(xlow, xhigh))
        self.bins = (edges[:-1] + edges[1:]) / 2.

    def fill(self, arr):
        hist, edges = np.histogram(arr, bins=self.nbins, range=(self.xlow, self.xhigh))
        self.hist += hist

    @property
    def data(self):
        return self.bins, self.hist

这允许使用要求:

from matplotlib import pyplot as plt

h = Hist1D(100, 0, 1)
for _ in range(1000):
    a = np.random.random((3,))
    h.fill(a)
    plt.step(*h.data)
    plt.show()

编辑:如果某人有类似的基于事件的设置,但对于2D数据,我也有code for that。由于这里的问题没有被要求,我没有将其添加到答案中。

答案 2 :(得分:0)

这是一个简化的例子:

>>> c = Counter()
>>> for j in xrange(10):
...   c[j] = j**2
>>> c
Counter({9: 81, 8: 64, 7: 49, 6: 36, 5: 25, 4: 16, 3: 9, 2: 4, 1: 1, 0: 0})

这里任何时候都不需要内存中的整数列表。当然,如果您想将直方图作为numpy数组,则必须手动从Counter构造它。

如果你正在使用python&lt; 2.7,Counter无法提供collections,但此处为ActiveState recipe