
데이터 분석 고수들이 숨겨두고 쓰는 Pandas 꿀팁 BEST 5
데이터 분석을 하다 보면 read_csv나 기본적인 인덱싱 정도는 누구나 금방 익히게 됩니다. 하지만 데이터의 크기가 커지고 전처리 로직이 복잡해질수록, "어떻게 하면 더 빠르고, 읽기 쉬운 코드를 짤 수 있을까?" 라는 고민에 빠지게 됩니다.
오늘은 주니어 단계를 넘어 '고수'들의 코드를 보면 공통적으로 발견되는 Pandas 핵심 꿀팁 5가지를 정리했습니다. 여러분의 코드를 한 단계 업그레이드해 보세요.
1. 가독성의 끝판왕: Method Chaining (.assign 활용)
분석 코드를 작성하다 보면 중간 변수(df_temp, df_filtered 등)가 무수히 생성되어 메모리를 낭비하고 흐름을 끊는 경우가 많습니다. 고수들은 Method Chaining을 통해 이를 해결합니다.
😢Bad Case (중간 변수 남발)
import pandas as pd
df = pd.read_csv('data.csv')
df = df[df['price'] > 100] # 필터링
df['price_log'] = np.log(df['price']) # 컬럼 생성
df = df.sort_values('date') # 정렬
😍Good Case (Method Chaining) .assign()을 사용하면 새로운 컬럼을 체인 안에서 즉시 생성할 수 있습니다.
import pandas as pd
import numpy as np
# 물 흐르듯 이어지는 논리
df_clean = (pd.read_csv('data.csv')
.query('price > 100') # 1. 필터링
.assign(price_log = lambda x: np.log(x['price'])) # 2. 컬럼 생성 (lambda 활용)
.sort_values('date') # 3. 정렬
)
Point: 코드가 위에서 아래로 물 흐르듯 읽히며, 불필요한 중간 변수가 생성되지 않습니다.
2. 복잡한 조건문은 이제 그만: .query()
데이터를 필터링할 때 대괄호([])와 괄호(())가 겹겹이 쌓이면 코드를 해석하기 어렵습니다. .query()를 사용하면 SQL처럼 직관적인 필터링이 가능합니다.
😢Bad Case
# 괄호 지옥... 가독성이 떨어짐
subset = df[(df['region'] == 'Seoul') & (df['sales'] > 5000) & (df['category'] != 'A')]
😍Good Case
target_region = 'Seoul'
min_sales = 5000
# 외부 변수는 @를 붙여 참조 가능
subset = df.query('region == @target_region and sales > @min_sales and category != "A"')
Point: 따옴표 처리가 간결해지고, 특히 조건이 3개 이상일 때 압도적인 가독성을 자랑합니다.
3. 메모리 다이어트: category 타입 활용
수백만 건의 데이터를 다룰 때 MemoryError를 겪어본 적이 있으신가요? 문자열(object) 데이터 중 중복되는 값(Cardinality가 낮은 값)이 많다면 category 타입으로 변환하는 것만으로도 메모리를 획기적으로 줄일 수 있습니다.
예시: 성별, 지역, 요일 등
# 데이터 생성 (100만 행)
df_big = pd.DataFrame({'grade': ['A', 'B', 'C', 'A'] * 250000})
# 변환 전 메모리 확인
print(df_big['grade'].memory_usage(deep=True))
# 결과: 약 58,000,128 bytes (약 58MB)
# category 변환
df_big['grade'] = df_big['grade'].astype('category')
# 변환 후 메모리 확인
print(df_big['grade'].memory_usage(deep=True))
# 결과: 약 1,000,424 bytes (약 1MB) -> 약 58배 절약!
Point: 단순히 타입만 바꿨을 뿐인데 메모리 사용량이 극적으로 감소하고, groupby 연산 속도도 빨라집니다.
4. 집계 후 원본 유지하기: groupby + transform
그룹별 평균이나 합계를 구한 뒤, 이를 다시 원본 데이터프레임에 붙이고 싶을 때가 있습니다. 보통 groupby 후 merge를 사용하는데, 코드가 길어집니다. transform을 쓰면 원본의 인덱스를 유지하면서 집계 값을 채워줍니다.
상황: 각 직원의 판매 실적이 '팀 평균' 대비 얼마나 높은지 알고 싶을 때
df = pd.DataFrame({
'team': ['A', 'A', 'B', 'B', 'B'],
'sales': [100, 150, 200, 230, 180]
})
# 팀별 평균 매출을 계산하여 'team_avg' 컬럼 생성
df['team_avg'] = df.groupby('team')['sales'].transform('mean')
# 팀 평균 대비 실적 비율 계산
df['performance_ratio'] = df['sales'] / df['team_avg']
print(df)
출력 결과:
team sales team_avg performance_ratio
0 A 100 125.0 0.800000
1 A 150 125.0 1.200000
2 B 200 203.3 0.983607
...
Point: merge 없이도 그룹 연산 결과를 원본 행 개수 그대로 매핑할 수 있습니다. 결측치 채우기(fillna + transform)에도 매우 유용합니다.
5. 리스트가 들어있는 셀 다루기: .explode()
크롤링 데이터나 로그 데이터를 다루다 보면, 한 셀 안에 리스트 형태(['apple', 'banana'])로 데이터가 들어있는 경우가 있습니다. 이를 분석하려면 행을 쪼개야 하는데, 과거에는 반복문을 썼지만 이제는 .explode() 한 방이면 해결됩니다.
예시: 한 주문에 포함된 여러 상품 리스트 분리
df = pd.DataFrame({
'order_id': [1, 2],
'items': [['apple', 'pear'], ['banana']]
})
# 리스트를 개별 행으로 분리
df_exploded = df.explode('items')
print(df_exploded)
출력 결과:
order_id items
0 1 apple
0 1 pear
1 2 banana
Point: 한 행을 리스트의 요소 개수만큼 복제하여 'Long Format' 데이터로 만들어줍니다. 이후 groupby 집계가 훨씬 수월해집니다.
마치며
Pandas는 아는 만큼 보이고, 활용하는 만큼 퇴근 시간이 빨라집니다. 오늘 소개한 5가지 팁(Method Chaining, query, category, transform, explode)만 실무에 적용해 봐도 코드가 훨씬 전문적으로 변할 것입니다.
지금 바로 여러분의 노트북(Notebook)을 열어 적용해 보세요!
'IT > Pandas' 카테고리의 다른 글
| Pandas 로 4분위수 및 4분위범위(IQR) 쉽게 구하기 (0) | 2020.01.17 |
|---|---|
| Pandas DataFrame 컬럼 이름 쉽게 변경 (0) | 2019.12.11 |
| Pandas DataFrame 이나 Series 를 txt, csv, tsv 파일로 깔끔하게 저장하기 (0) | 2019.11.27 |
댓글