Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Apache Commons getPercentile()与MS Excel percentile不同的结果_Java_Excel_Statistics_Apache Commons_Percentile - Fatal编程技术网

Java Apache Commons getPercentile()与MS Excel percentile不同的结果

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

我有一个算法,它使用一系列值(12个值)的
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()));
    }
}