📌 데이터 전처리 개념
✅ 전처리란?
- **데이터 전처리(Data Preprocessing)**는 머신러닝, 통계 분석, 데이터 시각화 등 다양한 분석 작업을 수행하기 전에 데이터를 분석 가능하게 정제하고 구조화하는 단계임.
- 원본 데이터에는 오류, 결측치, 중복, 이상치 등이 존재하며, 이를 사전에 처리하지 않으면 분석 결과의 정확도와 신뢰성이 크게 떨어짐.
- 전처리의 결과물이 곧 분석의 출발점이자 기반임.
✅ 전처리가 중요한 이유
- Garbage In, Garbage Out (GIGO) 원칙: 잘못된 입력 데이터는 잘못된 결과를 낳음.
- 동일한 정보를 여러 형태로 표현한 데이터(예: "남", "남성", "M")는 정규화가 필요함.
- 분석 목적에 맞는 데이터 포맷으로 변환해야 후속 작업이 원활하게 진행됨.
- 전처리를 잘하면 모델 성능, 시각화 품질, 인사이트 도출력이 크게 향상됨.
✅ 전처리 프로세스 4단계
- 목표 설정: 분석의 대상이 되는 문제 또는 질문 정의 (예: "어떤 고객이 이탈할까?")
- 예상 산출물 정의: 보고서, 대시보드, 머신러닝 모델, 예측 결과 등 산출물 형태를 명확히 설정
- AS-IS 분석 (현재 상태 파악): 원시 데이터의 문제점 파악 (중복, 결측, 이상치, 타입 불일치 등)
- TO-BE 설계 (개선 방향): 정제, 필터링, 형변환, 단위 통일, 인코딩 등 방향 설정
💼 실습 과제 정리
🔹 채용공고 분석 숙제
- 총 5개 이상 채용공고를 수집하여 비교 분석
- 자격요건, 우대사항에서 반복 등장하는 단어, 요구 역량, 우대 기술 등을 키워드로 정리
- 회사 브랜드보다는 포지션과 직무 중심으로 정리
🔹 키워드 정리 기준
- 기술: SQL, Python, Tableau, GA, Excel, PowerBI
- 분석 역량: A/B Test, 퍼널 분석, 로그 분석, KPI 정의, 데이터 시각화
- 업무 스킬: 커뮤니케이션, 문제 해결, 협업 능력
🐼 pandas & NumPy 기초
✅ NumPy란?
- Numerical Python의 줄임말로 고속 수치 연산을 위한 라이브러리
- 파이썬 리스트보다 연산이 빠르며 벡터 연산이 가능함
- pandas도 내부적으로 NumPy 기반으로 작동
import numpy as np
a = np.array([1, 2, 3])
print(a * 2)
np.mean(a)
np.zeros(5)
np.nan
np.random.rand(3)
🧩 pandas 구조 이해
✅ Series vs DataFrame
- Series: 1차원 데이터(값 + 인덱스), 하나의 컬럼처럼 사용됨
- DataFrame: 여러 개의 Series가 합쳐진 2차원 표 형태
import pandas as pd
ages = pd.Series([25, 30, 38, 22, 50])
print(type(ages))
✅ DataFrame 생성
data = {
'name': ['김철수', '이영희', '박민수', '최지은'],
'age': [25, 30, 35, 28],
'city': ['서울', '부산', '대구', '인천']
}
df = pd.DataFrame(data)
print(df)
- 딕셔너리 + 리스트 구조로 생성
- 인덱스는 기본적으로 0부터 시작되며 지정 가능
df = pd.DataFrame({
'A': [1, 2, 3],
'B': ['a', 'b', 'c']
}, index=['index1', 'index2', 'index3'])
🔎 데이터 구조 확인
✅ pandas, numpy 버전 확인
import pandas as pd
import numpy as np
print(pd.__version__)
print(np.__version__)
✅ 설치된 패키지 확인
pip list
✅ VSCode 단축키
✅ 주요 데이터 확인 메서드
df.head()
df.tail()
df.info()
df.describe()
df.shape
df.columns
df.index
df.dtypes
🧱 컬럼 및 인덱스 조작
✅ 컬럼 추가/삭제/이름 변경
df['스포츠'] = '축구'
del df['스포츠']
df.rename(columns={'나이': 'age'}, inplace=True)
df.columns = ['이름', '나이', '도시']
✅ 인덱스 조작
df.index = ['1', '2', '3', '4']
df.set_index('이름', inplace=True)
df.reset_index(drop=True)
❗ 결측치 처리
df.isna()
df[df['B'].isna()]
df.dropna()
df.fillna(0)
df.fillna(method='ffill')
🔍 조건 필터링 & Boolean 인덱싱
df[df['성별'] == 'female']
df[(df['성별'] == 'female') & (df['나이'] < 30)]
df[df['등급'].isin([1, 2])]
df[~df['나이'].isna()]
➕ 파생 컬럼 생성
df['Family_Size'] = df['SibSp'] + df['Parch'] + 1
import numpy as np
df['Is_Adult'] = np.where(df['Age'] >= 18, 'Adult', 'Child')
df['리뷰등급'] = df['리뷰수'].apply(lambda x: '많음' if x > 100 else '보통')
📂 파일 입출력
df.to_csv("tips_data.csv", index=False)
pd.read_csv("tips_data.csv")
pd.read_csv("tips_data.csv", index_col=0)
df.to_csv("tips_data.xlsx")
🔁 주요 메서드 요약 및 예시
| 분류 | 메서드 | 설명 | 예시 |
|---|
| 조회 | head() | 상위 5개 행 반환 | df.head() |
| 조회 | tail() | 하위 5개 행 반환 | df.tail() |
| 조회 | info() | 컬럼별 타입 및 결측치 정보 | df.info() |
| 조회 | describe() | 수치형 요약 통계 | df.describe() |
| 조회 | shape | 행과 열 수 반환 | df.shape → (10, 5) |
| 선택 | loc[] | 인덱스 이름 기준 선택 | df.loc['index1'] |
| 선택 | iloc[] | 위치 기준 선택 | df.iloc[0, 1] |
| 선택 | query() | 조건문으로 행 필터 | df.query("age > 30") |
| 선택 | isin() | 특정 값 포함 여부 | df[df['col'].isin([1, 2])] |
| 선택 | between() | 범위 조건 | df[df['age'].between(20, 30)] |
| 조작 | rename() | 컬럼명 변경 | df.rename(columns={'old':'new'}) |
| 조작 | drop() | 행 또는 열 제거 | df.drop('컬럼명', axis=1) |
| 조작 | set_index() | 컬럼을 인덱스로 설정 | df.set_index('이름') |
| 조작 | reset_index() | 인덱스 초기화 | df.reset_index() |
| 조작 | apply() | 함수 적용 | df['리뷰'].apply(lambda x: x+1) |
| 정렬 | sort_values() | 컬럼 기준 정렬 | df.sort_values('age') |
| 정렬 | sort_index() | 인덱스 기준 정렬 | df.sort_index() |
| 결합 | concat() | 데이터프레임 연결 | pd.concat([df1, df2]) |
| 결합 | merge() | 조인 방식으로 병합 | pd.merge(df1, df2, on='key') |
| 결합 | join() | 인덱스를 기준으로 결합 | df1.join(df2) |
| 결측치 | isna() | 결측치 여부 확인 | df.isna() |
| 결측치 | fillna() | 결측치 채우기 | df.fillna(0) |
| 결측치 | dropna() | 결측치 제거 | df.dropna() |
| 결측치 | notna() | 결측치가 아닌 값 | df[df['col'].notna()] |
| 결측치 | ffill() | 결측치를 앞값으로 채움 | df.fillna(method='ffill') |
| 결측치 | bfill() | 결측치를 뒷값으로 채움 | df.fillna(method='bfill') |
| 통계 | mean() | 평균 | df['age'].mean() |
| 통계 | sum() | 합계 | df['매출'].sum() |
| 통계 | std() | 표준편차 | df['나이'].std() |
| 통계 | median() | 중앙값 | df['연봉'].median() |
| 통계 | corr() | 상관계수 | df.corr() |
| 통계 | count() | 값 개수 | df.count() |
| 통계 | value_counts() | 고유값 개수 세기 | df['성별'].value_counts() |
| 변형 | pivot() | 행/열 구조 변경 | df.pivot(index='이름', columns='과목', values='점수') |
| 변형 | pivot_table() | 그룹별 요약 + 피벗 | df.pivot_table(index='반', values='성적', aggfunc='mean') |
| 변형 | melt() | wide → long 형태로 변형 | pd.melt(df, id_vars='이름') |
| 변형 | stack() | 컬럼 → 인덱스 | df.stack() |
| 변형 | unstack() | 인덱스 → 컬럼 | df.unstack() |
| 시계열 | resample() | 시간 간격 재조정 | df.resample('M').mean() |
| 시계열 | asfreq() | 빈도 변경 | df.asfreq('D') |
| 시계열 | rolling() | 이동 평균 등 계산 | df['매출'].rolling(window=3).mean() |
| 시계열 | dt 접근자 | 날짜 정보 추출 | df['날짜'].dt.year |