이상치란 무엇일까? IQR로 찾고 처리하는 방법
데이터 분석이나 머신러닝을 진행하다 보면 다른 값들과 비교했을 때 유난히 크거나 작은 데이터를 발견하게 됩니다.
이러한 값을 이상치(Outlier)라고 합니다.
이상치는 단순한 입력 오류일 수도 있지만, 실제로 중요한 사건이나 특별한 고객 행동을 나타내는 데이터일 수도 있습니다.
따라서 이상치를 발견했다고 해서 무조건 삭제해서는 안 됩니다. 이상치가 발생한 원인과 데이터의 의미를 먼저 확인해야 합니다.
이번 글에서는 이상치가 무엇인지, 왜 발생하는지, 분석 결과에 어떤 영향을 주는지, 그리고 Pandas와 IQR을 이용해 이상치를 찾고 처리하는 방법을 알아보겠습니다.
이상치란?
이상치란 대부분의 데이터와 비교했을 때 지나치게 크거나 작은 값을 의미합니다.
예를 들어 다음과 같은 고객의 월 소득 데이터가 있다고 가정해 보겠습니다.
| 고객 | 월 소득 |
|---|---|
| 고객 A | 320만 원 |
| 고객 B | 350만 원 |
| 고객 C | 290만 원 |
| 고객 D | 340만 원 |
| 고객 E | 5,000만 원 |
고객 E의 월 소득은 다른 고객과 비교했을 때 매우 큽니다. 이 값은 이상치로 판단될 가능성이 높습니다.
하지만 고객 E가 실제 고소득자라면 잘못된 데이터가 아닙니다. 반대로 500만 원을 입력해야 하는데 5,000만 원으로 잘못 입력한 것이라면 데이터 오류에 해당합니다.
이상치는 다른 값과 크게 다르다는 뜻이지, 반드시 틀린 데이터라는 뜻은 아닙니다.
이상치는 왜 발생할까?
1. 데이터 입력 오류
사람이 직접 데이터를 입력하는 과정에서 숫자를 잘못 입력할 수 있습니다.
정상 입력: 35세
잘못된 입력: 350세
이런 경우는 명확한 오류이므로 수정하거나 제거하는 것이 적절합니다.
2. 측정 장비나 센서 오류
센서가 고장 나거나 통신에 문제가 생기면 비정상적으로 크거나 작은 값이 기록될 수 있습니다.
09:00 온도 22.1℃
10:00 온도 21.9℃
11:00 온도 145.0℃
12:00 온도 22.3℃
일반적인 환경이라면 145℃는 센서 오류일 가능성이 높습니다.
3. 단위가 서로 다른 경우
일부 데이터는 센티미터로 입력되고 일부는 미터로 입력되면 값의 범위가 크게 달라질 수 있습니다.
170cm
165cm
1.8m
단위를 통일하지 않으면 1.8이라는 값이 이상치처럼 보일 수 있습니다.
4. 실제로 드문 사건이 발생한 경우
이상치는 데이터 오류가 아니라 현실에서 실제로 발생한 특별한 사건일 수도 있습니다.
- 갑작스러운 매출 급증
- 대규모 주문
- 질병 발생
- 금융 사기 거래
- 시스템 장애
특히 금융 사기 탐지나 의료 데이터 분석에서는 이상치 자체가 가장 중요한 분석 대상이 될 수 있습니다.
5. 서로 다른 집단이 섞인 경우
일반 고객과 기업 고객의 구매 데이터를 함께 분석하면 기업 고객의 구매 금액이 이상치처럼 보일 수 있습니다.
이 경우에는 이상치를 제거하기보다 고객 유형을 나누어 분석하는 것이 더 적절할 수 있습니다.
이상치가 분석에 미치는 영향
1. 평균값을 크게 왜곡할 수 있다
다음과 같은 데이터가 있다고 가정해 보겠습니다.
300, 320, 330, 350, 5000
대부분의 값은 300대이지만 5,000이라는 큰 값이 포함되어 있습니다.
이 데이터를 평균으로 계산하면 실제 대다수 데이터보다 훨씬 큰 값이 나올 수 있습니다.
| 통계값 | 결과 |
|---|---|
| 평균 | 1,260 |
| 중앙값 | 330 |
이처럼 이상치가 존재할 때는 평균보다 중앙값이 데이터의 중심을 더 잘 나타낼 수 있습니다.
2. 머신러닝 모델의 학습을 방해할 수 있다
선형 회귀처럼 오차를 기반으로 학습하는 모델은 큰 이상치 하나에도 큰 영향을 받을 수 있습니다.
이상치 때문에 회귀선이 정상적인 데이터 구간에서 벗어나면 전체 예측 성능이 떨어질 수 있습니다.
3. 스케일링 결과를 왜곡할 수 있다
MinMaxScaler는 최솟값과 최댓값을 기준으로 데이터를 변환합니다.
매우 큰 이상치가 하나 존재하면 나머지 값들이 좁은 범위에 몰릴 수 있습니다.
4. 잘못 제거하면 중요한 정보를 잃을 수 있다
사기 거래, 질병, 장애 발생처럼 드문 사건을 분석하는 경우 이상치를 제거하면 가장 중요한 데이터를 잃게 됩니다.
따라서 이상치 처리는 모델 성능만 보고 결정하는 것이 아니라 분석 목적과 업무 맥락을 함께 고려해야 합니다.
Pandas로 데이터 분포 확인하기
이상치를 찾기 전에 먼저 데이터의 전체적인 분포를 확인해야 합니다.
import pandas as pd
df = pd.DataFrame({
"Salary": [300, 320, 330, 350, 370, 400, 420, 5000]
})
print(df)
describe()로 요약 통계 확인하기
df["Salary"].describe()
describe()를 실행하면 다음 정보를 확인할 수 있습니다.
- 데이터 개수
- 평균
- 표준편차
- 최솟값
- 25% 지점
- 중앙값
- 75% 지점
- 최댓값
평균과 중앙값의 차이가 지나치게 크거나 최댓값이 75% 값보다 매우 크다면 이상치가 있을 가능성을 확인할 수 있습니다.
describe()만으로 이상치를 확정할 수는 없습니다. 데이터의 분포를 빠르게 확인하는 용도로 사용하는 것이 좋습니다.IQR이란?
이상치를 찾는 대표적인 방법 중 하나가 IQR(Interquartile Range)입니다.
IQR은 데이터의 75% 지점인 Q3에서 25% 지점인 Q1을 뺀 범위입니다.
Q2 = 데이터의 50% 지점, 중앙값
Q3 = 데이터의 75% 지점
IQR = Q3 - Q1
IQR 방식에서는 일반적으로 다음 범위를 벗어난 값을 이상치 후보로 판단합니다.
하한값 = Q1 - 1.5 × IQR
상한값 = Q3 + 1.5 × IQR
하한값보다 작거나 상한값보다 큰 값을 이상치로 판단합니다.
1.5는 IQR 방식에서 일반적으로 사용하는 기준값입니다. 절대적인 법칙은 아니며 데이터 특성에 따라 조정할 수 있습니다.
Pandas로 IQR 계산하기
Q1 = df["Salary"].quantile(0.25)
Q3 = df["Salary"].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
print("Q1:", Q1)
print("Q3:", Q3)
print("IQR:", IQR)
print("하한값:", lower_bound)
print("상한값:", upper_bound)
quantile(0.25)는 25% 지점인 Q1을 구하고, quantile(0.75)는 75% 지점인 Q3를 구합니다.
이상치 행 찾기
outliers = df[
(df["Salary"] < lower_bound) |
(df["Salary"] > upper_bound)
]
print(outliers)
조건은 다음 두 경우를 의미합니다.
- Salary가 하한값보다 작은 경우
- Salary가 상한값보다 큰 경우
두 조건 중 하나라도 만족하면 이상치 후보로 조회합니다.
코드 안의 작은 부등호는
<, 큰 부등호는 > 형태로 작성해야 티스토리 HTML에서 정상적으로 표시됩니다.정상 범위 데이터만 조회하기
이상치를 제외하고 정상 범위에 있는 데이터만 조회할 수도 있습니다.
normal_data = df[
(df["Salary"] >= lower_bound) &
(df["Salary"] <= upper_bound)
]
print(normal_data)
이 코드는 Salary 값이 하한값 이상이며 상한값 이하인 행만 선택합니다.
하지만 이 결과를 바로 이상치 제거 결과로 사용하기 전에 반드시 해당 값이 실제 오류인지 확인해야 합니다.
이상치를 처리하는 방법
1. 이상치 제거
이상치가 명확한 입력 오류이거나 센서 오류라면 해당 행을 제거할 수 있습니다.
df_removed = df[
(df["Salary"] >= lower_bound) &
(df["Salary"] <= upper_bound)
]
다만 데이터 수가 적을 때 행을 제거하면 정보 손실이 커질 수 있습니다.
2. 상한값과 하한값으로 변경
이상치를 완전히 제거하지 않고 경계값으로 제한하는 방법도 있습니다.
df["Salary"] = df["Salary"].clip(
lower=lower_bound,
upper=upper_bound
)
상한값보다 큰 값은 상한값으로, 하한값보다 작은 값은 하한값으로 변경됩니다.
이러한 방식을 클리핑(Clipping) 또는 윈저라이징(Winsorizing)이라고 부르기도 합니다.
3. 중앙값으로 대체
이상치가 오류라고 판단되지만 행 자체를 제거하기 어려운 경우 중앙값으로 대체할 수 있습니다.
median_value = df["Salary"].median()
df.loc[
(df["Salary"] < lower_bound) |
(df["Salary"] > upper_bound),
"Salary"
] = median_value
중앙값은 이상치의 영향을 적게 받기 때문에 평균보다 안정적인 대체값이 될 수 있습니다.
4. 로그 변환
소득, 매출, 집값처럼 값의 범위가 크고 오른쪽으로 치우친 데이터는 로그 변환을 사용할 수 있습니다.
import numpy as np
df["Salary_log"] = np.log1p(df["Salary"])
log1p()는 값에 1을 더한 뒤 로그를 계산합니다. 값이 0인 경우에도 사용할 수 있다는 장점이 있습니다.
로그 변환은 이상치를 삭제하는 방법이 아니라 큰 값의 영향력을 줄이는 방법입니다.
5. 그룹을 나누어 분석
이상치처럼 보이는 값이 실제로 다른 집단에 속한 정상 데이터라면 그룹을 분리하여 분석하는 것이 좋습니다.
예를 들어 개인 고객과 기업 고객을 분리하면 기업 고객의 큰 구매 금액이 더 이상 이상치로 보이지 않을 수 있습니다.
6. 이상치를 그대로 유지
이상치가 분석의 핵심인 경우에는 제거하지 않아야 합니다.
- 금융 사기 탐지
- 불량 제품 탐지
- 질병 이상 징후 탐지
- 서버 장애 탐지
- 비정상 사용자 행동 탐지
이 경우에는 이상치를 제거하는 것이 아니라 이상치를 예측하고 탐지하는 모델을 만들어야 합니다.
이상치는 언제 제거해야 할까?
제거를 고려할 수 있는 경우
- 명확한 입력 오류인 경우
- 센서나 측정 장비의 오류인 경우
- 분석 대상과 관련 없는 데이터인 경우
- 단위 변환 오류가 발생한 경우
- 이상치가 모델 성능을 크게 왜곡하는 경우
유지해야 하는 경우
- 실제로 발생한 정상적인 값인 경우
- 비즈니스적으로 중요한 고객이나 거래인 경우
- 사기, 장애, 질병처럼 드문 사건을 분석하는 경우
- 해당 값이 새로운 패턴을 의미하는 경우
이상치를 제거할지 결정할 때는 통계 기준뿐 아니라 데이터가 만들어진 업무 환경과 분석 목적을 함께 고려해야 합니다.
머신러닝에서 주의할 점
머신러닝에서는 전체 데이터를 학습용과 테스트용으로 나눈 뒤 이상치 처리 기준을 계산해야 합니다.
전체 데이터에서 먼저 Q1, Q3, IQR을 계산하면 테스트 데이터의 정보가 학습 과정에 포함될 수 있습니다.
이를 데이터 누수(Data Leakage)라고 합니다.
올바른 순서는 다음과 같습니다.
↓
학습 데이터에서 Q1, Q3, IQR 계산
↓
학습 데이터 이상치 처리
↓
같은 기준을 테스트 데이터에 적용
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2,
random_state=42
)
Q1 = X_train["Salary"].quantile(0.25)
Q3 = X_train["Salary"].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
X_train["Salary"] = X_train["Salary"].clip(
lower=lower_bound,
upper=upper_bound
)
X_test["Salary"] = X_test["Salary"].clip(
lower=lower_bound,
upper=upper_bound
)
테스트 데이터에서 별도로 IQR을 계산하지 않고 학습 데이터에서 계산한 기준을 동일하게 적용해야 합니다.
전체 실습 예제
import pandas as pd
df = pd.DataFrame({
"Name": ["Kim", "Lee", "Park", "Choi", "Jung", "Han"],
"Salary": [300, 320, 330, 350, 370, 5000]
})
# 데이터 요약 확인
print(df["Salary"].describe())
# Q1과 Q3 계산
Q1 = df["Salary"].quantile(0.25)
Q3 = df["Salary"].quantile(0.75)
# IQR 계산
IQR = Q3 - Q1
# 이상치 경계값 계산
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
print("Q1:", Q1)
print("Q3:", Q3)
print("IQR:", IQR)
print("하한값:", lower_bound)
print("상한값:", upper_bound)
# 이상치 조회
outliers = df[
(df["Salary"] < lower_bound) |
(df["Salary"] > upper_bound)
]
print("이상치")
print(outliers)
# 정상 범위 데이터 조회
normal_data = df[
(df["Salary"] >= lower_bound) &
(df["Salary"] <= upper_bound)
]
print("정상 범위 데이터")
print(normal_data)
위 코드를 통해 데이터의 분포를 확인하고, IQR 기준으로 이상치 후보와 정상 범위 데이터를 구분할 수 있습니다.
단, 코드에서 이상치로 분류되었다는 이유만으로 바로 삭제하지 말고 실제 데이터의 의미를 반드시 확인해야 합니다.
자주 사용하는 이상치 관련 함수
| 함수 및 방법 | 역할 |
|---|---|
describe() |
데이터의 요약 통계 확인 |
quantile(0.25) |
Q1, 25% 지점 계산 |
quantile(0.75) |
Q3, 75% 지점 계산 |
clip() |
값을 상한과 하한 범위로 제한 |
median() |
이상치 영향을 적게 받는 중앙값 계산 |
np.log1p() |
큰 값의 영향력을 줄이기 위한 로그 변환 |
| IQR | 사분위 범위를 이용한 이상치 탐지 |
마무리
이상치는 대부분의 데이터와 다른 값을 의미하지만 반드시 잘못된 데이터는 아닙니다.
입력 오류나 센서 오류일 수도 있고, 실제로 발생한 중요한 사건일 수도 있습니다.
따라서 이상치를 발견하면 다음 질문을 먼저 확인해야 합니다.
- 이 값은 실제로 발생할 수 있는가?
- 입력이나 측정 과정에서 오류가 있었는가?
- 단위가 다른 데이터가 섞여 있는가?
- 이상치가 분석 목적에서 중요한 의미를 가지는가?
- 제거했을 때 중요한 정보가 사라지지 않는가?
이상치 처리는 튀는 값을 무조건 삭제하는 작업이 아니라, 데이터의 원인과 의미를 확인한 뒤 적절한 방법을 선택하는 과정입니다.
핵심 정리
- 이상치는 대부분의 데이터보다 지나치게 크거나 작은 값입니다.
- 이상치는 입력 오류일 수도 있고 실제로 중요한 데이터일 수도 있습니다.
describe()로 데이터의 분포와 통계값을 확인할 수 있습니다.- IQR은 Q3에서 Q1을 뺀 사분위 범위입니다.
- 일반적으로 Q1 - 1.5 × IQR보다 작거나 Q3 + 1.5 × IQR보다 큰 값을 이상치 후보로 판단합니다.
- 이상치는 제거, 대체, 클리핑, 로그 변환, 그룹 분리 등의 방법으로 처리할 수 있습니다.
- 분석 목적에 따라 이상치를 그대로 유지해야 할 수도 있습니다.
- 머신러닝에서는 학습 데이터에서 계산한 이상치 기준을 테스트 데이터에도 동일하게 적용해야 합니다.
다음 글 예고
다음 글에서는 중복 데이터가 무엇인지, 중복 데이터가 분석 결과와 머신러닝 모델에 어떤 영향을 주는지 알아보겠습니다.
또한 Pandas의 duplicated()와 drop_duplicates()를 사용하여 중복 데이터를 찾고 제거하는 방법을 실습해 보겠습니다.
'AI > 데이터 처리' 카테고리의 다른 글
| AI가 데이터를 이해하지 못하는 첫 번째 이유 (0) | 2026.07.13 |
|---|---|
| 데이터 전처리를 왜 하는 것일까? (0) | 2026.07.13 |



