Java Apache Commons getPercentile() отличается тем, что MS Excel процентили

У меня есть алгоритм, который вычисляет 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 ( который я получил, чтобы достичь).

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

Спасибо.

Ответ 1

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

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

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

setPercentileImpl(PercentileExcel);

Ответ 2

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

Apache methodметод, на который ссылается страница 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;
 }

Ответ 3

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

Ответ 4

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