Java Apache Commons getPercentile () отличается от процентиля MS Excel - PullRequest
11 голосов
/ 10 мая 2011

У меня есть алгоритм, который вычисляет percentile(85) с Apache Commons из серии значений (12 значений) для последующей оценки с пороговым значением для принятия решения. Результат аналогичен приведенному в Excel, но не равен, и иногда это критично для моего приложения, потому что с Excel результат не пересекает порог, а с Apache Commons Math в Java это так, поэтому я получаю другое выходы.

Вот пример: интернет-трафик (Мбит / с) каждые 2 часа

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

После деления на 1000 Мб (емкость кабеля) я вычисляю процентиль (85) Занятия:

Excel: 0,049153870117

Apache Commons Math: 0,05003126676104001

Я обнаружил, что можно изменить реализацию процентиля (он не является официальным) с помощью setPercentileImpl(), но я не смог найти ни одного примера того, как это сделать, или алгоритм Excel ( именно этого мне велели достичь).

Любая помощь по этому поводу будет приветствоваться.

Спасибо.

Ответы [ 4 ]

10 голосов
/ 10 мая 2011

Разница неуловима и обусловлена ​​предположениями. Это проще всего объяснить с помощью трехэлементного случая. Предположим, у вас есть три элемента (N = 3) a=x[0] < b=x[1] < c=x[2]. И Apache, и метод Excel говорят, что элемент b является 50-м процентилем (медиана). Однако они отличаются для a и c.

Метод Apache метод, на который ссылается страница NIST ), говорят: a - это 25-й процентиль, а c - это 75% -ный процентиль, потому что он делит пространство в N + 1 блоков, то есть в четверти.

Метод Excel говорит, что a - это 0-й процентиль, а c - 100-й процентиль, поскольку пространство разделено на N-1 блоков, то есть пополам.

Из-за этого, если вам нужен метод Excel и вы не хотите его кодировать самостоятельно, вы можете просто удалить самый маленький и самый большой элемент из вашего массива и вызвать метод Apache - он должен дать вам точно тот же результат за исключением процентилей за пределами конечных точек.

Если вы хотите закодировать это самостоятельно, простой способ приведен ниже. Помните об этих проблемах:

  • сортирует массив (поэтому изменяет его)
  • это занимает O (N log (N)) время из-за сортировки. В методе Apache используется алгоритм быстрого выбора, поэтому он занимает время O (N) (google "quickselect", если вы хотите узнать больше)

Код (не проверен и даже не скомпилирован, но должен дать вам представление).

// 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;
 }
5 голосов
/ 11 января 2012

Решением было создание класса PercentileExcel , который является почти копией метода процентиля из общего фонда, за исключением небольшого изменения в том, как рассчитать позицию:

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

Тогда вам нужнодобавить эту строку в код, чтобы использовать новый класс для процентиля:

setPercentileImpl(PercentileExcel);
4 голосов
/ 10 мая 2011

Не существует уникального определения процентиля, вычисленного по набору данных. На странице Википедии приведены наиболее распространенные используемые определения.

2 голосов
/ 12 июня 2015

Класс 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()));
    }
}
...