Algorithm 如何保持动态直方图?
是否有已知的算法+数据结构来维护动态直方图 假设我有一个数据流(x_1,w_1),(x_2,w_2)。。。其中x_t为双倍,表示一些测量变量,w_t为相关权重 我可以做显而易见的(伪python代码): 但当我有连续的数据流时,我会遇到一些问题。我手头没有完整的数据集,我必须在数据收集之间检查直方图。我也不期望: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
- 理想的垃圾箱尺寸,不会有很多空垃圾箱
- 数据的范围
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]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
t15
从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)