Python Pandas : rank (순위, 순위 매기기, rank, ranking, DataFrame ranking, DataFrame rank)
pandas의 rank() method는 특정 column을 기준으로 ranking을 매겨줍니다.
Syntax
rank(ascending={True, False},
method={'min', 'max', 'dense', 'first', 'average'},
pct={True, False},
na_option={'keep', 'top', 'bottom},
numeric_only={True, False})
- ascending (default = True)
True -> ranking을 매길 때 오름차순으로 정렬하여 rank를 매김. 따라서 원본 데이터가 더 작은 값일수록 더 1위에 가까운 rank를 얻게 됨.
False -> ranking을 매길 때 내림차순으로 정렬하여 rank를 매김. 따라서 원본 데이터가 더 큰 값일수록 더 1위에 가까운 rank를 얻게 됨.
- method (devault = average)
ranking을 어떻게 나타내줄지를 결정하는 옵션입니다.
min -> 동일한 rank일 경우 숫자가 더 작은 rank(= 1위에 가까운 rank)를 return
max -> 동일한 rank일 경우 숫자가 더 큰 rank(= 1위로부터 먼 rank)를 return
dense -> 동일한 rank 뒤에 나오는 rank를 바로 +1을 더한 rank로 표시함. (동일한 rank 다음 나오는 rank를 건너뛰고 표시하지 않음.)
first -> 동일한 rank를 같은 순위로 표시하지 않고, 원본 data에서 더 위쪽에 있는 행에 숫자가 더 작은 rank(= 1위에 가까운 rank)를 부여함. 따라서 이 옵션은 rank에 따른 row number를 매길 수 있음.
average -> first 옵션과 동일하지만 동일한 수치를 가져서 동일 rank인 행들에 대해 rank의 평균값을 부여함.
- pct (default = False)
True -> rank의 표시를 1위, 2위, 3위, ... 등이 아닌 전체를 1(= 100%)로 하여 ranking %로 나타냄.
False -> rank의 표시를 1위, 2위, 3위, ... 등처럼 정수 등수로 표시.
- na_option (default = keep)
keep -> NaN 값에 대해서는 rank값을 부여하지 않고 NaN으로 표시함.
top -> NaN 값에 대해서 가장 상위 rank (= 1위에 가까운) rank를 부여함.
bottom -> NaN 값에 대해서 가장 하위 rank (= 1위로부터 먼) rank를 부여함.
- numeric_only (default = False)
True -> 숫자 데이터에 대해서만 rank를 매김.
False -> 숫자 데이터 뿐 아니라 문자 등 숫자 데이터가 아닌 다른 type의 데이터가 섞여있어도 rank method를 적용함.
설명만 보면 무슨 소린지 잘 이해가 되지 않을 수 있습니다.
예시를 봅시다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=False,
na_option='bottom')
df_test = df_test.sort_values(by=['rank'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank
16 5 10.0 1.0
12 4 10.0 1.0
15 5 55.0 3.0
14 5 80.0 4.0
2 2 100.0 5.0
13 5 100.0 5.0
8 3 150.0 7.0
9 3 180.0 8.0
5 3 200.0 9.0
3 2 300.0 10.0
6 3 300.0 10.0
4 2 500.0 12.0
10 4 580.0 13.0
0 1 1000.0 14.0
1 1 2000.0 15.0
7 3 NaN 16.0
11 4 NaN 16.0
위 예시의 결과를 보면 rank 컬럼이 생겼습니다.
df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=False,
na_option='bottom')
col1 col2 rank
16 5 10.0 1.0
12 4 10.0 1.0
15 5 55.0 3.0
14 5 80.0 4.0
2 2 100.0 5.0
13 5 100.0 5.0
8 3 150.0 7.0
9 3 180.0 8.0
5 3 200.0 9.0
3 2 300.0 10.0
6 3 300.0 10.0
4 2 500.0 12.0
10 4 580.0 13.0
0 1 1000.0 14.0
1 1 2000.0 15.0
7 3 NaN 16.0
11 4 NaN 16.0
- df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(
이 말은 col2 컬럼의 값을 기준으로 rank method를 적용한다는 의미이며, 결과로 return되는 rank값을 df_test의 rank column에 삽입하겠다는 의미입니다.
- asending=True
이 값은 col2 값을 오름차순 정렬하여 가장 위쪽에 있는 값일수록 더 상위 rank(= 더 1위에 가까운 rank)를 부여하겠다는 의미입니다.
- method='min'
기본적으로 우리가 보는 일반적인 ranking처럼 rank를 매깁니다..
결과를 보면 상위부터 1위이며, col2값이 10으로 동일한 값을 경우 둘 다 1이라는 rank를 가지게 됩니다.
그리고 그 다음인 55는 3위를 할당받게 됩니다.
- pct=False
rank를 %가 아닌 정수 순위로 표현합니다.
그래서 1위, 2위, 3위, ... 등등으로 표시되었습니다.
- na_option='bottom'
bottom은 col2에 NaN 값이 존재할 경우 NaN값에 가장 하위의 rank를 부여하겠다는 의미입니다.
그래서 위 예시를 보면 NaN 값을 가진 행은 16위로 가장 낮은 rank를 받았습니다.
이제 option을 살짝씩 조절해봅시다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(ascending=False,
method='min',
pct=False,
na_option='bottom')
df_test = df_test.sort_values(by=['rank'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank
1 1 2000.0 1.0
0 1 1000.0 2.0
10 4 580.0 3.0
4 2 500.0 4.0
3 2 300.0 5.0
6 3 300.0 5.0
5 3 200.0 7.0
9 3 180.0 8.0
8 3 150.0 9.0
2 2 100.0 10.0
13 5 100.0 10.0
14 5 80.0 12.0
15 5 55.0 13.0
12 4 10.0 14.0
16 5 10.0 14.0
7 3 NaN 16.0
11 4 NaN 16.0
- ascending=False
asending을 False로 설정했으므로 col2 컬럼의 값을 내림차순하여 더 위에 있을수록 더 상위의 rank(= 1위에 가까운 rank)를 부여합니다.
그래서 col2 컬럼에서 가장 큰 값을 가지는 2000에 rank 1이 부여되었습니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank_min'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=False,
na_option='bottom')
df_test.loc[:, 'rank_max'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='max',
pct=False,
na_option='bottom')
df_test = df_test.sort_values(by=['rank_min'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank_min rank_max
16 5 10.0 1.0 2.0
12 4 10.0 1.0 2.0
15 5 55.0 3.0 3.0
14 5 80.0 4.0 4.0
2 2 100.0 5.0 6.0
13 5 100.0 5.0 6.0
8 3 150.0 7.0 7.0
9 3 180.0 8.0 8.0
5 3 200.0 9.0 9.0
3 2 300.0 10.0 11.0
6 3 300.0 10.0 11.0
4 2 500.0 12.0 12.0
10 4 580.0 13.0 13.0
0 1 1000.0 14.0 14.0
1 1 2000.0 15.0 15.0
7 3 NaN 16.0 17.0
11 4 NaN 16.0 17.0
- method='max'
method를 max로 설정하면 동일한 값을 가져서 동일한 rank를 부여받아야할 때 더 낮은 rank를 부여합니다.
가장 상단에 있어서 가장 높은 rank를 받아야하는 행은 col2에서 10을 가진 2개의 행입니다.
이 행의 값이 달랐다면 1위 2위를 부여받아야겠지만 동률이라 1 또는 2를 부여받게되죠.
위 예시에서는 보기 좋게 min과 max를 동시에 나타내었습니다.
가장 위쪽 2개 행을 보면 min으로 설정했을 때에는 두 행이 모두 rank 1을 부여받았지만
max로 설정했을 때에는 두 행이 모두 rank 2를 부여받았습니다.
사실 두개 행의 값이 달랐으면 1위, 2위를 각각 나눠가져야했으나 두 개 행의 값이 10으로 같아서 동일한 rank를 부여받아야합니다.
여기서 min으로 설정할 경우 1위, 2위 중 더 적은 숫자의 rank인 1을 부여하고,
max로 설정할 경우 1위, 2위 중 더 큰 숫자의 rank인 2를 부여하게 됩니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank_min'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=False,
na_option='bottom')
df_test.loc[:, 'rank_desne'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='dense',
pct=False,
na_option='bottom')
df_test = df_test.sort_values(by=['rank_min'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank_min rank_desne
16 5 10.0 1.0 1.0
12 4 10.0 1.0 1.0
15 5 55.0 3.0 2.0
14 5 80.0 4.0 3.0
2 2 100.0 5.0 4.0
13 5 100.0 5.0 4.0
8 3 150.0 7.0 5.0
9 3 180.0 8.0 6.0
5 3 200.0 9.0 7.0
3 2 300.0 10.0 8.0
6 3 300.0 10.0 8.0
4 2 500.0 12.0 9.0
10 4 580.0 13.0 10.0
0 1 1000.0 14.0 11.0
1 1 2000.0 15.0 12.0
7 3 NaN 16.0 13.0
11 4 NaN 16.0 13.0
- method='dense'
dense 옵션은 동률 rank 뒤에 나오는 rank를 어떻게 표시할지를 결정합니다.
rank_min과 rank_dense를 비교해봅시다.
가장 위의 2개 행은 모두 1위로 동일한 rank를 가집니다.
rank_min의 경우 그 다음 나오는 행은 3입니다. 당연히 2개 행이 공동 1위이니까 그 다음 rank는 3위가 나와야겠죠.
하지만 dense는 공동 순위 다음 나오는 rank를 건너뛰지 않고 2로 부여하게 됩니다.
그래서 rank_dense 컬럼을 보시면 가장 위 2개 컬럼에 1위라는 rank가 부여되어있고, 그 다음 행의 rank는 3이 아닌 2입니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank_first'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='first',
pct=False,
na_option='bottom')
df_test.loc[:, 'rank_average'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='average',
pct=False,
na_option='bottom')
df_test = df_test.sort_values(by=['rank_first'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank_first rank_average
12 4 10.0 1.0 1.5
16 5 10.0 2.0 1.5
15 5 55.0 3.0 3.0
14 5 80.0 4.0 4.0
2 2 100.0 5.0 5.5
13 5 100.0 6.0 5.5
8 3 150.0 7.0 7.0
9 3 180.0 8.0 8.0
5 3 200.0 9.0 9.0
3 2 300.0 10.0 10.5
6 3 300.0 11.0 10.5
4 2 500.0 12.0 12.0
10 4 580.0 13.0 13.0
0 1 1000.0 14.0 14.0
1 1 2000.0 15.0 15.0
7 3 NaN 16.0 16.5
11 4 NaN 17.0 16.5
- method='first'
first는 rank 개념보단 행번호 개념이라고 생각하면 쉽습니다..
df_test.loc[:, 'col2'].rank(ascending=True, -> col2 기준으로 오름차순 한 후 존재하는 DataFrame에 가장 위에 존재하는 행부터 1을 부여한 후 그 아래로 2, 3, 4, ... 등등의 rank를 부여합니다.
위 예시를 보면 감이 올겁니다.
가장 상단에 있는 2개 행은 col2값이 10으로 동일하지만 1, 2로 다른 rank를 가지게 됩니다.
그리고 index를 보면 1위가 12, 2위가 16으로 기존 DataFrame에서 더 위에 존재할수록 더 상위의(= 더 1위에 가까운) rank를 얻게 됩니다.
- method='average'
average 옵션은 first 옵션으로부터 생성된 rank값을 동일한 값을 가진 행에 대해서 평균내서 보여줍니다.
가장 상단에 있는 2개 행은 col2값이 10으로 동일합니다. 다만 rank_first의 결과로서는 각각 1, 2를 부여받게 되었죠.
average는 이렇게 동일한 값을 가진 행에 대하여 rank_frst의 결과를 평균내서 1.5로 부여하게 됩니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=True,
na_option='bottom')
df_test = df_test.sort_values(by=['rank'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank
16 5 10.0 0.058824
12 4 10.0 0.058824
15 5 55.0 0.176471
14 5 80.0 0.235294
2 2 100.0 0.294118
13 5 100.0 0.294118
8 3 150.0 0.411765
9 3 180.0 0.470588
5 3 200.0 0.529412
3 2 300.0 0.588235
6 3 300.0 0.588235
4 2 500.0 0.705882
10 4 580.0 0.764706
0 1 1000.0 0.823529
1 1 2000.0 0.882353
7 3 NaN 0.941176
11 4 NaN 0.941176
- pct=True
pct 옵션을 True로 설정한 경우 위처럼 총 개수 대비 각 rank값의 %를 rank로서 return합니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=False,
na_option='top')
df_test = df_test.sort_values(by=['rank'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank
11 4 NaN 1.0
7 3 NaN 1.0
16 5 10.0 3.0
12 4 10.0 3.0
15 5 55.0 5.0
14 5 80.0 6.0
2 2 100.0 7.0
13 5 100.0 7.0
8 3 150.0 9.0
9 3 180.0 10.0
5 3 200.0 11.0
3 2 300.0 12.0
6 3 300.0 12.0
4 2 500.0 14.0
10 4 580.0 15.0
0 1 1000.0 16.0
1 1 2000.0 17.0
- na_option='top'
na_option을 top으로 설정하면 NaN 값에 가장 높은(= 1위에 가까운) rank를 부여합니다.
위 예시를 보면 NaN값이 1위라는 rank를 가진 것을 볼 수 있습니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank'] = df_test.loc[:, 'col2'].rank(ascending=True,
method='min',
pct=False,
na_option='keep')
df_test = df_test.sort_values(by=['rank'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank
12 4 10.0 1.0
16 5 10.0 1.0
15 5 55.0 3.0
14 5 80.0 4.0
2 2 100.0 5.0
13 5 100.0 5.0
8 3 150.0 7.0
9 3 180.0 8.0
5 3 200.0 9.0
3 2 300.0 10.0
6 3 300.0 10.0
4 2 500.0 12.0
10 4 580.0 13.0
0 1 1000.0 14.0
1 1 2000.0 15.0
7 3 NaN NaN
11 4 NaN NaN
- na_option='keep'
na_option을 keep으로 설정하면 NaN 값에는 rank를 부여하지 않고 NaN으로 표시합니다.
위 예시를 보면 col2에서 NaN 값에 대한 rank는 NaN으로 표시된 것을 볼 수 있습니다.
rank method는 groupby와 함께 사용해서 마치 window rank function처럼 사용할 수 있습니다.
import pandas as pd
import numpy as np
dict_test = {
'col1': [1, 1,
2, 2, 2,
3, 3, 3, 3, 3,
4, 4, 4,
5, 5, 5, 5],
'col2': [1000, 2000,
100, 300, 500,
200, 300, np.nan, 150, 180,
580, np.nan, 10,
100, 80, 55, 10]
}
df_test = pd.DataFrame(dict_test)
print(df_test)
df_test.loc[:, 'rank'] = df_test.groupby(by=['col1'])['col2'].rank(ascending=True,
method='min',
pct=False,
na_option='bottom')
df_test = df_test.sort_values(by=['col1', 'rank'], ascending=True, ignore_index=False, inplace=False)
print(df_test)
-- Result
col1 col2
0 1 1000.0
1 1 2000.0
2 2 100.0
3 2 300.0
4 2 500.0
5 3 200.0
6 3 300.0
7 3 NaN
8 3 150.0
9 3 180.0
10 4 580.0
11 4 NaN
12 4 10.0
13 5 100.0
14 5 80.0
15 5 55.0
16 5 10.0
col1 col2 rank
0 1 1000.0 1.0
1 1 2000.0 2.0
2 2 100.0 1.0
3 2 300.0 2.0
4 2 500.0 3.0
8 3 150.0 1.0
9 3 180.0 2.0
5 3 200.0 3.0
6 3 300.0 4.0
7 3 NaN 5.0
12 4 10.0 1.0
10 4 580.0 2.0
11 4 NaN 3.0
16 5 10.0 1.0
15 5 55.0 2.0
14 5 80.0 3.0
13 5 100.0 4.0
위 예시를 보면 rank가 동일한 col1 값을 가진 행들의 세트 내에서 매겨진 것을 볼 수 있습니다.
df_test.loc[:, 'rank'] = df_test.groupby(by=['col1'])['col2'].rank(ascending=True,
method='min',
pct=False,
na_option='bottom')
먼저 DataFrame에 groupby method를 적용합니다.
by=['col1']이라고 적었으므로 col1 에서 동일한 값을 가진 행끼리 group지어서 rank를 적용하겠다는 의미입니다.