Java Apache Commons getPercentile()与MS Excel percentile不同的结果
我有一个算法,它使用一系列值(12个值)的Java Apache Commons getPercentile()与MS Excel percentile不同的结果,java,excel,statistics,apache-commons,percentile,Java,Excel,Statistics,Apache Commons,Percentile,我有一个算法,它使用一系列值(12个值)的Apache Commons计算百分位(85),以便稍后使用阈值进行评估以做出决定。结果与Excel给出的结果相似,但并不相等,有时这对我的应用程序至关重要,因为使用Excel,结果不会超过阈值,而使用Java中的Apache Commons Math,结果会超过阈值,因此我得到不同的输出 这里是一个例子:每2小时互联网流量(Mbps) 327076813360000000 41258042976000000 4544539402000000000 48
Apache Commons
计算百分位(85)
,以便稍后使用阈值进行评估以做出决定。结果与Excel给出的结果相似,但并不相等,有时这对我的应用程序至关重要,因为使用Excel,结果不会超过阈值,而使用Java中的Apache Commons Math,结果会超过阈值,因此我得到不同的输出
这里是一个例子:每2小时互联网流量(Mbps)
327076813360000000 41258042976000000 4544539402000000000 4880444094560000004674628479360000004980281000560000005437194511440000041970813460000000 2943719632400000 224667255616000000 20038845224800000 2878075710400000
除以1000 Mb(电缆容量)后,我计算占用百分比(85):
Excel:0049153870117
Apache Commons数学:0.05003126676104001
我发现可以使用setPercentileImpl()
更改百分位数的实现(它不存在正式的实现),但我找不到任何关于如何实现这一点的示例,也找不到Excel算法(这是我被告知要实现的)
欢迎对此提供任何帮助
谢谢。从数据集计算的百分位数没有唯一的定义。有关使用中最常见的定义,请参见。差异很小,是由于假设造成的。这是最简单的解释与3元素的情况。假设有三个元素(N=3)
a=x[0]
。Apache和Excel方法都说元素b是第50个百分位(中位数)。但是,它们在a
和c
方面有所不同
(和)比如说a
是第25个百分位,c
是第75个百分位,因为它将空间分成N+1个块,即四分之一
Excel方法表示,a
是第0个百分位,c
是第100个百分位,因为空间被划分为N-1个块,即一半
因此,如果您想要Excel方法,而不想自己编写它,您可以从数组中删除最小和最大的元素,然后调用Apache方法-它应该会给出完全相同的结果,除了端点以外的百分位
如果您想自己编写代码,下面给出了一种简单的方法。注意这些问题:
- 这会对数组进行排序(因此会对其进行更改)
- 由于排序,这需要O(N log(N))时间。Apache方法使用快速选择算法,因此需要O(N)个时间(如果您想了解更多,请使用google“quickselect”)
//警告-修改数据
双百分比(双[]数据,双百分比){数组
数组。排序(数据);
双指数=百分位数*(数据长度-1);
整数下限=(整数)数学下限(指数);
如果(lower=data.length-1){//仅在100%的情况下,但应为防御型
返回数据[数据长度-1];
}
双分数=指数较低;
//线性插值
双结果=数据[下限]+分数*(数据[下限+1]-数据[下限]);
返回结果;
}
解决方案是创建一个类PercentileExcel,它几乎是commons方法中percentile的副本,只是在如何计算位置上有一个小的变化:
pos=(1+p*(n-1))/100;
然后,您需要将此行添加到代码中,以便将新类用于百分位:
setPercentileImpl(PercentileExcel);
Class
org.apache.commons.math3.stat.description.rank.Percentile
已经支持Excel风格的插值,您只需使用EstimationType.R_7
public class PercentileExcel extends Percentile {
public PercentileExcel() throws MathIllegalArgumentException {
super(50.0,
EstimationType.R_7, // use excel style interpolation
NaNStrategy.REMOVED,
new KthSelector(new MedianOf3PivotingStrategy()));
}
}
在3.6中,不需要新类别的以下替代方案:
DescriptiveStatistics ds=new DescriptiveStatistics();
百分位p=新的百分位(50.0)。带有EstimationType(EstimationType.R_7)
.带NaNStrategy(已删除NaNStrategy)
.带KTH选配件(新KTH选配件)(新
MediaNof3数据透视策略())
ds.setPercentileImpl(p);
你能给出一个你看到的差异的例子吗?我们可以自己尝试数据?当然,我会用数据编辑我的问题。请注意,不同结果的原因是一组值是12。对于较大的值,两种算法会给出相似的结果。我的问题是如何在Java中实现excel的方法。好问题,当我使用线性插值,我得到0.049004
(当我将你的数字除以1e19时)我看不出0.05000怎么可能是一个答案,因为它比第11大,而且应该更小。如果我使用简化的三阶多项式插值,我得到0.491584是的,我发现了至少3个不同的插值。谢谢。我认为我发现了Commons实现的源代码,我将尝试在第199行中更改分配给pos的值。这应该行得通,而且我不必改变代码的结构。看起来应该行得通。我假设double pos=1+p*(n-1)/100;我假设您将创建一个新类,而不仅仅是替换Apache jar中的Percentile类。如果Apache jar中的其他类使用此方法,这可能会很危险,也意味着您必须在将来的版本中将其保持最新!它应该是pos=(1+p*(n-1))/100.除以100是Commons方法的一部分,不是吗?所以它应该除以整个表达式。是的,我正在创建一个新类,我将尝试使用方法setPercentileImpl(新类)在代码中,为了使用新算法。只要我能检查结果,我就会告诉我是否得到与Excel中相同的值。注意:commons-math-3.0或更低版本不支持这一点,只有commons-math-3.5有它。
public class PercentileExcel extends Percentile {
public PercentileExcel() throws MathIllegalArgumentException {
super(50.0,
EstimationType.R_7, // use excel style interpolation
NaNStrategy.REMOVED,
new KthSelector(new MedianOf3PivotingStrategy()));
}
}