Skip to main content

중복과 이상치

데이터 품질을 확보하기 위해서는 중복 데이터와 이상치(Outlier)를 적절히 처리해야 합니다. 중복은 집계 결과를 왜곡하고, 이상치는 모델 학습에 부정적 영향을 미칠 수 있습니다.

학습 목표

  • 중복 행을 탐지하고 제거할 수 있다
  • IQR 방법으로 이상치를 탐지할 수 있다
  • Z-score 방법으로 이상치를 탐지할 수 있다
  • 이상치 처리 전략(제거, 클리핑, 변환)을 상황에 맞게 선택할 수 있다

왜 중요한가

데이터 수집 과정에서 중복 레코드가 발생하면 특정 샘플이 과대 대표되어 모델이 편향됩니다. 이상치는 평균, 분산 등 통계량을 크게 왜곡하며, 거리 기반 알고리즘(KNN, K-Means)의 성능을 저하시킵니다.

중복 처리

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'id': [1, 2, 2, 3, 4, 4],
    'name': ['김', '이', '이', '박', '최', '최'],
    'value': [100, 200, 200, 300, 400, 450]
})

# 중복 행 탐지
print(df.duplicated())           # 불리언 Series
print(df.duplicated().sum())     # 중복 행 수

# 특정 열 기준 중복 확인
print(df.duplicated(subset=['id']))

# 중복 행 확인
print(df[df.duplicated(keep=False)])  # 중복된 모든 행 표시

# 중복 제거
df_clean = df.drop_duplicates()                    # 전체 열 기준
df_clean = df.drop_duplicates(subset=['id'])       # 특정 열 기준
df_clean = df.drop_duplicates(subset=['id'], keep='last')  # 마지막 것 유지

IQR 이상치 탐지

IQR(Interquartile Range) 방법은 사분위 범위를 기준으로 이상치를 정의합니다.
data = pd.Series([10, 12, 14, 15, 16, 18, 20, 100])

Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1

# 이상치 경계
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 이상치 탐지
outliers = data[(data < lower_bound) | (data > upper_bound)]
print(f"이상치: {outliers.values}")  # [100]

# DataFrame에 적용
def detect_outliers_iqr(df, column):
    """IQR 기반 이상치를 탐지합니다."""
    Q1 = df[column].quantile(0.25)
    Q3 = df[column].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    return (df[column] < lower) | (df[column] > upper)

Z-score 이상치 탐지

Z-score는 각 값이 평균에서 몇 표준편차만큼 떨어져 있는지를 나타냅니다.
from scipy import stats

data = pd.Series([10, 12, 14, 15, 16, 18, 20, 100])

# Z-score 계산
z_scores = np.abs(stats.zscore(data))

# 임계값 설정 (보통 3)
threshold = 3
outliers = data[z_scores > threshold]
print(f"이상치: {outliers.values}")  # [100]

# 수동 계산
z_manual = np.abs((data - data.mean()) / data.std())
방법장점단점적합한 상황
IQR분포 가정 불필요, 강건정규분포에서 5% 정상값 탐지편향된 분포, 범용
Z-score직관적, 계산 간단정규분포 가정, 이상치에 민감정규분포에 가까운 데이터

이상치 처리 전략

df = pd.DataFrame({'value': [10, 12, 14, 200, 15, 16, -50, 18]})

# 1. 제거
mask = detect_outliers_iqr(df, 'value')
df_clean = df[~mask]

# 2. 클리핑 (경계값으로 대체)
Q1, Q3 = df['value'].quantile([0.25, 0.75])
IQR = Q3 - Q1
df['value_clipped'] = df['value'].clip(
    lower=Q1 - 1.5 * IQR,
    upper=Q3 + 1.5 * IQR
)

# 3. 로그 변환 (편향된 분포 완화)
df['value_log'] = np.log1p(df['value'].clip(lower=0))

# 4. NaN으로 대체 후 결측치 처리
df.loc[mask, 'value'] = np.nan
df['value'] = df['value'].fillna(df['value'].median())

AI/ML에서의 활용

  • 데이터 정제: 중복과 이상치를 처리하여 학습 데이터 품질을 높입니다
  • 피처 엔지니어링: 이상치 여부를 이진 피처로 활용할 수 있습니다
  • 모델 선택: 이상치가 많으면 트리 기반 모델(이상치에 강건)을 고려합니다
  • 이상치 탐지 모델: Isolation Forest, LOF 등 전용 알고리즘은 ML 탭에서 다룹니다
아닙니다. 이상치가 측정 오류인지 실제 극단값인지 구분해야 합니다. 사기 탐지에서는 이상치 자체가 관심 대상이고, 의료 데이터에서 극단적 수치는 중요한 임상 정보일 수 있습니다. 도메인 지식과 함께 판단하세요.
1.5는 정규분포에서 약 99.3%의 데이터를 포함하는 관례적인 값입니다. 더 엄격하게 탐지하려면 1.0, 느슨하게 하려면 2.0이나 3.0을 사용할 수 있습니다.

체크리스트

  • duplicated()와 drop_duplicates()로 중복을 처리할 수 있다
  • IQR 방법으로 이상치를 탐지할 수 있다
  • Z-score 방법으로 이상치를 탐지할 수 있다
  • 제거, 클리핑, 변환 등 이상치 처리 전략을 상황에 맞게 선택할 수 있다
  • 이상치 처리 시 도메인 지식의 중요성을 이해한다

다음 문서