본문으로 건너뛰기
김신건의 로그

[Pandas] nlargest / nsmallest / rank

· 수정 · 📖 약 1분 · 381자/단어 #python #pandas #sorting #rank
Pandas nlargest, Pandas nsmallest, Pandas rank, Pandas nlargest / rank, Top-N pandas

정의

  • nlargest(n, cols) : 상위 N 개 행 (sort_values + head 보다 빠름)
  • nsmallest(n, cols) : 하위 N 개 행
  • rank() : 각 원소의 순위 (1, 2, 3, …)

rank method 비교 시각화

flowchart TD
    INPUT["값: 75, 88, 92, 92, 95"] --> AVG["method='average'\n75→1, 88→2, 92→3.5, 92→3.5, 95→5"]
    INPUT --> MIN["method='min'\n75→1, 88→2, 92→3, 92→3, 95→5"]
    INPUT --> MAX["method='max'\n75→1, 88→2, 92→4, 92→4, 95→5"]
    INPUT --> DENSE["method='dense'\n75→1, 88→2, 92→3, 92→3, 95→4"]
    INPUT --> FIRST["method='first'\n75→1, 88→2, 92→3, 92→4, 95→5"]

    AVG --> SQL_RANK["SQL RANK()"]
    DENSE --> SQL_DENSE["SQL DENSE_RANK()"]
    FIRST --> SQL_ROW["SQL ROW_NUMBER()"]

nlargest / nsmallest

df.nlargest(5, 'salary')
df.nsmallest(3, 'age')
df.nlargest(5, ['salary', 'age'])   # 다중 키 (salary 우선, 동률 시 age)
python
import pandas as pd
df = pd.DataFrame({
  'name': ['A','B','C','D','E','F'],
  'score': [88, 92, 75, 92, 95, 81],
})
print(df.nlargest(3, 'score'))
결과
  name  score
4    E     95
1    B     92
3    D     92
namescore
4E95
1B92
3D92

keep 옵션

df.nlargest(3, 'score', keep='first')   # 동률 시 먼저 등장 우선 (기본)
df.nlargest(3, 'score', keep='last')    # 나중 등장 우선
df.nlargest(3, 'score', keep='all')     # 동률 모두 포함 (3 개 초과 가능)

왜 sort + head 보다 빠른가

nlargest 는 N 크기의 힙으로 부분 정렬, O(n log k). 전체 정렬은 O(n log n).

  • n = 1,000,000, k = 10 일 때 차이 큼

rank

각 원소에 순위를 매긴다.

df['rank'] = df['score'].rank(ascending=False)
python
import pandas as pd
s = pd.Series([88, 92, 75, 92, 95])
print(s.rank(method='min'))           # 동률은 가장 작은 순위
print(s.rank(method='dense'))         # 동률은 같은 순위, 다음은 +1
print(s.rank(method='average'))       # 동률은 평균
print(s.rank(ascending=False).tolist())   # 내림차순 (큰 값이 1)
결과
0    2.0
1    3.0
2    1.0
3    3.0
4    5.0
dtype: float64
0    2.0
1    3.0
2    1.0
3    3.0
4    4.0
dtype: float64
0    2.0
1    3.5
2    1.0
3    3.5
4    5.0
dtype: float64
[4.0, 2.5, 5.0, 2.5, 1.0]

method 옵션 비교

method92, 92 인 경우다음 순위SQL 대응
average3.5, 3.55-
min3, 35RANK()
max4, 45-
dense3, 34DENSE_RANK()
first3, 45ROW_NUMBER()

그룹별 순위 (SQL 의 ROW_NUMBER OVER PARTITION BY)

df['rank_in_dept'] = df.groupby('dept')['salary'].rank(ascending=False)

Pandas groupby + rank.

python
import pandas as pd
df = pd.DataFrame({
  'dept': ['Dev','Dev','HR','HR','Dev'],
  'name': ['A','B','C','D','E'],
  'salary': [5000, 7000, 4000, 6000, 6000],
})
df['rank'] = df.groupby('dept')['salary'].rank(method='dense', ascending=False)
cols = ['dept', 'name', 'salary', 'rank']
print(df[cols])
결과
  dept name  salary  rank
0  Dev    A    5000   3.0
1  Dev    B    7000   1.0
2   HR    C    4000   2.0
3   HR    D    6000   1.0
4  Dev    E    6000   2.0

분위수

