이상치 탐지와 처리
이상치 탐지와 처리
- 이상치(outlier): 기존에 관찰된 분포 바깥에 속하는 값
- 정상치(inlier): 기존에 관찰된 분포 안에 속하는 값
- 이상치가 생기는 주요 원인
- 입력하는 사람의 실수 또는 센서 오류
- 제대로 교정되지 않은 측정 장비 또는 환경 변화로 인한 측정 오류
- 데이터 단위 변환이나 스케일링 과정에서의 잘못된 처리
- 매우 드문 사건이나 특이한 현상
- 데이터가 다양한 집단에서 수집된 경우
- 결측치를 부정확한 값으로 대치한 경우
- 예: 관행적으로 결측치를 99로 입력하는 경우
- 예: 다봉분포에서 평균값으로 대치하는 경우
이상치 다루기
- 수정해야 할 경우
- 데이터 포인트의 원본과 대조했을 때 입력이 잘못된 경우
- 삭제해야 할 경우
- 데이터 포인트가 연구의 모집단에 속하지 않는 경우
- 실험 절차나 측정이 잘못된 경우
- 진단 지표를 기계적으로 적용해 데이터를 삭제하면 안 됨
- 데이터 삭제에는 객관적 이유가 필요
- 데이터를 삭제한 경우 결과 보고에 포함해야 함
- 삭제 여부를 결정하기 어려운 경우
- 삭제한 데이터셋과 삭제하지 않은 데이터셋을 따로 분석하고 결과 비교
- 모형을 수정해야 할 경우
- 중요한 변수의 누락
- 상호작용
- 비선형성
데이터 불러오기
# 데이터 로딩
import numpy as np
import pandas as pd
df_outlier = pd.read_csv("outlier_detection.csv")
df_outlier.head()
dataset_names = df_outlier.dataset.unique().tolist()
데이터셋 하나 그리기
# 시각화
import matplotlib.pyplot as plt
import seaborn as sns
dataset = df_outlier.query('dataset == "single_cluster"')
sns.scatterplot(x="sensor_a", y="sensor_b", hue="type", data=dataset)

한 번에 그리기
g = sns.FacetGrid(df_outlier, col="dataset", hue="type")
g.map(sns.scatterplot, "sensor_a", "sensor_b")

시각화 함수
def apply_outlier_detection(algorithm):
g = sns.FacetGrid(
df_outlier,
col="dataset",
col_order=dataset_names,
hue="type",
)
g.map(sns.scatterplot, "sensor_a", "sensor_b")
xx, yy = np.meshgrid(
np.linspace(-7, 7, 150),
np.linspace(-7, 7, 150),
)
for i, ax in enumerate(g.axes.flat):
dataset_name = dataset_names[i]
X = df_outlier.query(
"dataset == @dataset_name"
)[["sensor_a", "sensor_b"]].to_numpy()
algorithm.fit(X)
Z = algorithm.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
ax.contour(xx, yy, Z, levels=[0], linewidths=2, colors="black")
return g.add_legend()
- 각 데이터셋에 알고리즘을 학습한 뒤, 격자상의 모든 점을 예측해 정상/이상 경계를 그림
EllipticEnvelope
- 데이터의 분포를 알고 있다고 가정할 수 있으면, 분포를 추정해 이상점 여부를 진단할 수 있음
from sklearn.covariance import EllipticEnvelope
outliers_fraction = 0.15
algorithm = EllipticEnvelope(
contamination=outliers_fraction,
random_state=42,
)
apply_outlier_detection(algorithm)

OneClassSVM
- 이상치와 마진을 최대화하는 방식
gamma를 이용해 커널의 특성을 조절할 수 있음"scale"은 기본값
- RBF 커널의 경우
gamma를 줄이면 좁고 뾰족한 형태의 경계가 만들어짐
from sklearn.svm import OneClassSVM
algorithm = OneClassSVM(
nu=outliers_fraction,
kernel="rbf",
gamma="scale",
)
apply_outlier_detection(algorithm)

Isolation Forest
- 데이터를 분할하는 트리(tree)를 무작위로 만듦
- 이상치는 뿌리에서 짧은 거리 안에서 고립되는 경향이 있음
- 트리를 많이 만들어 forest를 구성하고, 쉽게 고립되는 점을 찾음


IsolationForest
from sklearn.ensemble import IsolationForest
algorithm = IsolationForest(
contamination=outliers_fraction,
random_state=42,
)
apply_outlier_detection(algorithm)

LocalOutlierFactor
- k-최근접 이웃에 대해 밀도를 비교함
- 주변 이웃과 비교해 멀리 떨어져 있으면 이상치로 판정
from sklearn.neighbors import LocalOutlierFactor
algorithm = LocalOutlierFactor(
n_neighbors=35,
contamination=outliers_fraction,
novelty=True,
)
apply_outlier_detection(algorithm)

알고리즘별 예측 실습
퀴즈를 풀기 전에 다음 코드를 한 번 실행합니다. uneven_cluster 데이터로 모델을 학습하고, (0, -3)과 (1.5, -2)를 차례로 판정합니다.
import numpy as np
import pandas as pd
df_outlier = pd.read_csv("outlier_detection.csv")
X_practice = (
df_outlier
.query('dataset == "uneven_cluster"')
[["sensor_a", "sensor_b"]]
.to_numpy()
)
test_points = np.array([
[0.0, -3.0],
[1.5, -2.0],
])
네 알고리즘의 predict()는 정상으로 판정한 점에 1, 이상치로 판정한 점에 -1을 반환합니다. 예측 배열의 첫 번째 값은 (0, -3), 두 번째 값은 (1.5, -2)의 결과입니다.