데이터 분석의 핵심은 코드 암기가 아니라 데이터에 적절한 질문을 던지는 거예요. 전체 데이터의 describe와 corr를 통해 기초 통계량과 상관관계를 파악하고, groupby, crosstab, pivot_table을 활용해 그룹별 집계를 수행하는 실전 흐름을 알아봐요. 또한 시각화와 기계학습의 목적에 맞춰 stack, unstack, melt를 사용해 데이터 형태를 넓게 또는 길게 변환하는 필수 전처리 기법까지 한 번에 정리해 드릴게요.
목차
- 시작하며: 분석의 첫걸음, 데이터에 질문 던지기
- 전체 그림 파악하기: 기초 통계량과 상관관계
- 그룹별로 쪼개고 분석하기: groupby 기초와 주의할 오류
- 원형을 유지하는 그룹 연산: transform과 filter
- 직관적인 교차 요약: crosstab과 pivot_table
- 분석과 시각화를 위한 데이터 모양 변환: stack, unstack, melt
- 자주 묻는 질문
시작하며: 분석의 첫걸음, 데이터에 질문 던지기
데이터를 받자마자 무작정 코드를 치기 시작하는 분들 많으시죠? 저도 처음엔 그랬어요. 데이터 분석을 배울 때 가장 흔하게 하는 실수가 바로 파이썬이나 판다스의 함수 문법부터 외우려고 하는 거예요. 하지만 진짜 분석은 코드를 짜는 게 아니라, 데이터에 끊임없이 질문을 던지는 것부터 시작해요.
예를 들어 데이터 분석 입문용으로 가장 유명한 타이타닉 생존자 데이터를 분석한다고 해볼게요. 단순히 전체 승객의 평균 나이를 구하는 게 최종 목표는 아닐 거예요. “어떤 조건이 승객의 생존율을 높였을까?” 혹은 “여성과 아이들이 정말 먼저 구조되었을까?” 같은 구체적인 가설을 먼저 세워야 해요.
가설을 세웠다면 이를 검증하기 위해 데이터를 성별, 연령대, 객실 등급 등 그룹별로 묶어보고, 피벗테이블을 활용해 엑셀처럼 직관적인 교차 검증을 해나가는 거예요. 이렇게 명확한 목적을 가지고 접근해야 groupby나 crosstab 같은 집계 함수들을 왜 써야 하는지, 언제 써야 하는지 제대로 이해할 수 있어요.
전체 그림 파악하기: 기초 통계량과 상관관계
데이터를 처음 열었을 때 가장 먼저 해야 할 일은 무엇일까요? 바로 데이터의 전체적인 분포와 변수들 사이의 관계를 파악하는 거예요. 마치 숲을 먼저 보고 나무를 보는 것과 같죠. 이때 describe()와 corr() 함수를 자주 사용해요.
describe()는 데이터의 개수, 평균, 표준편차, 최솟값, 최댓값, 그리고 사분위수 등을 한 번에 요약해서 보여줘요. 데이터의 대략적인 형태를 잡는 데 아주 훌륭한 도구예요. corr()는 변수들이 서로 같이 움직이는 경향성, 즉 상관관계를 -1에서 1 사이의 숫자로 보여준답니다.
기본 통계 분석 흐름
데이터프레임을 불러온 후 describe()를 통해 숫자형 데이터의 요약 정보를 확인해요.
평균과 중간값을 비교하여 극단적인 이상치가 있는지 가늠해 봐요.
corr()를 이용해 어떤 변수끼리 강하게 연결되어 있는지 흐름을 잡아요.
평균과 중간값을 같이 확인하는 습관을 들이는 게 정말 중요해요. 소득이나 나이 같은 데이터에는 항상 아주 높거나 낮은 극단값(이상치)이 존재할 수 있거든요. 극단값이 하나만 섞여 있어도 평균은 크게 왜곡되지만, 데이터를 순서대로 줄 세웠을 때 정가운데 있는 값인 중간값은 영향을 훨씬 덜 받아요.
📌 Note
상관관계에서 꼭 기억해야 할 점이 있어요. 상관관계는 절대 인과관계가 아니에요. 여름에 아이스크림 판매량과 익사 사고 수가 같이 늘어난다고 해서 아이스크림이 익사 사고를 유발하는 건 아니잖아요? 단순히 두 수치가 같이 변한다는 의미로만 해석해야 오류를 피할 수 있어요.
그룹별로 쪼개고 분석하기: groupby 기초와 주의할 오류
“성별로 생존율을 구해줘”, “객실 등급별 평균 나이를 알고 싶어” 이런 질문이 머릿속에 떠오르면 주저 없이 groupby를 꺼내면 돼요. 데이터 분석 실무에서 가장 많이 쓰이는 함수 중 하나예요.
groupby는 데이터를 특정 기준에 따라 쪼개고(Split), 각 그룹에 함수를 적용한 뒤(Apply), 다시 하나의 표로 합치는(Combine) 3단계 원리로 동작해요. 처음엔 복잡해 보일 수 있지만, 이 원리만 이해하면 어떤 복잡한 조건도 쉽게 처리할 수 있답니다.
집계 과정에서 결측치(NaN)는 자동으로 계산에서 제외돼요. 아주 똑똑하죠? 하지만 주의할 점도 있어요. 이름이나 티켓 번호 같은 문자열 데이터에 억지로 평균(mean)을 적용하려고 하면 어떻게 될까요? 최신 버전의 Pandas에서는 얄짤없이 TypeError를 발생시켜요.
⚠️ Warning
과거에는 판다스가 알아서 문자열을 무시하고 계산해 줬지만, 이제는 명시적인 에러를 뱉어내요. 문자열이 섞인 데이터프레임에서 그룹 집계를 할 때는 반드시 함수 안에 numeric_only=True 파라미터를 넣어 숫자형 열만 계산하라고 알려줘야 해요.
이 groupby 오류 해결 방법을 미리 알아두면 실무에서 당황할 일이 확 줄어들 거예요.
원형을 유지하는 그룹 연산: transform과 filter
일반적으로 groupby를 쓰면 그룹의 개수만큼 행이 팍 줄어든 요약 결과를 받게 돼요. 예를 들어 890명의 승객 데이터를 3개의 객실 등급으로 묶어버리면 결과는 딱 3줄만 나오는 식이죠. 전체 요약본을 볼 때는 이게 맞아요.
그런데 분석을 하다 보면 “각 승객의 데이터 옆에, 그 승객이 속한 객실 등급의 평균 요금을 적어주고 싶다”는 생각이 들 때가 있어요. 개별 데이터가 전체 그룹에서 어느 정도 위치인지 비교할 기준점이 필요한 거죠. 이때 원본 데이터의 행 개수를 그대로 유지해 주는 함수가 바로 transform이에요.
여기에 더해 filter를 사용하면 우리가 원하는 특정 조건을 만족하는 그룹 전체만 깔끔하게 남길 수 있어요.
요약 결과만 딱 필요하다면 일반 groupby를, 원본 데이터 행마다 통계값을 하나씩 붙여서 머신러닝의 파생 변수로 쓰고 싶다면 transform을 쓴다고 구분해 두면 절대 헷갈리지 않아요. 엑셀의 VLOOKUP 기능을 떠올리면 이해가 확 되실 거예요.
직관적인 교차 요약: crosstab과 pivot_table
두 개 이상의 범주형 데이터(예를 들어 성별과 생존 여부)가 어떻게 분포되어 있는지 한눈에 보고 싶을 때는 crosstab이 정말 편해요. 빈도수나 비율을 빠르게 구할 수 있거든요. 성별로 100%를 기준 잡고 비율을 보면 남성과 여성의 생존 차이가 극명하게 드러나요.
반면, 특정 범주별로 숫자 데이터(요금이나 나이 등)의 평균, 최댓값, 합계 등을 엑셀의 피벗테이블처럼 멋진 리포트 형태로 뽑고 싶다면 pivot_table을 사용해요.
어떤 상황에 무엇을 쓸지 헷갈린다면 이렇게 기억하세요. 개수나 비율 분포가 궁금하면 crosstab, 숫자 값의 평균/합계를 엑셀 표처럼 보고 싶다면 pivot_table, 더 복잡하고 유연한 연산을 직접 제어하고 싶다면 groupby를 쓰는 거예요.
💡 Tip
pivot_table을 쓸 때 margins=True 옵션을 넣으면 표의 끝에 총합(All) 행과 열이 자동으로 추가돼요. 보고서나 대시보드 데이터를 만들 때 별도로 합계를 계산할 필요가 없어서 시간 단축에 아주 유용해요.
분석과 시각화를 위한 데이터 모양 변환: stack, unstack, melt
데이터의 형태는 크게 열이 많고 행이 적은 넓은 형태(Wide)와 행이 많고 열이 적은 긴 형태(Long)로 나뉘어요. 사람이 눈으로 보는 보고서나 엑셀 파일은 넓은 형태가 보기 편하죠. 하지만 컴퓨터가 기계학습 알고리즘을 돌리거나 Seaborn 같은 시각화 라이브러리에 데이터를 집어넣기에는 긴 형태가 훨씬 유리해요.
그래서 분석 목적에 맞게 넓은 표를 긴 표로 바꾸거나, 그 반대로 조작하는 파이썬 데이터 전처리 과정을 꼭 거쳐야 해요. 이 변환을 도와주는 핵심 삼총사가 바로 stack, unstack, melt랍니다.
melt()는 고정할 열을 잡아두고 나머지 열 이름을 하나의 변수 값으로 싹 다 녹여버리는 역할을 해요. 마치 얼음을 녹여서 물로 만드는 것처럼 넓은 데이터를 길게 늘어뜨리죠. 반면 stack()은 표의 위쪽(컬럼)에 있던 라벨을 왼쪽(인덱스)으로 차곡차곡 쌓아 올려서 데이터를 세로로 길게 만들어요.
unstack()은 이와 반대로 왼쪽에 겹쳐 있던 인덱스를 위쪽으로 쫙 펼쳐서 데이터를 가로로 넓게 만들어 줘요. 시각화 라이브러리를 다룰 때 x축이나 범례(legend)에 데이터를 어떻게 매핑할지 고민하면서 데이터 형태를 자유자재로 바꾸는 연습을 많이 해보세요.
자주 묻는 질문
Q. 숫자형 데이터가 아닌 열이 포함된 상태에서 mean() 등의 통계 함수를 쓰면 왜 자꾸 TypeError가 발생하나요?
Pandas 최신 버전부터는 비수치형(문자열 등) 데이터에서 집계 함수를 묵시적으로 무시하지 않고 명시적인 에러를 발생시키도록 업데이트되었어요. groupby 시 aggfunc나 mean() 안에 numeric_only=True 파라미터를 추가하면 숫자형 열만 계산하도록 명시할 수 있어서 오류를 아주 쉽게 해결할 수 있답니다.
Q. groupby로 데이터를 집계할 때 결측치(NaN)는 어떻게 처리되나요?
다행히 판다스의 집계 연산(sum, mean 등)은 기본적으로 결측치(NaN)를 철저하게 무시하고 계산해요. 예를 들어 5개의 데이터 중 1개가 NaN이라면 남은 4개의 데이터만 가지고 진짜 평균을 구해주니 크게 걱정하지 않으셔도 돼요.
Q. 일반 groupby 통계값과 transform을 사용한 결과는 어떤 차이가 있나요?
가장 큰 차이는 결과물의 ‘행 개수’에 있어요. 일반 groupby는 데이터를 그룹화하여 딱 그룹의 개수만큼 행을 줄여 요약본을 만들어내요. 반면, transform은 계산된 그룹 통계값을 원본 데이터의 각 행 위치에 그대로 매핑해 주죠. 그래서 원본 데이터프레임과 완벽히 동일한 행 개수를 유지하게 되고, 주로 파생 변수를 덧붙일 때 유용하게 쓰여요.
Q. stack과 unstack을 적용했을 때 데이터 모양이 어떻게 변하는지 직관적으로 잘 그려지지 않아요.
처음엔 당연히 헷갈릴 수 있어요. stack은 열(Columns)에 있는 라벨을 인덱스(Index) 쪽으로 끌어내려 ‘쌓아 올려서’ 데이터를 세로로 길게(Long) 만든다고 생각하세요. 반대로 unstack은 겹쳐 있는 인덱스를 열 쪽으로 ‘쫙 펼쳐서’ 데이터를 가로로 넓게(Wide) 만들어요. 본문의 실행 결과처럼 컬럼이 하나씩 인덱스 쪽으로 내려온다고 상상하면 훨씬 이해하기 쉽답니다.