Функция процентиля NumPy отличается от функции процентиля MATLAB

когда я пытаюсь вычислить 75-й процентиль в MATLAB, я получаю другое значение, чем в NumPy.

MATLAB:

>> x = [ 11.308 ;   7.2896;   7.548 ;  11.325 ;   5.7822;   9.6343;
     7.7117;   7.3341;  10.398 ;   6.9675;  10.607 ;  13.125 ;
     7.819 ;   8.649 ;   8.3106;  12.129 ;  12.406 ;  10.935 ;
    12.544 ;   8.177 ]

>> prctile(x, 75)

ans =

11.3165

Python + NumPy:

>>> import numpy as np

>>> x = np.array([ 11.308 ,   7.2896,   7.548 ,  11.325 ,   5.7822,   9.6343,
     7.7117,   7.3341,  10.398 ,   6.9675,  10.607 ,  13.125 ,
     7.819 ,   8.649 ,   8.3106,  12.129 ,  12.406 ,  10.935 ,
    12.544 ,   8.177 ])

>>> np.percentile(x, 75)
11.312249999999999

Я тоже проверил ответ с R, и я получаю ответ NumPy.

R:

> x <- c(11.308 ,   7.2896,   7.548 ,  11.325 ,   5.7822,   9.6343,
+          7.7117,   7.3341,  10.398 ,   6.9675,  10.607 ,  13.125 ,
+          7.819 ,   8.649 ,   8.3106,  12.129 ,  12.406 ,  10.935 ,
+         12.544 ,   8.177)
> quantile(x, 0.75)
     75% 
11.31225 

что здесь происходит? И есть ли способ сделать поведение Python & R зеркальным MATLAB?

2 ответов


MATLAB по-видимому использует интерполяцию средней точки по умолчанию. NumPy и R используют линейную интерполяцию по умолчанию:

In [182]: np.percentile(x, 75, interpolation='linear')
Out[182]: 11.312249999999999

In [183]: np.percentile(x, 75, interpolation='midpoint')
Out[183]: 11.3165

понять разницу между linear и midpoint, давайте рассмотрим простой пример:

In [187]: np.percentile([0, 100], 75, interpolation='linear')
Out[187]: 75.0

In [188]: np.percentile([0, 100], 75, interpolation='midpoint')
Out[188]: 50.0

для компиляции последней версии NumPy (с помощью Ubuntu):

mkdir $HOME/src
git clone https://github.com/numpy/numpy.git
git remote add upstream https://github.com/numpy/numpy.git
# Read ~/src/numpy/INSTALL.txt
sudo apt-get install libatlas-base-dev libatlas3gf-base
python setup.py build --fcompiler=gnu95
python setup.py install

преимущества использования git вместо pip это то, что очень легко обновить (или понизить) до других версий NumPy (и вы получаете исходный код тоже):

git fetch upstream
git checkout master # or checkout any other version of NumPy
cd ~/src/numpy
/bin/rm -rf build
cdsitepackages    # assuming you are using virtualenv; otherwise cd to your local python sitepackages directory
/bin/rm -rf numpy numpy-*-py2.7.egg-info
cd ~/src/numpy
python setup.py build --fcompiler=gnu95
python setup.py install

поскольку принятый ответ все еще неполон даже после комментария @cpaulik, я размещаю здесь то, что, надеюсь, является более полным ответом (хотя, по причинам краткости, не идеально, см. ниже).

использование np.процентиль (x, p, interpolation='midpoint') будет давать один и тот же ответ только для очень конкретных значений, а именно, когда p/100 кратно 1/n, n-количество элементов массива. В исходном вопросе это действительно было так, поскольку n=20 и p=75, но в целом эти две функции различаются.

короткая эмуляция функции prctile Matlab задается:

def quantile(x,q):
    n = len(x)
    y = np.sort(x)
    return(np.interp(q, np.linspace(1/(2*n), (2*n-1)/(2*n), n), y))

def prctile(x,p):
    return(quantile(x,np.array(p)/100))

эта функция, как функция Matlab, дает кусочно-линейный выход, охватывающий от min(x) до max (x). Функция процентиля Numpy с интерполяцией=midpoint возвращает кусочно постоянный функция между средним из двух самых маленьких элементов и средним из двух самых больших. Построение двух функций для массива в оригинале вопрос дает картинка в этой ссылке (извините, не могу вставить его). Пунктирная красная линия обозначает 75% процентиль, где две функции фактически совпадают.

P.S. причина, по которой эта функция фактически не эквивалентна функции Matlab, заключается в том, что она принимает только одномерный x, давая ошибку для более высокого размерного материала. С другой стороны, Matlab принимает более высокий dim x и работает с первым (нетривиальным) измерением, но его правильная реализация возможно, займет немного больше времени. Однако и эта, и функция Matlab должны корректно работать с более высокими размерными входами для p / q (благодаря использованию np.interp, который заботится об этом).