Today I Learned

[내일배움캠프 QA/QC 트랙 6기 본캠프] TIL #015 데이터 전처리 & 시각화

JiJi0406 2026. 6. 1. 21:10

001

오늘의 키워드: 제곧내

오늘부터 본격적으로 시각화를 배우기 시작했다. 데이터의 시각화를 QA/QC 직무와 연결해서 생각해보면, 품질 관리를 제대로 하려면 결국 데이터 분석이 뒷받침돼야 하고, 그 분석 결과로 사람들을 설득시키려면 눈에 잘 들어오는 형태로 보여줄 수 있어야 한다! 숫자를 잔뜩 늘어놓는 것보다 차트 하나가 훨씬 보기 편하니...

 

시각화보다 먼저 해야 할 건 전처리. 실무에서는 전처리를 할 때 가장 오래걸린다고 들었던 게 기억이 난다. 데이터 자체가 엉망이면 아무리 예쁘게 그려도 의미가 없다. 결국 전처리가 제대로 되어야? 시각화도 믿을 수 있는 것이 된다. 오늘 배웠던 내용들 잘 정리해서 나중에 필요할 때마다 찾아 쓸 수 있도록 해야겠다. 코딩 = 오픈북 😁

 

 


 

002

오늘 학습한 내용

 

1. 데이터 선택 & 필터링

df['컬럼'] 단일 컬럼 선택 df['Age']
df[['컬럼1', '컬럼2']] 여러 컬럼 선택 (리스트로!) df[['Age', 'Sex']]
df[조건] 조건 필터링 df[df['Age'] > 30]
df[조건1 & 조건2] AND 조건 df[(df['Age'] > 30) & (df['Sex'] == 'male')]
df[조건1 | 조건2] OR 조건
.isin([값1, 값2]) 여러 값 중 하나인지 확인 df[df['Pclass'].isin([1, 2])]
.isna() / .notna() 결측치 여부 필터링 df[df['Age'].notna()]
.loc[행, 열] 이름 기반 선택. 슬라이싱 끝값 포함 df.loc[0:4, 'Age']
.iloc[행, 열] 숫자 위치 기반 선택. 슬라이싱 끝값 제외 df.iloc[0:4, 2]

++  조건이 많아서 코드가 길어지면 \로 줄바꿈

 

 

 

2. 데이터 집계 & 재구성

.groupby('컬럼') 특정 컬럼 기준으로 그룹 묶기
.agg({'컬럼': '함수'}) 그룹별로 컬럼마다 다른 집계 함수 적용 (max, mean, sum 등)
.sort_values('컬럼') 컬럼 기준 정렬. ascending=False로 내림차순
.sort_index() 인덱스 기준 정렬
.reset_index() 인덱스 초기화
.set_index('컬럼') 특정 컬럼을 인덱스로 설정 (중복 없는 값 권장)
.pivot_table(index, columns, values, aggfunc) 데이터를 재구성해서 요약·집계. 엑셀 피벗 테이블과 동일한 개념
# groupby + agg: 성별·요일별로 묶고 컬럼마다 다른 집계 적용
df.groupby(['sex', 'day']).agg({
    'total_bill': 'max',
    'tip': 'mean',
    'size': 'sum'
})

# pivot_table
df.pivot_table(index='Date', columns='Category', values='Value', aggfunc='sum')

 

 

 

3. 데이터프레임 합치기

pd.concat([df1, df2], axis=0) 위아래 단순 연결. ignore_index=True로 인덱스 초기화 가능
pd.concat([df1, df2], axis=1) 좌우 단순 연결
pd.merge(df1, df2, on='키', how='inner') 좌우 공통 열 기준 병합. SQL JOIN과 동일

merge의 how 옵션: inner(교집합) / outer(합집합) / left(왼쪽 기준) / right(오른쪽 기준)

 

 

 

4. 데이터 탐색 메서드

.head(n) / .tail(n) 상위/하위 n행 확인 (기본 5행)
.info() 컬럼명, 타입, 결측치 개수 요약
.describe() 숫자형 기본 통계 (평균, 표준편차, 사분위수 등)
.describe(include='all') 범주형 포함 전체 통계
.describe(percentiles=[.1, .9, .95]) 백분위수 상세 지정
.value_counts() 빈도 확인
.value_counts(normalize=True) 비율 확인 (빈도보다 더 중요!)
.skew() 왜도
.kurtosis() 첨도
.corr() 상관관계 매트릭스

 

 

 

★ 헷갈림 주의 🚨

5. 왜도 해석

평균 > 중위수 양수(+) 봉우리 왼쪽, 꼬리 오른쪽
평균 < 중위수 음수(-) 봉우리 오른쪽, 꼬리 왼쪽
평균 = 중위수 0 좌우 대칭 (정규분포)

첨도 > 3이면 뾰족(데이터 몰림)

< 3이면 평평(데이터 퍼짐)

 

상관관계 절대값 기준: 0.7 이상 → 매우 강함 / 0.3~0.7 → 강함 / 0.1~0.3 → 중간 / 0.1 미만 → 약함

상관관계가 높다고 인과관계가 있는 건 아님!

 

 

 

6. 결측치 처리

결측치 형태: NaN, N/A, Null, 공백 등

0이나 9999처럼 생긴 건 결측치보다 이상치에 가까움

