TL;DR
Использование
sz = temp['INCOME'].size-1
temp['PCNT_LIN'] = temp['INCOME'].rank(method='max').apply(lambda x: 100.0*(x-1)/sz)
INCOME PCNT_LIN
0 78 44.444444
1 38 11.111111
2 42 22.222222
3 48 33.333333
4 31 0.000000
5 89 55.555556
6 94 66.666667
7 102 77.777778
8 122 100.000000
9 122 100.000000
Ответ
Это действительно очень просто, если вы понимаете механику.Когда вы ищете процентиль балла, у вас уже есть баллы в каждом ряду.Единственным оставшимся шагом является понимание того, что вам нужен процентиль чисел, которые меньше или равны выбранному значению.Это именно то, что делают параметры kind = 'слабый' из scipy.stats.percentileofscore()
и method = 'средний' из DataFrame.rank()
.Чтобы инвертировать его, запустите Series.quantile()
с interpolation = 'lower' .
Итак, поведение scipy.stats.percentileofscore()
, Series.rank()
и Series.quantile()
равно соответствует, см. Ниже:
In[]:
temp = pd.DataFrame([ 78, 38, 42, 48, 31, 89, 94, 102, 122, 122], columns=['INCOME'])
temp['PCNT_RANK']=temp['INCOME'].rank(method='max', pct=True)
temp['POF'] = temp['INCOME'].apply(lambda x: scipy.stats.percentileofscore(temp['INCOME'], x, kind='weak'))
temp['QUANTILE_VALUE'] = temp['PCNT_RANK'].apply(lambda x: temp['INCOME'].quantile(x, 'lower'))
temp['RANK']=temp['INCOME'].rank(method='max')
sz = temp['RANK'].size - 1
temp['PCNT_LIN'] = temp['RANK'].apply(lambda x: (x-1)/sz)
temp['CHK'] = temp['PCNT_LIN'].apply(lambda x: temp['INCOME'].quantile(x))
temp
Out[]:
INCOME PCNT_RANK POF QUANTILE_VALUE RANK PCNT_LIN CHK
0 78 0.5 50.0 78 5.0 0.444444 78.0
1 38 0.2 20.0 38 2.0 0.111111 38.0
2 42 0.3 30.0 42 3.0 0.222222 42.0
3 48 0.4 40.0 48 4.0 0.333333 48.0
4 31 0.1 10.0 31 1.0 0.000000 31.0
5 89 0.6 60.0 89 6.0 0.555556 89.0
6 94 0.7 70.0 94 7.0 0.666667 94.0
7 102 0.8 80.0 102 8.0 0.777778 102.0
8 122 1.0 100.0 122 10.0 1.000000 122.0
9 122 1.0 100.0 122 10.0 1.000000 122.0
Теперь в столбце PCNT_RANK
вы получите соотношение значений, которые меньше или равны значению в столбце INCOME
.Но если вам нужно «интерполированное» соотношение, оно находится в столбце PCNT_LIN
.И поскольку вы используете Series.rank()
для вычислений, это довольно быстро и за 255 миллионов вы за несколько секунд обработаете вас.
Здесь я объясню, как вы получаете значение от использования quantile()
с linear
интерполяция:
temp['INCOME'].quantile(0.11)
37.93
Наши данные temp['INCOME']
имеют только десять значений.Согласно формуле из вашей ссылки на Wiki ранг 11-го процентиля равен
rank = 11*(10-1)/100 + 1 = 1.99
Усеченная часть rank равна 1, что соответствует значению31, и значение с рангом 2 (то есть следующим бином) равно 38. Значение fraction
является дробной частью ранга .Это приводит к результату:
31 + (38-31)*(0.99) = 37.93
Для самих значений часть fraction
должна быть нулевой, поэтому очень легко выполнить обратный расчет, чтобы получить процентиль:
p = (rank - 1)*100/(10 - 1)
Надеюсь, я прояснил это.