我试图计算出的中位数的一套价值观,但我不想储存的所有价值观为可能打击的存储要求。有没有一种方法计算或估计的中位数没有储存和排序的所有个人的价值观?

理想情况下,我想写我的代码有点像下面

var medianCalculator = new MedianCalculator();
foreach (var value in SourceData)
{
  medianCalculator.Add(value);
}
Console.WriteLine("The median is: {0}", medianCalculator.Median);

所有我需要的是实际MedianCalculator代码!

更新: 有些人问,如果所值我想要计算中间值为有已知的性质。答案是肯定的。一个值是在0.5增量从约-25至-0.5.其它也是在0.5增量从-120到-60。我猜这意味着我可以用某种形式的直方图对于每个价值。

感谢

尼克

有帮助吗?

解决方案

如果值是离散的,不同值的数量不太高,你可能只是聚集在直方图发生的每个值的次数,然后找到直方图计数的中位数(距离加起来计数顶部和直方图的底部,直到你达到中等)。或者,如果他们是连续的值,你可以将其分发到箱子里去 - 这不会告诉你确切的中位数,但它会给你一个范围,如果您需要了解更准确,你可以再一次遍历列表,只检查在中央bin中的元素。

其他提示

有是 'remedian' 统计量。它通过第一设定K个阵列,各个长度b。数据值被馈送到第一阵列,并且当这是满的,中值被计算并存储在下一个阵列,在此之后被再使用的第一阵列的第一POS。当第二阵列是充满其值的中值被存储在第三阵列,等等,等等的第一POS你的想法:)

这是简单和相当强劲。基准是在这里...

http://web.ipac.caltech.edu/工作人员/ fmasci /家庭/ astro_refs / Remedian.pdf

希望这有助于

迈克尔

我使用这些增量/递归平均数和中位数估计,这两者都使用恒定存储:

mean += eta * (sample - mean)
median += eta * sgn(sample - median)

其中ETA是一个小的学习速率参数(例如0.001),SGN()是符号函数,其返回的一个{-1,0,1}。

此类型的增量的平均估计的似乎是所有使用的地方,例如在无人监督的神经网络学习规则,但中位版本似乎不太常见,尽管它的好处(鲁棒性异常值)。如此看来,中位数版本可以被用作许多应用中的平均估计的替代品。

我很想看到类似的形式的增量模式估计...

