파이썬 pandas 라이브러리로 계산을 빠르게 하는 법: SQL을 배워라
- 개요
저는 다양한 데이터를 분석, 시각화할 때 파이썬을 사용합니다.
정확히는 데이터 분석, 시각화의 과정에서 pandas, numpy, matplotlib 등 다양한 파이썬 라이브러리를 쓰는거죠.
이 중 pandas는 정형 데이터를 읽고, 전처리, 후처리 작업에 쓰입니다.
요즘 데이터리안에서 SQL을 배워보니 SQL에서 쓰는 명령어를 알게 되었고 대체로 이 기능은 pandas에 구현되어 있고 빠릅니다.
-속도 비교 1: 기상 자료
1. 자료 설명 및 목표 설정
첫번째 속도 비교로 기상관측 일평균 자료를 다운로드 받았습니다.
일별로 다양한 기상 변수가 저장되어 있고, 기간은 2007년부터 2025년까지입니다.
자료의 행은 7000~8000줄 정도 됩니다.
이 자료로 연평균 평균기온을 구해봅시다.
참고로 가장 오른쪽을 보시면 datetime이라는 열은 '일시' 열값을 시간 자료형으로 쓰고 싶어 pd.to_datetime()으로 바꾼 것입니다.
2. pandas의 groupby 사용 (SQL 명령어와 유사)
groupby를 연별로 해야하므로 'datetime' 열에서 연도 정보를 'YYYY'라는 새로운 열로 저장합니다.
그리고 'YYYY'값에 따라 group를 나누고 평균을 하면 연평균 온도가 됩니다.
최종결과물은 list 타입으로 저장했습니다.
주피터 노트북에서는 %timeit 함수이름을 치면 함수가 돌아가는 시간을 알려주고 -n 1000은 1000번 돌린 시간을 확인하라는 뜻입니다.
def sql_like(df):
df['YYYY'] = df['datetime'].dt.year
df_year = df[['YYYY', '평균기온(°C)']].groupby(by='YYYY').mean()
temp_year = df_year['평균기온(°C)'].tolist()
"""
%timeit -n 1000 sql_like(df)의 결과
1.31 ms ± 9.03 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
"""
1000번 돌려서 평균 1.31 ms(마이크로 초)가 걸립니다.
3. pandas에서 제공하는 SQL과 유사한 방법을 쓰지 않음
def not_sql_like(df):
temp_year = []
syr, fyr = 2007, 2025
for year in range(syr, fyr):
temp_year.append(df['평균기온(°C)'][(df['datetime'] >= f'{year}-01-01')
& (df['datetime'] <= f'{year}-12-31')].mean())
"""
%timeit -n 1000 not_sql_like(df)의 결과
6.31 ms ± 189 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
"""
제가 groupby를 몰랐을 땐 특정 연도의 1월 1일부터 12월 31일까지 조건문을 만들어서 연평균 기온을 구했었습니다.
1000번 돌려서 평균 6.31 ms (마이크로 초)가 걸립니다.
대충 4~5배 느리네요.
- 속도 비교 2: 메이플스토리 랭킹 자료
1. 자료 설명 및 목표 설정
이 자료는 넥슨 API로 받았습니다.
메이플스토리 랭킹조회 API에서는 날짜별로 순위(ranking) 및 캐릭터 이름, 경험치, 직업 등등 자료를 얻을 수 있습니다.
참고로 자료의 행은 6,000,000(600만)줄이고 2024년 12월 20일부터 2025년 4월 18일까지 120일 동안 1등부터 50000등 자료(120 * 50000 = 600만)가 있습니다.
목표는 그냥 일별 270레벨 이상 유저수가 궁금하다고 쳐봅시다.
2. pandas의 groupby, agg 사용(SQL 명령어와 유사)
# count_270이라는 열이름으로 저장됨
result = data.groupby('date').agg(count_270=('character_level', lambda x: (x >= 270).sum()))
위에서 말한 자료를 pandas DataFrame 형태로 data 변수에 저장했습니다.
위에서 작성 코드의 pandas 문법을 SQL 문법과 비교해봅시다(SQL로는 안 돌려봐서 문법이 틀렸을 수 있음).
pandas | SQL |
groupby('date') | GROUP BY date |
agg(count_270=('character_level', lambda x: (x >= 270).sum())) | SUM( CASE WHEN character_level >= 270 THEN 1 ELSE 0) |
코드가 돌아간 시간은 0.3초로 count_270열을 시계열로 그려보면 아래와 같습니다.
# 간단한 시계열 확인
result['count_270'].plot()
3. pandas에서 제공하는 SQL과 유사한 방법을 쓰지 않음
# 레벨 270이상인 경우만 filtering
result_filter = data[data['character_level'] >= 270]
count_dict = {}
# count_dict의 key 설정, 만약 레벨 270 이상 유저가 없으면
# 해당 날짜 dictionary key가 없으므로 따로 선언
for date in result_filter['date'].unique():
count_dict[date] = 0
# 이미 270 이상인 행만 추출했으므로 'date'의 값을 key로 1씩 더하면 됨
for date in result_filter['date']:
count_dict[date] += 1
최대한 pandas에서 제공하는 메서드를 쓰지 않고 같은 작업을 하는 코드를 작성했습니다.
코드가 돌아간 시간은 4.3초로 시계열을 그려보면 결과가 같습니다.
같은 작업을 수행했는데도 10배 이상 느려졌습니다.
# 간단한 시계열 그리기
# dictionary로 저장했으므로 pandas.DataFrame()으로 변환
result = pd.DataFrame.from_dict(count_dict, orient='index', columns=['count_270'])
result['count_270'].plot()
- 빠른 이유
글의 시작은 pandas에 있는 SQL 문법과 유사한 메서드를 써서 빠른 것처럼 설명했지만 진짜 빠른 이유는 단순히 SQL과 유사하기 때문은 아닙니다.
SQL 문법과 유사한 pandas의 메서드는 대체로 벡터화 및 C언어로 구현되어 있어 빠릅니다.
- 결론
같은 결과를 내더라도 SQL 문법과 유사한 코드는 4~5배 이상 빠릅니다.
(groupby만 썼기 때문에 다른 방법은 이 정도로 빠르지 않을 수도 있음)
그 이유는 SQL과 관련되기보다 pandas의 특정 벡터화, C언어를 사용해서 빠른 것이지만...
SQL 지식이 있었다면 바로 '이런 게 없었나?'하고 찾아봤을 겁니다.
이 글을 쓰게 된 동기도 사실은
pandas로 데이터 분석을 하다가 계산 코드가 너무 느렸기 때문입니다.
제가 짠 코드를 chatGPT한테 최적화 해달라고 한 뒤 그 결과를 보니 '이거 완전 SQL이랑 비슷하잖아? 근데 더 빠르네?'
요즘 우연히 데이터리안에서 SQL 강의를 듣고 있어서 바로 이런 생각이 들었습니다.
제가 SQL을 먼저 배웠다면 SQL 스타일로 코드를 작성했을 것 같습니다.
이제는 chatGPT 같은 LLM에게 물어보면 알아서 최적화된 코드를 짜주니까 그냥 이런 게 있다고만 알면 되는 세상이지만 이런 지식을 알고 모르고에 따라 작업을 더 빨리 할 수도 있고, 면접에서 좀 아는 척?을 해서 긍정적인 이미지를 줄 수 있지 않을까요.