.isnull().sum() 컬럼별 결측치 개수. sum() 안에 넣는 게 아니라 뒤에 붙이는 것!
.isnull().sum() / len(df) * 100 결측치 비율 (개수보다 더 중요)
.dropna() 결측치 있는 행 삭제
.dropna(axis=1) 결측치 있는 컬럼 삭제
.dropna(subset=['컬럼']) 특정 컬럼 기준으로만 행 삭제
.fillna(값) 결측치를 특정 값으로 대체
.ffill() / .bfill() 앞/뒤 값으로 채우기 (시계열 데이터에서 유용)

+ dropna는 뭘 기준으로 지울지 잘 생각하고 써야 한다!

 

 

7. 결측치 대체 기준

정규분포에 가까운 연속형 평균값 .mean()
이상치 많거나 치우친 분포 중위수 .median()
범주형 변수 최빈값 .mode()[0] (mode()는 Series 반환이라 [0] 필요)
# 결측치 비율 확인
(titanic.isnull().sum() / len(titanic) * 100).round(2)

# 대체 예시
titanic['Age'].fillna(titanic['Age'].median())
titanic['Embarked'].fillna(titanic['Embarked'].mode()[0])

 

 

 

 

8. 데이터 타입 변환

.astype(int/float/str) 기본 타입 변환. 결측치나 이상한 값 섞여 있으면 에러 남
pd.to_numeric(df['컬럼'], errors='coerce') 문자열 → 숫자 변환. errors='coerce'로 변환 불가능한 값은 NaN 처리
.str.replace(',', '') 콤마 등 문자 제거 후 변환할 때 전처리용
pd.to_datetime(df['컬럼']) 문자열 → 날짜 타입 변환. 대부분의 날짜 형식 자동 인식

실무에서 CSV 불러오면 숫자가 문자열로 읽히는 경우가 있어서 데이터 타입 변환이 필요할 때도 있다!

astype()은 결측치가 없는 깨끗한 데이터에만 쓰고, 실제 데이터엔 pd.to_numeric(errors='coerce')이 안전

# astype()은 깨끗한 데이터에만
df['score'].astype(float)

# 결측치·이상값 섞인 실제 데이터엔 이걸로
df['age_clean'] = pd.to_numeric(df['age'], errors='coerce')

# 콤마 포함된 숫자 (예: '50,000')
df['income_clean'] = df['income'].str.replace(',', '').astype(float)

# 날짜 변환
df['order_date'] = pd.to_datetime(df['order_date'])

 

 

 

9. 날짜 타입 변환 후 쓸 수 있는 것들

.dt.year / .dt.month / .dt.day 연/월/일 추출
.dt.day_name() 요일명 추출
.dt.quarter 분기 추출
.dt.dayofweek 요일 번호 (월=0, 일=6)
(날짜A - 날짜B).dt.days 날짜 간 차이 (일 단위)

 

 

 

10. 시각화 — Matplotlib 기초

라이브세션에서 Matplotlib  내용 들어가기 전에 VOD 강의로 가볍게 봤다.

▼ 주요 메서스 정리 

plt.plot(x, y) 선 그래프
plt.hist(data) 히스토그램 (막대그래프 아님!)
plt.xlabel() / plt.ylabel() 축 레이블
plt.title() 그래프 제목
plt.legend() 범례 표시
plt.text(x, y, '텍스트') 특정 좌표에 텍스트 추가
plt.show() 그래프 출력
sns.heatmap(matrix, annot=True, cmap='coolwarm') 히트맵 (상관관계 시각화에 유용)

 

 


 

003

오늘의 코드카타

프로그래머스 24번 : 서울에서 김서방 찾기

 

문제 설명
String형 배열 seoul의 element중 "Kim"의 위치 x를 찾아, "김서방은 x에 있다"는 String을 반환하는 함수, solution을 완성하세요. seoul에 "Kim"은 오직 한 번만 나타나며 잘못된 값이 입력되는 경우는 없습니다.

 


제한 사항

  • seoul은 길이 1 이상, 1000 이하인 배열입니다.
  • seoul의 원소는 길이 1 이상, 20 이하인 문자열입니다.
  • "Kim"은 반드시 seoul 안에 포함되어 있습니다.

 

입출력 예

seoul return
["Jane", "Kim"]  "김서방은 1에 있다"

 

 

▼ 내가 짠 코드

def solution(seoul):
    for i in seoul:
        if "Kim" in seoul:
            answer = seoul.index("Kim")

    return f"김서방은 {answer}에 있다"

 

어렵지 않게 짜긴 했다만... 굳이 for문을 안 써도 된다는 걸 다 짜고 알았다.

 

▼ fancy한 버전 😎
def solution(seoul):
    return f"김서방은 {seoul.index('Kim')}에 있다"

 

 

 

원래는 코드카타 하루에 5~10개씩 풀었는데 20번 넘어가고부터는 어려워져서 하루에 하나씩이라도 풀자로 바뀜....^^

 


 

004

내일 학습할 것

 

  • 오늘 배운 전처리 메서드들 하나씩 직접 타이핑하면서 손에 익히기
  • 오늘 라이브세션 실습 문제 풀어보기
  • Matplotlib이랑 Seaborn 활용해서 예제 데이터로 직접 그래프 만들어보고 커스텀해보기