df['quartile'] = pd.qcut(df['score'], 4, labels=['Q1','Q2','Q3','Q4'])
df['percentile'] = df['score'].rank(pct=True)   # 0.0~1.0

rank(pct=True) 는 백분위 (0~1).

실전 패턴

Top-N 필터 (그룹별)

# 부서별 연봉 상위 2명
df['rank'] = df.groupby('dept')['salary'].rank(method='min', ascending=False)
top2 = df[df['rank'] <= 2]

증가율 Top-N

df['growth'] = df['revenue'].pct_change()
growth_cols = ['name', 'revenue', 'growth']
top5_growth = df.nlargest(5, 'growth')[growth_cols]

순위 변동 추적

# 이번 달 순위 - 지난 달 순위
df['rank_change'] = df['rank_prev'] - df['rank_curr']
df.nlargest(5, 'rank_change')   # 가장 많이 오른 항목

분위수 기반 세그먼트

python
import pandas as pd
df = pd.DataFrame({'score': [45, 60, 72, 85, 91, 55, 78, 63, 88, 50]})
df['tier'] = pd.qcut(df['score'], q=3, labels=['하위','중위','상위'])
print(df.groupby('tier', observed=True)['score'].agg(['min','max','count']))
결과
       min  max  count
tier
하위    45   60      4
중위    63   78      3
상위    85   91      3

성능

# nlargest vs sort + head
import timeit

# sort_values + head: O(n log n)
# nlargest: O(n log k), k << n 일 때 크게 유리

# 1M 행에서 Top-10 추출
# nlargest: ~0.05s
# sort_values + head: ~0.3s

# 다중 컬럼 정렬은 nlargest 에서도 내부 sort 사용 가능
df.nlargest(10, ['col_a', 'col_b'])   # col_a 우선, 동률 시 col_b

자주 만나는 함정

1. rank 의 기본 method

rank() 의 기본은 'average', 동률을 평균값으로 둔다. 정수 순위를 원하면 method='min' 또는 'dense'.

IMPORTANT

rank() 기본 method='average' 는 동률 시 float 값을 반환한다 (3.5 등). 정수 순위가 필요하면 method='min' (SQL RANK) 또는 method='dense' (SQL DENSE_RANK) 를 명시.

2. NaN 처리

s.rank(na_option='keep')      # NaN 은 NaN (기본)
s.rank(na_option='top')       # NaN 을 가장 높은 순위 (가장 큰 값처럼)
s.rank(na_option='bottom')    # NaN 을 가장 낮은 순위 (가장 작은 값처럼)

3. nlargest 의 다중 키

df.nlargest(3, ['a', 'b'])
# 'a' 가 더 우선, 'b' 는 동률일 때만 결정

4. ascending 방향 혼동

df['rank'] = df['score'].rank(ascending=False)
# ascending=False 면 높은 점수가 낮은 순위 번호 (1위, 2위...)
# ascending=True (기본) 면 낮은 값이 1위

WARNING

rank(ascending=True) 가 기본값이다. 점수가 높을수록 1위가 되게 하려면 반드시 ascending=False. 이를 빠뜨리면 순위가 반전된다.

관련 위키

이 글의 용어 (5개)
[Pandas] agg / aggregatepandas
정의 는 여러 집계 함수를 한 번에 적용 한다. , , 모두에서 사용 가능. 는 같은 함수의 별칭. agg 처리 흐름 사용 상황 | 상황 | 패턴 | |:---|:---| | 전…
[Pandas] cut / qcutpandas
정의 - : 값 기반 binning (구간을 직접 지정) - : 빈도 기반 binning (분위수로 같은 크기) 연속형 변수를 범주형으로 변환. ML 의 feature engin…
[Pandas] groupbypandas
정의 는 데이터를 그룹으로 나누고 (split), 각 그룹에 함수를 적용 (apply), 결과를 합쳐 (combine) 새 DataFrame 으로 만드는 split-apply-c…
[Pandas] idxmax / idxminpandas
정의 - : 최댓값의 index 라벨 반환 - : 최솟값의 index 라벨 반환 / 이 값 을 반환한다면, / 은 그 값이 있는 index 라벨 을 반환한다. "MAX 인 행의 …
[Pandas] sort_values / sort_indexpandas
정의 - : 컬럼 값 기준 정렬 - : index (행 또는 열 라벨) 기준 정렬 기본은 오름차순, 로 내림차순. 사용 상황 - 단일 컬럼 정렬: 날짜, 점수, 금액 등 단순 순…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기