#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
программисты не потрудились бы реализовать разные типы интерполяции 😉