np.квантиль с неправильным вычислением?

#python #numpy

#python #numpy

Вопрос:

При определенных настройках np.quantile допускает ошибки при определении правильного квантиля. Это ошибка?

 x = np.array([374, 358, 341, 355, 342, 334, 353, 346, 355, 344,
              349, 330, 352, 328, 336, 359, 361, 345, 324, 386,
              334, 370, 349, 327, 342, 354, 361, 354, 377, 324])

q = np.quantile(x, 0.25)

print(q)

print(len(x[x<=q]) / len(x))

print(len(x[x>=q]) / len(x))
  

Вывод:

 337.25

0.26666666666666666

0.7333333333333333
  

0.73 означает, что только 73% значений больше или равно определенному квантилю; по определению это должно быть > = 75%

Комментарии:

1. согласно Википедии , стандартного определения квантиля / процентиля не существует. Но в нем также говорится, что «Например, 20-й процентиль — это значение (или оценка), ниже которого может быть найдено 20% наблюдений». Поэтому вместо того, чтобы смотреть на то, сколько значений больше, вам, вероятно, следует посмотреть, сколько из них меньше q . Хотя я не эксперт в статистике 😉

2. Привет и добро пожаловать в SO! @SamProell то, что вы запрашиваете, уже в вопросе, с print(len(x[x<=q]) / len(x)) 😉

3. @jeannej, я знаю! Смысл, который я пытался подчеркнуть, заключается в том, что numpy верен в указанном примере, если вы посмотрите, сколько значений в x меньше q . Поскольку len(x[x<=q]) / len(x) = 0.2566 по крайней мере 25% значений лежат ниже q .

4. @SamProell Извините, я не понимаю. len(x[x<=q]) / len(x) = 0.2666 итак, немного больше, чем 26% значений лежат ниже q , но чем это отличается от утверждения, что по крайней мере 73% значений больше (с короткими десятичными дробями)? Все еще существует проблема, поскольку это не так, 25% и 75% как ожидалось здесь…

5. @jeannej, это не отличается. Проблема заключается в определении квантиля. Если вы определяете 25-й процентиль q как значение, для которого по крайней мере 25 процентов значений в списке меньше q (как это сделано в википедии), вы также не можете ожидать, что по крайней мере 75% значений больше q . Кроме того, поскольку в списке 30 элементов, вы не можете получить ровно 25% или 75%.

Ответ №1:

https://github.com/numpy/numpy/blob/v1.15.1/numpy/lib/function_base.py#L3543-L3644

 default value is linear
    interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'}
        This optional parameter specifies the interpolation method to
        use when the desired quantile lies between two data points
        ``i < j``:
            * linear: ``i   (j - i) * fraction``, where ``fraction``
              is the fractional part of the index surrounded by ``i``
              and ``j``.
            * lower: ``i``.
            * higher: ``j``.
            * nearest: ``i`` or ``j``, whichever is nearest.
            * midpoint: ``(i   j) / 2``.
  

Если вы выберете «выше», вы получите то, что хотите

Комментарии:

1. не уверен, что ‘higher’ — это действительно то, чего хочет Пепино, поскольку вы все еще не получаете распределение 25% / 75%

2. А если нет, то метод выдает неверный результат, который опасен для пользователей метода … это на самом деле моя главная мысль. Я знаю, что получаю правильный ответ с помощью np.квантиль (x, 0.25, интерполяция = «нижний») = 366.

Ответ №2:

Как заявил @SamProell, существуют разные соглашения для вычисления центилей, как вы можете видеть здесь с вычислительными методами квартиля (американский способ). Здесь у нас четное количество данных, поэтому давайте придерживаться первого метода и попробуем посмотреть, как мы будем делать это «вручную».

Сначала отсортируйте данные:

 > x2=np.sort(x)
> print(x2)
array([324, 324, 327, 328, 330, 334, 334, 336, 341, 342, 342, 344, 345,
       346, 349, 349, 352, 353, 354, 354, 355, 355, 358, 359, 361, 361,
       370, 374, 377, 386])
  

Затем разделите данные на две половины:

 > x2_low = x2[:int(len(x2)/2)]
array([324, 324, 327, 328, 330, 334, 334, 336, 341, 342, 342, 344, 345,
       346, 349])
> x2_up = x2[int(len(x2)/2):]
array([349, 352, 353, 354, 354, 355, 355, 358, 359, 361, 361, 370, 374,
       377, 386])
  

Наконец, найдите медиану (то есть значение, сокращающее ваши данные пополам). Здесь лежит выбор как len(x2_low)=15 . Вы могли бы сказать, что медиана x2_low является его 8-м значением (индекс 7 в python), тогда:

 > q = x2_low[int(len(x2_low)/2)]
336
> len(x2_low[x2_low<q])
7
> len(x2_low[x2_low>q])
7
  

это также то, что np.median(x2_low) вернуло бы, или даже q=np.percentile(x2,25,interpolation='lower') . Но вы все равно получите:

 > len(x[x<q])/len(x)
0.2333333333334
  

Поскольку ваше количество данных не кратно 4. Теперь все зависит от того, чего вы хотите достичь, вот результаты, которые вы можете получить для всех параметров интерполяции:

linear : значение по умолчанию, вы получили его в своем вопросе

lower : смотрите выше

higher :

 > q=np.percentile(x,25,interpolation='higher')
341
> len(x[x>q])/len(x)
0.7
> len(x[x<q])/len(x)
0.26666666666666666
  

nearest :

 > q=np.percentile(x,25,interpolation='nearest')
336
> len(x[x>q])/len(x)
0.7333333333333333
> len(x[x<q])/len(x)
0.23333333333333334
  

и, наконец midpoint :

 > q=np.percentile(x,25,interpolation='midpoint')
> len(x[x>q])/len(x)
0.7333333333333333
> len(x[x<q])/len(x)
0.26666666666666666
  

Все зависит от того, что вы хотите сделать с этим впоследствии. Для получения дополнительной информации о различных методах вычисления ознакомьтесь с документацией numpy.

Комментарии:

1. @SamProell Для правильного определения вам нужно использовать «<=» и «>=» при выполнении теста определенного квантиля. В этом случае np.квантиль (x, 0.25, интерполяция = «lower») выдает правильный результат, 366, где 26% составляют <= 366, а 76% >= 366, следовательно, правильный результат в этом наборе данных. Я хочу сказать, что стандартная версия этого метода (без «interpolation =»lower»») выдает неверный результат. И «интерполяция =»ниже») работает правильно только для p<0,5, для p> 0,5 это снова приводит к неправильному результату (и нужно использовать «интерполяция =»выше»»).

2. @PepinoDoMar Это не неправильный результат, а другой способ определения квантиля. Код работает так, как задумано, см. Определение в numpy документации. Если «нижняя» интерполяция дает то, что вы хотите, почему вы считаете, что в numpy есть ошибка?

3. Я мог бы добавить, что если бы существовал только один способ определения вычисления квантиля, numpy программисты не потрудились бы реализовать разные типы интерполяции 😉