전처리시각화_2일차_1

3eo·2026년 1월 19일

클리닝 4종세트

#시작에 앞서 간단한 tip
〔전처리 예시: 결측치 처리〕
결측치는 데이터에서 값이 비어있는 경우를 말합니다. 결측치가 있으면 분석 결과가 왜곡되거나, 모델 학습이 제대로 되지 않을 수 있어요. 또한 결측치 처리 방법도 상황에 따라 선택이 달라집니다.

• 삭제: 결측치 비율이 낮고, 데이터가 충분할 때
• 평균/중앙값 대체: 수치형 데이터이고, 분포 특성에 맞게 선택
• 최빈값 대체: 범주형 데이터일 때
• 보간법: 시계열 데이터처럼 순서가 있는 경우
• 별도 범주 처리: 결측 자체가 의미 있는 정보일 때 

"어떤 메서드를 쓰는가"보다 "왜 이 방법을 선택했는가? 현재 나의 분석에서 어떤 방법이 적절한가?" 설명할 수 있어야 합니다.

rename / drop — 컬럼명 정리의 본질

rename : 이름 정리

df2 = df2.rename(columns={"qty": "quantity"})

df2에서 "qty"라는 컬럼 이름을 "quantity"라는 이름으로 바꿈
qty → quantity 라는 사전(dictionary)을 준 것.

drop : 분석에서 제외

예를 들어 이런 컬럼이 있다고 해보자

temp_price
debug_flag
memo

이 상태에서 df.mean()을 하면 의미 없는 컬럼까지 평균에 포함될 수 있다.
& 분석은 항상 질문에 답하기 위한 건데, '매출 분석하기'라고 해놓고
매출과 무관한 컬럼이 잔뜩 있으면 분석의 초점이 흐려진다.

👉 원본 데이터를 파괴하지 않으면서 df2라는 분석용 테이블에서만 특정 칼럼을 제외할 때 drop() 사용

df2 = df2.drop(columns=["memo", "temp_col"])

같은 의미의 값들을 컴퓨터가 같은 대상으로 인식하게 만드는 과정
(대소문자나 공백 등으로 인해 의미는 같으나 다르게 쓰인 경우 다른 대상으로 인식)

df2["menu"] = (
    df2["menu"]
    .astype(str)
    .str.strip()
    .str.title()
)

df2["menu"].value_counts()

(1) .astype(str)로 menu 컬럼 내 값들을 문자열로 통일
(2) .str.strip()로 앞뒤 공백 제거(오류 방지)
(3) .tr.title() : 첫 글자 대문자, 나머지 소문자 로 통일
※ 참고: .lower() : 소문자로 통일 / .upper() : 대문자로 통일

(4) df2["menu"].value_counts()로 정리가 잘 되었는지 확인
e.g. menu에 "ice americano", "Ice Americano" 같은 값이 있다면 정리 안 된 것

price 정리 - '문자열'을 '계산 가능한 숫자'로 바꾸기

실무 데이터에서 price는 보통 이렇게 들어온다.

"10,000원"
"5000원"
" 3,200 "
"무료"
None

이런 형태들로는 분석 자체가 불가능하므로 정리가 필요하다.
문자열로 정리(불필요한 내용 제거) → 숫자로 변환

1단계: 문자열로 정리

df2["price"] = (
    df2["price"]
    .astype(str)
    .str.replace(",", "", regex=False)
    .str.replace("원", "", regex=False)
    .str.strip()
)

쉼표 ❌, 통화 단위 ❌, 공백 ❌

  • regex = Fale : ",", "원"처럼 딱 정해진 글자만 지우고 싶을 때
    e.g. 괄호, 대괄호 같은 문자
.str.replace("[", "")

이건 정규표현식 문법이라 에러가 나거나 이상하게 작동한다.
이런 경우를 막기 위해 그냥 '글자 그 자체'로 읽어들이라는 regex = Fale 입력.

2단계 : 숫자로 변환

df2["price"] = pd.to_numeric(df2["price"], errors="coerce")

숫자로 바꿀 수 있으면 바꾸고, 못 바꾸면 NaN으로 처리

  • errors="coerce"가 없으면 에러 때문에 프로그램이 작동하지 않음
    이상한 값은 나중에 처리할테니 일단 지금은 비워두고 코드가 실행되도록 하는 역할

점검

df2["price"].isnull().sum()

숫자로 안 바뀐(비어있는) price가 몇 개인지 파악

  • is.null() : 값이 비어있으면 True, 값이 있으면 False
  • .sum() : True를 1로 세어 몇 개인지 계산

결측치 처리

  • .dropna() : 값이 없는 행을 분석에서 제외
  • .fillna() : 값이 없으면 다른 값으로 대체

✔ dropna를 써야 하는 상황

  • 이 컬럼이 핵심 변수인가? (e.g. price, quantity)
  • 값이 없으면 계산 자체가 불가능한가?
  • 억지로 채우면 의미가 왜곡되는가?
  • 의미를 추측해서 값을 만드는 것보다 확실한 데이터만 쓰는 게 안전한 경우

👉 price가 없으면 매출 계산이 안 된다.
👉 quantity가 없으면 판매량 계산이 안 된다.

clean = df2.dropna(subset=["price", "quantity"]).copy()

✔ fill이 가능한 상황

  • 보조 변수
  • 평균으로 대체해도 해석이 크게 안 변함
  • “없음 = 0” 이 논리적으로 맞는 경우

e.g. 리뷰 수, 할인 금액, 쿠폰 사용 횟수

  • .copy() : df2의 복제품 clean을 만들어 clean을 마음껏 수정해도 df2에 영향 없음
  • .shape : (행의 개수, 열의 개수) 도출. 결측치 처리 후 데이터가 얼마나 많이 줄었는지 확인할 수 있음

✅ 전체 파이프라인 요약

  1. 컬럼명 정리 (rename / drop)
  2. 문자열 정리 (menu, paid 등)
  3. 숫자 정리 (price, quantity)
  4. 결측치 처리 (dropna / fillna)

인사이트

regex=False, errors="coerce" 같은 옵션들의 역할을 제대로 이해하기 전에는 필요성을 느끼지 못했다.
'이걸 안 쓰면 어떻게 되지?', '지금은 잘 되는데, 왜 굳이 쓰는 거지?' 등의 질문을 통해 옵션은 실수를 막기 위한 장치라는 걸 이해했다. 특히 regex=False를 사용해 지금은 차이가 없어 보이지만, 나중에 큰 문제를 만들 수 있는 지점을 미리 차단하는 방식은 실무적인 사고방식에 가깝다는 생각이 들었다.
결측치 처리를 할 때는 단순히 결측치를 채우거나 버리는 행위에 집중하기보다, '이 값이 없으면 지금 이 분석이 성립하는가?'를 늘 생각해야 한다. 분석 의도에 적합하게 결측치 처리를 하는 것이 중요하다.

0개의 댓글