Algorithm 如何保持动态直方图?

Algorithm 如何保持动态直方图?,algorithm,data-structures,statistics,histogram,Algorithm,Data Structures,Statistics,Histogram,是否有已知的算法+数据结构来维护动态直方图 假设我有一个数据流(x_1,w_1),(x_2,w_2)。。。其中x_t为双倍,表示一些测量变量,w_t为相关权重 我可以做显而易见的(伪python代码): 但当我有连续的数据流时,我会遇到一些问题。我手头没有完整的数据集,我必须在数据收集之间检查直方图。我也不期望: 理想的垃圾箱尺寸,不会有很多空垃圾箱 数据的范围 所以我想动态地定义垃圾箱。我可以做一件蠢事: for x in data_stream: data.append(x

是否有已知的算法+数据结构来维护动态直方图

假设我有一个数据流(x_1,w_1),(x_2,w_2)。。。其中x_t为双倍,表示一些测量变量,w_t为相关权重

我可以做显而易见的(伪python代码):

但当我有连续的数据流时,我会遇到一些问题。我手头没有完整的数据集,我必须在数据收集之间检查直方图。我也不期望:

  • 理想的垃圾箱尺寸,不会有很多空垃圾箱
  • 数据的范围
所以我想动态地定义垃圾箱。我可以做一件蠢事:

 for x in data_stream:
      data.append(x)
      hist = make_histogram(data)
但我想这会很快变慢

如果所有权重相等,我认为其中一件事是将数据存储在排序的数组中,并以保持数组排序的方式插入新数据。这样我就可以:

data = sortedarray();
for x in data_stream:
     data.insert(x)
     bins = [ data[int(i * data.size()/numbins)] for i in xrange(numbins)]
每个箱子内的计数将等于所有箱子的data.size()/numbins

我想不出一个方法来包括重量在这虽然。。。有人有什么建议吗?(关于C++的知识也会受到欢迎)。 编辑:(用于要求的澄清)

x_t是浮点数。为了计算直方图,我必须将x所在的连续范围划分为若干个箱子。所以我会有一系列的数字bin[0],bin[1],等等。。。所以我必须确定我做了什么,bin[I] 这就是当你事先有了所有的数据时,你通常做柱状图的方法。然后,您将知道最大(x)和最小(x)的限制,并且很容易确定足够的垃圾箱。例如,可以使它们在最小值(x)和最大值(x)之间等距分布

如果您事先不知道范围,则无法确定垃圾箱。你可能会收到一个不落在任何箱子里的x。或者,您可能会因为选择的范围太大而无法创建多个空垃圾箱

是粒子物理学家用于这类工作的工具……它附带python绑定。请注意,它不是一个轻量级的软件

C++中你会做一些类似

的事情
TH1D hist("hist","longer title for hist",numbins,lowlimit,highimit);

...

for (int i=0; i<num; ++i){
   hist.Fill(x[i],w[i]);
}

...

hist.Draw();
TH1D hist(“hist”,“hist的长标题”,numbins,lowlimit,highimit);
...

对于(inti=0;i,听起来好像您想要以下抽象数据类型的实现

insert(x, w): add item x to the collection with weight x
select(p): return the item greater than a p weighted fraction of the items
例如,
select(0)
返回最小值,
select(0.5)
返回加权中值,
select(1)
返回最大值

我会用两种方法之一实现这个ADT。如果选择不频繁,我会将数据放入数组中,并使用线性时间选择算法,用于O(1)时间插入和O(n)时间选择。如果选择频繁,我会使用二叉搜索树,其中每个节点将总权重存储在其子树中。例如,在

insert(2, 10)
insert(1, 5)
insert(3, 100)
insert(4, 20)
这棵树可能看起来像

   2 (135)
  / \
 /   \
1 (5) 4 (120)
     /
    /
   3 (100)
现在,要找到加权中值,将
135
乘以
0.5
,得到所需的
67.5
从根
2
开始,我们发现
5
小于
67.5
,因此项目不在左子树中,我们减去
5
,得到
62.5
,索引进入树的其余部分。由于
135-120=15
小于
62.5
,中位数不是
2
t
15
62.5
获得
47.5
并下降到
4
。在
4
,我们发现
100
大于
47.5
,因此
3
是中位数


假设是一个平衡树,
insert
select
的运行时间都是
O(logn)
。如果我是从头开始实现的,我可能会选择splay树。

如何确定存储箱的数量

确定柱状图中的值有许多规则。对于您的问题,我同意Scott的选择:

bin_width = 3.5*sd*n^{-1/3}
其中sd是标准偏差,n是数据点的数量。至关重要的是,您可以使用算法计算标准偏差。箱子的数量k由下式给出:

k = ceil((max(x) - min(x))/bin_width)
存储数据

假设我们观察到N个数据点,那么标准偏差的置信区间

Lower limit: sd*sqrt((N-1)/CHIINV((alpha/2), N-1))
Upper limit: sd*sqrt((N-1)/CHIINV(1-(alpha/2), N-1))
其中CHIINV是卡方分布的值。当N=1000时,sd的CI为:

(0.96*sd, 1.05*sd)
因此,95%CI的料仓宽度为:

(3.5*0.96*sd*1000^{-1/3}, 3.5*1.05*sd*1000^{-1/3})
(0.336*sd, 0.3675*sd)
你可以得到类似的箱子数量

算法

  • 存储所有数据,直到您对最佳箱子宽度有一个很好的估计,例如箱子数量的上下CI相等时
  • 创建存储箱的数量并将数据放入存储箱中
  • 所有新的数据点都放入存储箱中,然后丢弃
  • 评论

  • Freedman–Diaconis的规则更适合选择箱子的数量,但它涉及分位数之间的范围,这在在线计算时有点棘手
  • 从技术上讲,当数据是连续的时,CI间隔是不正确的。但是,如果您设置了一个合理的最小观察数据点数,例如~100或1000,您应该可以
  • 这假设所有数据都遵循相同的分布
  • 箱子的数量取决于n^{-1/3}。如果您大致知道需要多少个点,即10^5、10^6或10^7,那么您可以创建更小的箱子,并期望在将来更改箱子宽度

  • 请您澄清一下,如果您只关心权重,为什么不简单地做
    数据[x]+=w
    ?除了权重之外,您还关心什么?x是一个浮点数…对于一系列的数字bin[0],bin[1],…我必须确定bin[I](3.5*0.96*sd*1000^{-1/3}, 3.5*1.05*sd*1000^{-1/3}) (0.336*sd, 0.3675*sd)