(注:我也贴这类似的话题在这里:的” 在线”(迭代)算法用于估计统计中值,模式,偏度,峰度?

这里是一个疯狂的方法,你可能会尝试。这是一个典型问题在流算法。规则是

  1. 你的内存有限,请说 O(log n) 哪里 n 是的项目数量你想要的
  2. 你可以看一下在每个项目一旦作出决定时并没有用它做什么,如果你储存,它的成本的存储器,如果你把它扔掉它永远消失。

的想法找到一个中间值是简单的。样本 O(1 / a^2 * log(1 / p)) * log(n) 元素从清单随机的,你可以这样做,通过水库抽样(见a 前一个问题).现在简单地返回的中值从你的抽样元素中,使用古典方法。

保证这一索引项目的返回将会 (1 +/- a) / 2 与率至少 1-p.因此,有一个概率p失败,则可以选择通过取样的多个元素。它不会返回中位或保证项目的价值返回的任何地方接近值,只是说当你排序的清单的项目返回的将近一半的清单。

这个算法的使用 O(log n) 额外的空间和运行在线性时间。

这是很难全面恢复一般,尤其是处理已排序退化系列,还是有一堆值中的“启动”清单,但清单结束在不同范围内具有价值。

制作的直方图的基本思想是最有前途的。这可以让你积累从它的分布信息并解答疑问(如中位数)。中位数将是近似的,因为你明显不存储所有值。所述存储空间是固定的,因此将与您有任何长度的序列工作。

但你不能只是建立一个柱状图从说的第100个值,并使用直方图不断..不断变化的数据可以作出这样的直方图无效。所以你需要一个动态直方图,可以在运行中改变它的范围和箱。

请,其具有N个频点的结构。您会存储每个时隙过渡(N + 1倍的值总计)以及所述存储箱的人口的X值。

流中的数据。记录第一N + 1的值。如果流在此之前结束,伟大的,你必须加载所有的值,你可以找到确切的中位数,并将其返回。否则,使用值来定义你的第一个直方图。刚值进行排序,并使用这些作为组定义,每个箱具有1.人口这是确定有受骗者(0宽度的帧)。

现在流在新的值。对于每一个二进制搜索找到它所属的垃圾桶。 在通常情况下,你只需增加段的人口和继续。 如果您的抽样超出了直方图的边缘(最高或最低),只是延长了末彬的范围,包括它。 当你流完成后,你通过查找具有在它的两侧相等人口垃圾桶,和线性插值剩余箱宽度发现中间采样值。

但是,这还不够..你仍然需要,因为它是在被传输到直方图适应数据。当斌获得过满,你失去有关斌子分布信息。 您可以通过基于启发式适应解决这个问题......最简单,最强大的一个是如果单元达到一定的阈值的人口(像10 * V / N,其中v =流中迄今为止看到的值#,和N是仓的数量),您拆分过多的垃圾桶。在仓的中点处添加一个新的价值,给原斌人口的每一侧的一半。但是,现在你有太多的垃圾箱,所以你需要删除箱。一个很好的启发式算法就是要找到与人口和宽度上尺寸最小的bin。删除它,与它的左或右的邻居将其合并(本身具有宽度和人口最少的产品邻居的哪一个)。完成! 请注意,合并或分立箱丢失信息,但这是不可避免的..你只有固定的存储。

此算法是很好的,因为它会处理全部类型的输入流,并给予了良好的效果。如果你有选择的样品订单的奢侈品,随机抽样是最好的,因为最小化拆分和合并。

该算法还可以查询任何百分比,不只是中位数,因为你有一个完整的分布估计。

我用我自己的代码这种方法在很多地方,多数用于调试日志..其中一些统计数据,你记录有未知的分布。有了这个算法,你不需要去猜测的时间提前。

缺点是不平等箱宽度意味着你必须做每个样品二进制搜索,所以你的净算法是O(NlogN)。

我不认为这是可能做到的,没有具有清单中记忆。你可以明显地大致与

  • 平均如果你知道这数据是对称分布
  • 或计算一个适当的中间值的一小部分的数据(这符合在存储器)-如果你知道你的数据具有同样的分布在的样品(例如第一项具有相同的分配作为最后的一个)

大卫的建议似乎是近似中值最明智的做法。

一个运行的意味着作为同样的问题,是一种更容易计算:

  

中号<子>名词 = M <子> N-1 +((V <子>名词 - 中号<子> N-1 )/ n)的

     

其中,M <子>名词是n个值的平均值中,M <子> N-1 是先前的平均值,和V <子>名词是新值

在换句话说,新的平均值是现有平均值加新值和平均值,通过值的数量之差除以。

在这个代码看起来是这样的:

new_mean = prev_mean + ((value - prev_mean) / count)

但很明显,你可能要考虑特定语言的东西,如浮点舍入误差等。

发现的最小和最大的列表,包含N项目通过直线搜索和他们的名字作为高价值并因情况变未执行化而 让MedianIndex=(N+1)/2

1以二进制的搜索:

重复以下4个步骤,直至因情况变未执行化而 < 高价值.

  1. 获得MedianValue约=(高价值+因情况变未执行化而)/2

  2. 获得NumberOfItemsWhichAreLessThanorEqualtomedianvalue=K

  3. 为K=MedianIndex,然后返回MedianValue

  4. 是K>MedianIndex?然后高价值=MedianValue其他因情况变未执行化而=MedianValue

它将以更快的速度没有消费记忆

2阶二进制的搜索:

LowIndex=1 HighIndex=N

重复下列5个步骤,直至(LowIndex < HighIndex)

  1. 获得近似DistrbutionPerUnit=(高价值-因情况变未执行化而)/(HighIndex-LowIndex)

  2. 获得近似MedianValue=因情况变未执行化而+(MedianIndex-LowIndex)*DistributionPerUnit

  3. 获得NumberOfItemsWhichAreLessThanorEqualtomedianvalue=K

  4. 是(K=MedianIndex)?回MedianValue

  5. 是(K>MedianIndex)?然后HighIndex=K和高价值=MedianValue别LowIndex=K和因情况变未执行化而=MedianValue

它将以更快的速度超过1顺序而不消耗存储器

我们还可以认为配合高价值,因情况变未执行化而且MedianValue与HighIndex,LowIndex和MedianIndex给一个抛物线,并且可以获得三阶二进制的搜索,这将以更快的速度比2的顺序而不消耗存储器等...

通常,如果输入在一定范围内,说1至1亿,很容易建立一系列计数:读代码为"分位数"和"ibucket"在这里: http://code.google.com/p/ea-utils/source/browse/trunk/clipper/sam-stats.cpp

这种方案可以推广作为一个近似的胁迫输入一个整数在内的一些范围内使用一个功能,你然后反向的方式出:即:foo。推动((int)输入/1000000)和分位数(foo)*1000000.

如果你输入是任意的双精确数字,然后你得到自动扩展你的直方图为的价值观来在超出范围(见上文)。

或者您可以使用的中位-三胞胎描述方法在这个文件: http://web.cs.wpi.edu/~hofri/medsel.pdf

我拿起迭代位数计算的想法。这是有起点和ETA物有所值重要的是,这些可能来自平均值和西格玛。因此,我编程这样的:

功能QuantileIterative(VAR X:双阵列; n:整数; P,意思是,西格玛:双):双;结果 瓦尔ETA,分位数,Q1,DQ:双;点击     我:整数;结果 点击开始   位数:=平均值±1.25 * *西格马(对 - 0.5);结果   Q1:=位数;结果   ETA:= 0.2 *西格玛/ XY(1 + N,0.75); //不宜过大!设置精度结果   对于i:= 1到n位数做:=位数+ ETA *(signum_smooth(X [Ⅰ] - 分位数,ETA)+ 2 * P - 1);结果   DQ:= ABS(Q1-位数);结果   如果DQ> ETA结果      然后开始搜索           如果DQ <3 * ETA ETA然后:= ETA / 4;
          对于i:= 1到n位数做:=位数+ ETA *(signum_smooth(X [Ⅰ] - 分位数,ETA)+ 2 * P - 1);结果      结束;结果   QuantileIterative:=位数结果 结束;结果 结果

至于两个元素中值将是平均值,我使用的平滑正负号函数,和XY()是x ^收率有没有想法,使其更好?当然,如果我们有更多的先验知识,我们可以使用数组的最小和最大添加代码,歪斜等。对于大数据,你不会或者使用数组,但是出于测试更容易。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top