Preprocesamiento de Datos 🧹
실제 데이터는 깨끗하지 않습니다. 데이터 전 처리는 분석 가능한 형태로 데이터를 정제하는 필수 과정입니다.
¿Qué es el Preprocesamiento de Datos?
데이터 전처리는 원시 데이터를 분석이나 머신러닝에 적합한 형태로 변환하는 과정입니다.
Tareas Principales
- 결측치 처리: 누락된 데이터 다루기
- 중복 제거: 중복된 레코드 제거
- 데이터 타입 변환: 적절한 타입으로 변경
- 이상치 처리: 비정상적인 값 처리
- 데이터 통합: 여러 데이터 소스 결합
Información
데이터 과학자들은 업무 시간의 80%를 데이터 전처리에 사용한다고 합니다!
Manejo de Valores Faltantes
Verificar Valores Faltantes
import pandas as pd
import numpy as np
# 샘플 데이터 (결측치 포함)
data = {
'name': ['Alice', 'Bob', 'Charlie', None, 'Eve'],
'age': [25, None, 35, 28, 32],
'salary': [50000, 60000, None, 55000, None],
'department': ['IT', 'HR', 'IT', None, 'HR']
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# Verificar Valores Faltantes
print("\n=== 결측치 개수 ===")
print(df.isnull().sum())
# 결측치 비율
print("\n=== 결측치 비율 ===")
print((df.isnull().sum() / len(df) * 100).round(2))
# 결측치가 있는 행
print("\n=== 결측치 포함 행 ===")
print(df[df.isnull().any(axis=1)])
Eliminar Valores Faltantes
# 결측치가 있는 행 전체 제거
df_dropped_rows = df.dropna()
print("행 제거 후:", df_dropped_rows.shape)
# 결측치가 있는 열 제거
df_dropped_cols = df.dropna(axis=1)
print("열 제거 후:", df_dropped_cols.shape)
# 특정 열의 결측치만 제거
df_dropped_subset = df.dropna(subset=['name', 'age'])
print("name, age 결측치 제거:", df_dropped_subset.shape)
# 모든 값이 결측치인 행만 제거
df_dropped_all = df.dropna(how='all')
# 최소 N개 이상의 값이 있는 행만 유지
df_dropped_thresh = df.dropna(thresh=3) # 최소 3개 값
Rellenar Valores Faltantes
# 특정 값으로 채우기
df_filled = df.fillna(0)
df_filled = df.fillna('Unknown')
# 열별로 다른 값 채우기
df_filled = df.fillna({
'age': df['age'].mean(), # 평균
'salary': df['salary'].median(), # 중앙값
'department': 'Unknown'
})
# 앞/뒤 값으로 채우기 (시계열 데이터)
df_ffill = df.fillna(method='ffill') # 앞 값으로
df_bfill = df.fillna(method='bfill') # 뒤 값으로
# 보간법
df['age'] = df['age'].interpolate() # 선형 보간
고급 결측치 처리
import pandas as pd
import numpy as np
# 샘플 데이터
data = {
'date': pd.date_range('2024-01-01', periods=10),
'temperature': [22, 23, None, 25, 26, None, 28, 29, None, 31],
'humidity': [60, 62, 65, None, 68, 70, None, 75, 77, 80]
}
df = pd.DataFrame(data)
# 그룹별 평균으로 채우기
df['category'] = ['A', 'A', 'B', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
df['temperature'] = df.groupby('category')['temperature'].transform(
lambda x: x.fillna(x.mean())
)
# 시계열 보간
df['temperature'] = df['temperature'].interpolate(method='time')
# KNN 기반 채우기 (scikit-learn 사용)
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=2)
df[['temperature', 'humidity']] = imputer.fit_transform(
df[['temperature', 'humidity']]
)
Procesamiento de Datos Duplicados
중복 확인
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
'age': [25, 30, 25, 35, 30],
'city': ['Seoul', 'Busan', 'Seoul', 'Incheon', 'Busan']
}
df = pd.DataFrame(data)
print("=== 원본 데이터 ===")
print(df)
# 중복 확인
print("\n=== 중복 여부 ===")
print(df.duplicated())
# 중복 개수
print(f"\n중복 행 개수: {df.duplicated().sum()}")
# 중복된 행 보기
print("\n=== 중복된 행 ===")
print(df[df.duplicated(keep=False)])
Eliminar Duplicados
# Eliminar Duplicados (첫 번째 유지)
df_unique = df.drop_duplicates()
print("중복 제거 후:", len(df_unique))
# 마지막 유지
df_unique_last = df.drop_duplicates(keep='last')
# 모두 제거
df_no_duplicates = df.drop_duplicates(keep=False)
# 특정 열 기준 중복 제거
df_unique_name = df.drop_duplicates(subset=['name'])
df_unique_multi = df.drop_duplicates(subset=['name', 'age'])
# 원본 수정
df.drop_duplicates(inplace=True)
Conversión de Tipos de Datos
기본 타입 변환
import pandas as pd
data = {
'id': ['1', '2', '3', '4', '5'],
'price': ['1000', '1500', '2000', '2500', '3000'],
'date': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05'],
'is_active': ['True', 'False', 'True', 'True', 'False']
}
df = pd.DataFrame(data)
print("=== 원본 타입 ===")
print(df.dtypes)
# 숫자로 변환
df['id'] = df['id'].astype(int)
df['price'] = df['price'].astype(float)
# 날짜로 변환
df['date'] = pd.to_datetime(df['date'])
# 불리언으로 변환
df['is_active'] = df['is_active'].map({'True': True, 'False': False})
print("\n=== 변환 후 타입 ===")
print(df.dtypes)
안전한 변환
# 에러 무시하고 변환
df['price'] = pd.to_numeric(df['price'], errors='coerce') # 실패 시 NaN
# 날짜 변환 (에러 처리)
df['date'] = pd.to_datetime(df['date'], errors='coerce')
# 카테고리 타입 (메모리 절약)
df['category'] = df['category'].astype('category')
복잡한 변환
# 문자열에서 숫자 추출
df['price_str'] = ['$1,000', '$1,500', '$2,000']
df['price'] = df['price_str'].str.replace('[$,]', '', regex=True).astype(float)
# 날짜 형식 지정
df['date'] = pd.to_datetime(df['date'], format='%Y/%m/%d')
# 여러 형식 시도
df['date'] = pd.to_datetime(df['date'], infer_datetime_format=True)
Procesamiento de Cadenas
기본 문자열 작업
import pandas as pd
data = {
'name': [' Alice ', 'BOB', 'charlie', 'David'],
'email': ['alice@example.com', 'BOB@EXAMPLE.COM', 'charlie@test.com', 'david@test.com']
}
df = pd.DataFrame(data)
# 공백 제거
df['name'] = df['name'].str.strip()
# 대소문자 변환
df['name_upper'] = df['name'].str.upper()
df['name_lower'] = df['name'].str.lower()
df['name_title'] = df['name'].str.title()
# 이메일 도메인 추출
df['domain'] = df['email'].str.split('@').str[1]
# 특정 문자 포함 여부
df['has_test'] = df['email'].str.contains('test')
# 문자열 길이
df['name_length'] = df['name'].str.len()
print(df)
정규표현식 활용
import pandas as pd
data = {
'phone': ['010-1234-5678', '02-987-6543', '031-555-1234', '010.9999.8888'],
'text': ['가격: 10,000원', '할인가 5,000원', '정상가 20000원', '특가 15,000']
}
df = pd.DataFrame(data)
# 전화번호 형식 통일
df['phone_clean'] = df['phone'].str.replace('[.-]', '', regex=True)
# 숫자만 추출
df['price'] = df['text'].str.extract(r'(\d+,?\d+)')[0]
df['price'] = df['price'].str.replace(',', '').astype(int)
# 특정 패턴 찾기
df['has_discount'] = df['text'].str.contains('할인|특가')
print(df)
텍스트 분할 및 결합
# 문자열 분할
df = pd.DataFrame({'full_name': ['John Doe', 'Jane Smith', 'Bob Johnson']})
df[['first_name', 'last_name']] = df['full_name'].str.split(' ', expand=True)
# 문자열 결합
df['full_name_reversed'] = df['last_name'] + ', ' + df['first_name']
# 여러 열 결합
df['address'] = df['city'] + ', ' + df['state'] + ' ' + df['zip']
Fusión de Datos
merge (SQL JOIN과 유사)
import pandas as pd
# 직원 정보
employees = pd.DataFrame({
'emp_id': [1, 2, 3, 4],
'name': ['Alice', 'Bob', 'Charlie', 'David'],
'dept_id': [10, 20, 10, 30]
})
# 부서 정보
departments = pd.DataFrame({
'dept_id': [10, 20, 30, 40],
'dept_name': ['IT', 'HR', 'Sales', 'Marketing']
})
# Inner Join (교집합)
inner = pd.merge(employees, departments, on='dept_id', how='inner')
print("=== Inner Join ===")
print(inner)
# Left Join (왼쪽 전체)
left = pd.merge(employees, departments, on='dept_id', how='left')
print("\n=== Left Join ===")
print(left)
# Right Join (오른쪽 전체)
right = pd.merge(employees, departments, on='dept_id', how='right')
# Outer Join (합집합)
outer = pd.merge(employees, departments, on='dept_id', how='outer')
# 다른 열 이름으로 조인
df1 = pd.DataFrame({'id': [1, 2], 'value': [10, 20]})
df2 = pd.DataFrame({'key': [1, 2], 'data': [100, 200]})
merged = pd.merge(df1, df2, left_on='id', right_on='key')
concat (단순 결합)
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
# 세로 결합 (행 추가)
vertical = pd.concat([df1, df2], ignore_index=True)
print("=== 세로 결합 ===")
print(vertical)
# 가로 결합 (열 추가)
df3 = pd.DataFrame({'C': [9, 10], 'D': [11, 12]})
horizontal = pd.concat([df1, df3], axis=1)
print("\n=== 가로 결합 ===")
print(horizontal)
join (인덱스 기반)
df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])
df2 = pd.DataFrame({'B': [4, 5, 6]}, index=['a', 'b', 'd'])
# 인덱스 기준 조인
joined = df1.join(df2, how='outer')
print("=== Join ===")
print(joined)
Agrupación (GroupBy)
기본 그룹화
import pandas as pd
import numpy as np
# 판매 데이터
data = {
'date': pd.date_range('2024-01-01', periods=20),
'product': np.random.choice(['A', 'B', 'C'], 20),
'region': np.random.choice(['서울', '부산', '대구'], 20),
'sales': np.random.randint(100, 1000, 20)
}
df = pd.DataFrame(data)
# 제품별 총 매출
product_sales = df.groupby('product')['sales'].sum()
print("=== 제품별 매출 ===")
print(product_sales)
# 여러 집계 함수
product_stats = df.groupby('product')['sales'].agg(['sum', 'mean', 'count'])
print("\n=== 제품별 통계 ===")
print(product_stats)
# 여러 열로 그룹화
region_product = df.groupby(['region', 'product'])['sales'].sum()
print("\n=== 지역별 제품 매출 ===")
print(region_product)
고급 그룹화
# 여러 열에 다른 함수 적용
agg_dict = {
'sales': ['sum', 'mean', 'max'],
'product': 'count'
}
result = df.groupby('region').agg(agg_dict)
print(result)
# 커스텀 함수
def range_func(x):
return x.max() - x.min()
custom_agg = df.groupby('product')['sales'].agg([
('합계', 'sum'),
('평균', 'mean'),
('범위', range_func)
])
print(custom_agg)
# 그룹별 변환
df['sales_mean_by_product'] = df.groupby('product')['sales'].transform('mean')
df['sales_vs_avg'] = df['sales'] - df['sales_mean_by_product']
# 그룹별 랭킹
df['rank_in_product'] = df.groupby('product')['sales'].rank(ascending=False)
피벗 테이블
# 피벗 테이블 생성
pivot = pd.pivot_table(
df,
values='sales',
index='region',
columns='product',
aggfunc='sum',
fill_value=0
)
print("=== 피벗 테이블 ===")
print(pivot)
# 여러 집계
pivot_multi = pd.pivot_table(
df,
values='sales',
index='region',
columns='product',
aggfunc=['sum', 'mean'],
fill_value=0
)