【问题标题】:Java Apache Commons getPercentile() different result that MS Excel percentileJava Apache Commons getPercentile() 与 MS Excel 百分位数不同的结果
【发布时间】:2011-08-22 07:59:12
【问题描述】:

我有一个算法,可以计算percentile(85)Apache Commons 的一系列值(12 个值),以便稍后使用阈值进行评估以做出决定。结果类似于 Excel 给出的结果,但不相等,有时这对我的应用程序至关重要,因为使用 excel 的结果没有通过阈值,而使用 Java 中的 Apache Commons Math 可以,所以我得到了不同输出。

这是一个示例:每 2 小时的互联网流量 (Mbps)

32,7076813360000000 41,2580429776000000 45,4453940200000000 48,8044409456000000 46,7462847936000000 49,8028100056000000 54,3719451144000000 41,9708134600000000 29,4371963240000000 22,4667255616000000 20,0388452248000000 28,7807757104000000 P>

除以 1000 Mb(电缆的容量)后,我计算职业的 percentil(85):

Excel:0,049153870117

Apache Commons 数学:0.05003126676104001

我发现可以使用setPercentileImpl() 更改百分位数的实现(不存在官方百分位数),但我找不到任何如何执行此操作的示例或 Excel 算法(这是我被告知要实现的目标)。

欢迎任何关于此的帮助。

谢谢。

【问题讨论】:

  • 你能举例说明你看到的差异吗?有了数据我们可以自己试试?
  • 当然,我会用数据编辑我的问题。
  • 请注意,结果不同的原因是值集是 12。对于较大的值,两种算法都会给出相似的结果。我的问题是如何在Java中实现excel的方法。
  • 好问题,当我使用线性插值时,我得到0.049004(当我将你的数字除以 1e19 时)我不知道 0.05000 怎么可能是一个答案,因为它超过了第 11 大并且它应该更少恕我直言。
  • 如果我使用简化的三阶多项式插值,我得到 0.491584

标签: java excel statistics apache-commons percentile


【解决方案1】:

以下不需要新类的替代方案在 3.6 中有效:

DescriptiveStatistics ds = new DescriptiveStatistics();
Percentile p = new Percentile(50.0).withEstimationType(EstimationType.R_7)
                .withNaNStrategy(NaNStrategy.REMOVED)
                .withKthSelector(new KthSelector(new 
                  MedianOf3PivotingStrategy()))
ds.setPercentileImpl(p);

【讨论】:

    【解决方案2】:

    org.apache.commons.math3.stat.descriptive.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()));
        }
    }
    

    【讨论】:

    • 注意:commons-math-3.0及以下版本不支持,只有commons-math-3.5有。
    【解决方案3】:

    差异是微妙的,并且是由于假设造成的。用 3 元素案例最容易解释。假设您有三个元素(N=3)a=x[0] < b=x[1] < c=x[2]。 Apache 和 Excel 方法都说元素 b 是第 50 个百分位数(中位数)。但是它们对于 ac 是不同的。

    Apache method(和 the method referenced by the NIST page)说 a 是第 25 个百分位数,c 是第 75% 个百分位数,因为它将空间划分为 N+1 个块,即划分为四分之一。

    Excel 方法说a 是第 0 个百分位,c 是第 100 个百分位,因为空间被分成 N-1 个块,也就是一半。

    因此,如果您想要 Excel 方法并且不想自己编写代码,您可以从数组中删除最小和最大的元素,然后调用 Apache 方法 - 它应该会准确地为您提供相同的结果,除了端点以外的百分位数。

    如果您想自己编写代码,下面给出了一种简单的方法。请注意这些问题:

    • 这会对数组进行排序(因此对其进行更改)
    • 由于排序,这需要 O(N log(N)) 时间。 Apache 方法使用快速选择算法,因此需要 O(N) 时间(如果您想了解更多信息,请谷歌“快速选择”)

    代码(未经测试,甚至未编译,但应该能给你一个想法)。

    // warning - modifies data 
    double excelPercentile(double [] data, double percentile) { array
        Arrays.sort(data);
        double index = percentile*(data.length-1);
        int lower = (int)Math.floor(index);
        if(lower<0) { // should never happen, but be defensive
           return data[0];
        }
        if(lower>=data.length-1) { // only in 100 percentile case, but be defensive
           return data[data.length-1);
        }
        double fraction = index-lower;
        // linear interpolation
        double result=data[lower] + fraction*(data[lower+1]-data[lower]);
        return result;
     }
    

    【讨论】:

    • 谢谢。我想我创建了 Commons 实现 java2s.com/Open-Source/Java-Document/Science/… 的源代码,我将尝试在第 199 行更改分配给 pos 的值。这应该可以,而且我不必更改代码的结构。
    • 看起来应该可以了。我假设加倍 pos = 1+ p * (n - 1) / 100;
    • 我假设您将创建一个新类,而不是仅仅替换 Apache jar 中的 Percentile 类。如果 Apache jar 中的其他类使用此方法,这可能会很危险,并且还意味着您必须使其与未来版本保持同步
    • 几乎!它应该是 pos=(1+p*(n-1))/100。除以 100 是 Commons 方法的一部分,不是吗?所以它应该划分整个表达式。
    • 是的,我正在创建一个新类,我将尝试在代码中使用方法 setPercentileImpl(the new class),以便使用新算法。一旦我可以检查结果,我会告诉我是否得到与 Excel 中相同的值。
    【解决方案4】:

    解决方案是创建一个类 PercentileExcel,它几乎是 commons 方法的 percentile 的副本,只是在如何计算位置方面做了一些小改动:

    pos=(1+p*(n-1))/100;
    

    那么您需要在代码中添加这一行,以便将新类用于百分位数:

    setPercentileImpl(PercentileExcel);
    

    【讨论】:

      【解决方案5】:

      根据数据集计算的百分位数没有唯一的定义。请参阅Wikipedia page 了解最常用的定义。

      【讨论】:

      • 是的,我创建了至少 3 个不同的。
      猜你喜欢
      • 2020-04-17
      • 2015-05-08
      • 2019-06-02
      • 2011-07-28
      • 2016-10-16
      • 2021-09-28
      • 2022-07-29
      • 2020-07-16
      • 1970-01-01
      相关资源
      最近更新 更多