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()));
}
}