Python 데이터 전처리 : 기술통계, 결측치 처리, 데이터 타입 변환
이번 글에서는 타이타닉 데이터셋과 간단한 예제 데이터를 바탕으로, 데이터 분석 입문 단계에서 반드시 익혀야 하는 기술통계 분석, 결측치 처리, 데이터 타입 변환 및 날짜 처리를 정리한다. 이 세 가지는 본격적인 시각화, 모델링, 머신러닝에 들어가기 전 데이터의 상태를 이해하고 정리하는 핵심 과정이다.
데이터 분석의 첫 단계는 데이터를 바로 모델에 넣는 것이 아니라, 데이터의 분포·결측치·자료형을 먼저 확인하는 것이다.
describe(), value_counts(), isnull(), fillna(), pd.to_numeric(), pd.to_datetime()은 데이터 전처리에서 가장 자주 사용되는 기본 도구다.1. 기초 통계 분석 - 데이터의 전체적인 모습 파악하기
기초 통계 분석은 데이터가 어떤 형태로 구성되어 있는지 빠르게 이해하는 과정이다. 타이타닉 데이터셋에서는 생존 여부, 객실 등급, 성별, 나이, 동반 가족 수, 요금, 선착장 등의 변수를 활용해 데이터의 분포와 변수 간 관계를 확인할 수 있다.
1-1. describe()로 숫자형 변수 요약하기
describe()는 숫자형 변수의 기본 통계를 한 번에 확인할 수 있는 메서드다. 평균, 표준편차, 최솟값, 최댓값, 사분위수 등을 통해 데이터의 중심과 퍼짐 정도를 파악할 수 있다.
titanic.describe()
- count: 결측치를 제외한 데이터 개수
- mean: 평균값
- std: 표준편차, 데이터가 평균 주변에 얼마나 퍼져 있는지 의미
- min / max: 최솟값과 최댓값
- 25% / 50% / 75%: 사분위수, 데이터 분포의 위치 정보
특히 평균과 중위수인 50% 값을 비교하면 분포가 한쪽으로 치우쳐 있는지 확인할 수 있다. 평균이 중위수보다 크면 일부 큰 값이 평균을 끌어올렸을 가능성이 있고, 반대로 평균이 중위수보다 작으면 작은 값 쪽으로 치우친 분포일 수 있다.
1-2. 상세 백분위수로 이상치 감지하기
기본 사분위수만으로는 상위 극단값을 충분히 확인하기 어렵다. 90%, 95% 백분위수를 추가하면 상위 일부 값이 급격히 커지는지 확인할 수 있어 이상치 탐색에 유용하다.
titanic.describe(percentiles=[.1, .25, .5, .75, .9, .95])
75% 값과 95% 값의 차이가 지나치게 크다면, 상위 5~25% 구간에 큰 값이 몰려 있거나 이상치가 존재할 가능성을 의심할 수 있다.
1-3. 범주형 데이터는 value_counts()로 확인하기
성별, 선착장, 객실 등급처럼 범주로 나뉘는 데이터는 value_counts()를 사용해 빈도를 확인한다. 단순 빈도뿐 아니라 비율도 함께 확인해야 데이터 불균형 여부를 판단할 수 있다.
titanic['Sex'].value_counts()
titanic['Sex'].value_counts(normalize=True)
예를 들어 특정 성별이나 객실 등급이 지나치게 많다면, 생존율 분석이나 모델링 결과가 특정 집단에 편향될 수 있다. 따라서 범주형 데이터는 항상 빈도와 비율을 함께 보는 것이 좋다.
1-4. 왜도와 첨도로 분포 형태 파악하기
평균과 중위수의 비교가 직관적인 방법이라면, 왜도와 첨도는 분포의 형태를 수치로 확인하는 방법이다.
- 왜도 > 0: 오른쪽 꼬리가 긴 분포
- 왜도 < 0: 왼쪽 꼬리가 긴 분포
- 첨도 값이 클수록: 분포가 더 뾰족하고 극단값의 영향이 클 수 있음
- 첨도 값이 작을수록: 분포가 상대적으로 평평함
age_data = titanic['Age'].dropna()
skewness = age_data.skew()
kurtosis = age_data.kurtosis()
1-5. 상관관계 분석으로 변수 간 관계 보기
상관관계 분석은 두 숫자형 변수가 함께 변하는 정도를 확인하는 방법이다. 타이타닉 데이터에서는 생존 여부와 객실 등급, 나이, 요금, 가족 수 등의 관계를 확인할 수 있다.
numeric_cols = ['Survived', 'Pclass', 'Age', 'SibSp', 'Parch', 'Fare']
correlation_matrix = titanic[numeric_cols].corr()
- 0.7 이상: 매우 강한 상관관계
- 0.3~0.7: 강한 상관관계
- 0.1~0.3: 중간 수준의 상관관계
- 0.1 미만: 약한 상관관계
상관관계가 높다고 해서 반드시 인과관계가 있는 것은 아니다. 상관관계는 두 변수가 함께 움직이는 정도를 보여줄 뿐, 한 변수가 다른 변수를 직접적으로 발생시킨다는 의미는 아니다.
2. 결측치 처리 - 비어 있는 데이터를 어떻게 다룰 것인가
결측치는 데이터에 값이 없거나 누락된 상태를 의미한다. 실제 데이터에서는 설문 미응답, 센서 오류, 입력 실수, 시스템 문제, 해당 없음 처리 등 다양한 이유로 결측치가 발생한다. 결측치를 그대로 두면 분석 결과가 왜곡되거나 코드 오류가 발생할 수 있으므로 반드시 확인하고 처리해야 한다.
2-1. 결측치 탐색하기
결측치 처리를 시작하기 전에 먼저 어느 컬럼에 얼마나 많은 결측치가 있는지 확인해야 한다.
missing_counts = titanic.isnull().sum()
missing_ratios = titanic.isnull().sum() / len(titanic) * 100
결측치 개수만 보는 것보다 비율을 함께 보는 것이 더 중요하다. 데이터가 1,000개일 때 결측치 10개와 데이터가 20개일 때 결측치 10개는 의미가 완전히 다르기 때문이다.
2-2. 결측치 제거하기
결측치를 처리하는 가장 단순한 방법은 삭제다. 그러나 삭제는 데이터 손실을 동반하기 때문에 신중하게 사용해야 한다.
# 결측치가 있는 행 전체 삭제
titanic.dropna()
# 결측치가 있는 컬럼 삭제
titanic.dropna(axis=1)
# 특정 컬럼의 결측치가 있는 행만 삭제
titanic.dropna(subset=['Age'])
- 행 삭제: 결측치 비율이 낮고, 데이터가 충분히 많을 때 사용
- 컬럼 삭제: 결측치 비율이 매우 높거나 분석에 중요하지 않은 컬럼일 때 사용
- subset 옵션: 분석에 꼭 필요한 컬럼의 결측치만 제거할 때 사용
일반적으로 결측치 비율이 낮으면 행 삭제를 고려할 수 있고, 결측치 비율이 매우 높은 컬럼은 삭제를 검토할 수 있다. 다만 분석 목적상 중요한 변수라면 단순 삭제보다 대체 방법을 먼저 고려하는 것이 좋다.
2-3. 결측치 대체하기
결측치를 삭제하지 않고 다른 값으로 채우는 방법도 있다. 변수의 성격과 분포에 따라 평균, 중위수, 최빈값, 특정값 등을 사용할 수 있다.
# 평균값 대체
titanic['Age'].fillna(titanic['Age'].mean())
# 중위수 대체
titanic['Age'].fillna(titanic['Age'].median())
# 최빈값 대체
titanic['Embarked'].fillna(titanic['Embarked'].mode()[0])
- 평균값: 정규분포에 가까운 연속형 변수에 적합
- 중위수: 이상치가 많거나 분포가 치우친 변수에 적합
- 최빈값: 범주형 변수에 적합
- 특정값: 비즈니스 로직상 의미 있는 값이 있을 때 사용
평균값 대체는 전체 평균을 유지할 수 있다는 장점이 있지만, 데이터의 분산을 줄여 실제 데이터의 다양성을 낮출 수 있다. 반면 중위수는 이상치의 영향을 덜 받기 때문에 치우친 분포에서는 평균보다 안정적인 선택이 될 수 있다.
2-4. 고급 결측치 처리 방법
시간 순서가 있는 데이터에서는 앞의 값으로 채우는 Forward Fill, 뒤의 값으로 채우는 Backward Fill, 선형 보간법 등을 사용할 수 있다. 다만 이러한 방법은 시계열 데이터처럼 순서가 의미 있는 경우에 적합하다.
# 앞 값으로 채우기
titanic['Age'].ffill()
# 선형 보간
titanic['Age'].interpolate()
타이타닉 데이터는 시계열 데이터가 아니기 때문에 Forward Fill이나 보간법이 항상 적절하다고 보기는 어렵다. 결측치 처리 방법은 데이터의 구조와 분석 목적에 맞게 선택해야 한다.
3. 데이터 타입 변환 및 날짜 처리 - 분석 가능한 형태로 바꾸기
실제 데이터에서는 숫자가 문자열로 저장되어 있거나, 날짜가 object 타입으로 들어오거나, Yes/No 같은 값이 문자열로 저장되는 경우가 많다. 이 상태에서는 계산, 집계, 모델링이 제대로 이루어지지 않기 때문에 데이터 타입을 올바르게 변환해야 한다.
3-1. 데이터 타입 확인하기
데이터 타입 변환의 첫 단계는 현재 컬럼의 자료형을 확인하는 것이다.
df.dtypes
숫자처럼 보이는 값이라도 문자열로 저장되어 있으면 평균, 합계, 상관관계 분석 등을 제대로 수행할 수 없다. 따라서 분석 전에 각 컬럼이 의도한 자료형으로 저장되어 있는지 확인해야 한다.
3-2. 문자열 숫자를 숫자형으로 변환하기
깨끗한 숫자 문자열은 astype()으로 간단히 변환할 수 있다. 하지만 실제 데이터에는 N/A, 공백, 특수문자 등이 섞여 있는 경우가 많기 때문에 주의해야 한다.
# 단순 변환
df['score'].astype(float)
# 변환 불가능한 값은 NaN으로 처리
df['age_clean'] = pd.to_numeric(df['age'], errors='coerce')
pd.to_numeric()의 errors='coerce' 옵션은 변환할 수 없는 값을 자동으로 NaN으로 바꿔준다. 따라서 실제 업무 데이터처럼 지저분한 값이 섞여 있는 경우 astype()보다 안전하게 사용할 수 있다.
3-3. 콤마가 포함된 숫자 처리하기
수입, 매출, 금액 데이터는 50,000처럼 천 단위 구분 콤마가 포함된 문자열로 저장되는 경우가 많다. 이 경우 먼저 콤마를 제거한 뒤 숫자형으로 변환해야 한다.
df['income_clean'] = df['income'].str.replace(',', '').astype(float)
3-4. 날짜 데이터는 pd.to_datetime()으로 변환하기
날짜가 문자열 상태로 저장되어 있으면 날짜 간 차이 계산이나 월별·요일별 분석을 할 수 없다. 날짜 분석을 위해서는 pd.to_datetime()을 사용해 datetime 타입으로 변환해야 한다.
orders_df['order_date_clean'] = pd.to_datetime(orders_df['order_date'])
orders_df['delivery_date_clean'] = pd.to_datetime(orders_df['delivery_date'])
변환 후에는 주문일과 배송일의 차이를 계산하거나, 월·요일·분기 같은 시간 정보를 추출할 수 있다.
# 배송 소요 시간 계산
orders_df['delivery_days'] = (
orders_df['delivery_date_clean'] - orders_df['order_date_clean']
).dt.days
# 월 추출
orders_df['order_month'] = orders_df['order_date_clean'].dt.month
# 요일 추출
orders_df['order_weekday'] = orders_df['order_date_clean'].dt.day_name()
# 분기 추출
orders_df['quarter'] = orders_df['order_date_clean'].dt.quarter
3-5. 날짜 기반 파생 변수 만들기
날짜 데이터는 단순히 날짜 자체를 저장하는 것에서 끝나지 않는다. 분석 목적에 따라 주말 주문 여부, 빠른 배송 여부, 신규 고객 여부, 월초·월말 주문 여부 같은 파생 변수를 만들 수 있다.
# 주말 주문 여부
orders_df['is_weekend_order'] = orders_df['order_date_clean'].dt.dayofweek >= 5
# 3일 이내 배송 여부
orders_df['is_quick_delivery'] = orders_df['delivery_days'] <= 3
# 월초 주문 여부
orders_df['is_month_start'] = orders_df['order_date_clean'].dt.day <= 7
# 월말 주문 여부
orders_df['is_month_end'] = orders_df['order_date_clean'].dt.day >= 25
날짜 데이터는 변환만 해도 분석 가치가 커진다. 날짜 간 차이, 요일, 월, 분기, 주말 여부 등을 만들면 고객 행동, 배송 품질, 매출 패턴 등을 더 쉽게 분석할 수 있다.
최종 정리
데이터 분석의 초반부에서 가장 중요한 것은 데이터를 정확히 이해하고, 분석 가능한 상태로 정리하는 것이다. 기초 통계 분석은 데이터의 전체적인 분포와 변수 간 관계를 파악하는 과정이고, 결측치 처리는 비어 있는 데이터를 삭제하거나 적절한 값으로 채우는 과정이다. 데이터 타입 변환과 날짜 처리는 문자열로 저장된 데이터를 실제 계산 가능한 형태로 바꾸는 과정이다.
즉, 기술통계 → 결측치 확인 및 처리 → 데이터 타입 변환 → 날짜 기반 파생 변수 생성의 흐름은 데이터 분석 전처리의 기본 골격이라고 할 수 있다. 이 과정을 제대로 수행해야 이후 시각화, 인사이트 도출, 머신러닝 모델링의 신뢰도도 높아진다.
좋은 데이터 분석은 복잡한 모델에서 시작되는 것이 아니라, 데이터의 분포를 이해하고, 결측치와 자료형을 올바르게 정리하는 기본 전처리에서 시작된다.
출처
KDT 빅데이터 기반 품질 관리(QA/QC) 양성 과정 6회차
'TIL > Python' 카테고리의 다른 글
| Python 기초 문법 정리 (0) | 2026.07.14 |
|---|---|
| Pandas로 시작하는 데이터 분석 : 데이터 불러오기부터 그룹 분석까지 (1) | 2026.06.05 |
| Python 분석 환경 조성하기 (0) | 2026.06.05 |
| Python 데이터 시각화 확장하기 (0) | 2026.06.04 |
| 데이터를 쉽게 보는 matplotlib 기초 (0) | 2026.06.02 |
