我正在寻找一种好的算法(意味着最小的计算量,最小的存储需求)来估计太大而无法存储的数据集的中值,这样每个值只能被读取一次(除非您明确存储该值)。可以假设的数据没有界限。
只要知道精度,就可以近似。
有指针吗?
我正在寻找一种好的算法(意味着最小的计算量,最小的存储需求)来估计太大而无法存储的数据集的中值,这样每个值只能被读取一次(除非您明确存储该值)。可以假设的数据没有界限。
只要知道精度,就可以近似。
有指针吗?
Answers:
您是否可以将数据集分组为更小的数据集(例如100或1000或10,000个数据点),然后再计算每个组的中位数。如果使用足够多的数据集进行此操作,则可以通过运行足够多的较小数据集来收敛到“平均”解决方案,从而绘制出每个较小集的结果的平均值之类的东西。
诸如分箱程序之类的东西怎么样?假设(出于说明目的)您知道值在1到1百万之间。设置N个大小为S的容器。因此,如果S = 10000,则将有100个容器,对应于值[1:10000,10001:20000,...,990001:1000000]
然后,逐步浏览这些值。无需存储每个值,只需在适当的bin中增加计数器即可。使用每个bin的中点作为估计值,您可以合理地近似中位数。您可以通过更改垃圾箱的大小将其缩放为所需的精细或粗略分辨率。您仅受拥有多少内存的限制。
由于您不知道您的值可能会变大,因此,请使用一些快速的信封计算方法,选择一个足够大的bin大小,这样就不会用完内存。您也可能会稀疏地存储垃圾箱,以便仅在垃圾箱包含值的情况下添加垃圾箱。
编辑:
链接ryfm提供了一个执行此操作的示例,其中还有一个额外的步骤,即使用累积百分比来更准确地估计中位数bin中的点,而不仅仅是使用中点。这是一个不错的改进。
在维斯特-的Tarjan选择算法(有时也被称为中位数的中位数算法)可以让您在计算线性时间的中间元素,没有任何的排序。对于大型数据集,这可能比对数线性排序快很多。但是,它不能解决您的内存存储问题。
我从来没有这样做,所以这只是一个建议。
我看到两种(其他)可能性。
一半数据
抽样分布
另一种选择是使用涉及采样分布的近似值。如果您的数据为“正常”,则中等n的标准误差为:
1.253 * SD /平方英尺(n)
为了确定您满意的n的大小,我在R中运行了快速蒙特卡洛模拟
n = 10000
outside.ci.uni = 0
outside.ci.nor = 0
N=1000
for(i in 1:N){
#Theoretical median is 0
uni = runif(n, -10, 10)
nor = rnorm(n, 0, 10)
if(abs(median(uni)) > 1.96*1.253*sd(uni)/sqrt(n))
outside.ci.uni = outside.ci.uni + 1
if(abs(median(nor)) > 1.96*1.253*sd(nor)/sqrt(n))
outside.ci.nor = outside.ci.nor + 1
}
outside.ci.uni/N
outside.ci.nor/N
对于n = 10000,统一中位数估计值的15%在CI之外。
这是在stackoverflow上提出的问题的答案:https : //stackoverflow.com/questions/1058813/on-line-iterator-algorithms-for-estimating-statistical-median-mode-skewness/2144754#2144754
迭代更新中位数+ = eta * sgn(sample-中位数)听起来像是要走的路。
所述Remedian算法(PDF)给出具有低存储要求和良好限定的精度的一个通位数估计。
以b为基础的救济者通过计算b个观察值组的中位数,然后计算这些中位数的中位数,直到仅剩下一个估计值来进行处理。此方法仅需要k个大小为b的数组(其中n = b ^ k)...
如果您使用的值在一定范围内(例如1到100000),则可以使用整数存储桶高效地计算大量值(例如,数万亿个条目)的中位数(此代码取自BSD许可的ea -utils / sam-stats.cpp)
class ibucket {
public:
int tot;
vector<int> dat;
ibucket(int max) {dat.resize(max+1);tot=0;}
int size() const {return tot;};
int operator[] (int n) const {
assert(n < size());
int i;
for (i=0;i<dat.size();++i) {
if (n < dat[i]) {
return i;
}
n-=dat[i];
}
}
void push(int v) {
assert(v<dat.size());
++dat[v];
++tot;
}
};
template <class vtype>
double quantile(const vtype &vec, double p) {
int l = vec.size();
if (!l) return 0;
double t = ((double)l-1)*p;
int it = (int) t;
int v=vec[it];
if (t > (double)it) {
return (v + (t-it) * (vec[it+1] - v));
} else {
return v;
}
}