Проставление рейтинга строчкам в pandas dataframe с изменяемым шагом

Имеется датафрейм(пример):

import pandas as pd
d = {'stores': ['AG21', 'AG41', 'AG85', 'AG45', 
'AG31', 'AS25', 'AR81', 'AA43',
'AG21', 'AD83', 'AA36', 'AG55',
'AT58', 'AD11', 'AH32', 'AE17'], 
'linear': [430, 145 , 120, 180,
250, 250, 250, 320,
376, 390, 420, 580,
350, 190, 125, 390]}
df = pd.DataFrame(data=d)
df = df.sort_values(by='linear')
df

В колонку linear заходят значения от расчетов из другого кода и сортируются по возрастанию.

Затем, вручную, строчкам проставляются рейтинги от 1 до 6. К примеру, к датафрейму выше(к колонке linear), вручную бы проставились примерно такие рейтинги(раскиданы на глаз)

import pandas as pd
d = {'stores': ['AG21', 'AG41', 'AG85', 'AG45', 
'AG31', 'AS25', 'AR81', 'AA43',
'AG21', 'AD83', 'AA36', 'AG55',
'AT58', 'AD11', 'AH32', 'AE17'], 
'linear': [430, 145 , 120, 180,
250, 250, 250, 320,
376, 390, 420, 580,
350, 190, 125, 390]}
df = pd.DataFrame(data=d)
df = df.sort_values(by='linear')
df['ratings'] = 1,1,1,2,2,3,3,3,4,4,4,5,5,5,5,6
df

Они приблизительно ставятся в зависимости от схожести значений с верхними строчками(после сортировки) с небольшим шагом и если шаг сильно отличается, то рейтинг возрастает.

НО не во всех случаях есть шестой или пятый рейтинг. Пример ниже:

import pandas as pd
d = {'stores': ['AG21', 'AG41', 'AG85', 'AG45', 
'AG31', 'AS25', 'AR81', 'AA43'],
'linear': [330, 145 , 120, 180,
250, 150, 185, 320]}
df = pd.DataFrame(data=d)
df = df.sort_values(by='linear')
df['ratings'] = 1,2,2,3,3,4,5,5
df

Подскажите, пожалуйста, каким способом можно автоматизировать процесс расставления этих рейтингов?


Ответы (1 шт):

Автор решения: strawdog

Если у вас нужные значения отсортированы, и вам просто нужно разбить их на квантильные сегменты, то сделать это можно просто:

df["cat"] = pd.qcut(df["linear"], 6, labels=False).values+1

df:

   stores  linear  cat
2    AG85     120    1
14   AH32     125    1
1    AG41     145    1
3    AG45     180    2
13   AD11     190    2
4    AG31     250    2
5    AS25     250    2
6    AR81     250    2
7    AA43     320    4
12   AT58     350    4
8    AG21     376    4
9    AD83     390    5
15   AE17     390    5
10   AA36     420    6
0    AG21     430    6
11   AG55     580    6

Если у вас нет каких-то категорий (как 3 в данном примере), значит ни одно из значений при данных условиях не попадает в третью секстиль. Если вам нужно железно получить 6 категорий, то тогда предлагаю сначала самостоятельно определить интервалы, а потом восользоваться методом pd.cut:

intervals = np.linspace(df["linear"].min(), df["linear"].max(), endpoint=True, num=7)
print(intervals) # [120. 196.66666667 273.33333333 350. 426.66666667 503.33333333 580. ]
df["cat"] = pd.cut(df["linear"], intervals, labels=False, include_lowest=True)+1

df:

   stores  linear  cat
2    AG85     120    1
14   AH32     125    1
1    AG41     145    1
3    AG45     180    1
13   AD11     190    1
4    AG31     250    2
5    AS25     250    2
6    AR81     250    2
7    AA43     320    3
12   AT58     350    3
8    AG21     376    4
9    AD83     390    4
15   AE17     390    4
10   AA36     420    4
0    AG21     430    5
11   AG55     580    6

UPDATE

Если нужно поделить датафрейм просто на приблизительно равные части, ***с потерей статистической значимости***, можно сделать простую группировку:

d = {'stores': ['AG21', 'AG41', 'AG85', 'AG45', 'AG31', 'AS25', 'AR81', 'AA43'], 'linear': [330, 145 , 120, 180, 250, 150, 185, 320]}
df = pd.DataFrame(data=d)
df = df.sort_values(by='linear')
chunks = 6
df["cat"] = df.groupby(np.arange(len(df))//(len(df)/chunks)).ngroup()+1
print(df)

df:

  stores  linear  cat
2   AG85     120    1
1   AG41     145    1
5   AS25     150    2
3   AG45     180    3
6   AR81     185    4
4   AG31     250    4
7   AA43     320    5
0   AG21     330    6​
→ Ссылка