이상치, 결측치 처리하기

김채윤·2025년 11월 26일

이상치란 전체 데이터를 벗어난 아주 작거나 큰 값을 말하고, 결측치란 누락된 값을 말한다.

결측치 처리
1. 제거

#컬럼별 결측치 식별
df3.isnull().sum()
#df3.isnull()을 하면 null값을 true false로 표시해서 알려주기 때문에 sum으로 결측치 개수를 센다.

#열 제거하기
df3 = df3.drop('Unnamed: 4', axis=1)
#df3의 'Unnamed: 4'인 컬럼을 다 지운다.

#결측치가 있는 행들을 모두 제거하기
df3.dropna(axis=0, how='any')

#결측치가 있는 열들을 모두 제거하기
df3.dropna(axis=1)
#데이터가 하나라도 누락된 열들은 모두 제거되기 때문에 매우 위험하다.

#전체 행이 결측값인 경우만 행을 제거하기
df3.dropna(how='all')

#결측치 제거 후 원래 데이터에 적용하여 저장하고 싶다면 inplace=True를 사용할 수 있다.
df3.dropna(how='all', inplace=True)
#df3 = df3.dropna(how='all')과 같다.
  1. 대체
# 결측치 대체: 최빈값
# mode 는 최빈값을 의미
# df3 의 Interaction type 컬럼을 fillna함수를 이용하여 채워주되, mode() 함수를 사용하여 최빈값으로 넣어줌
# mode 함수는 시리즈를 output으로 가집니다. 
# 따라서,[0]을 통해 시리즈 중 단일값을 가져와야 합니다. 
df3 = df3['Interaction type'].fillna(df3['Interaction type'].mode()[0])
df3.isnull().sum()

# 결측치 대체: 평균값
df['sw'] = df['sw'].fillna(df['sw'].mean())

# 결측치 대체: 중간값
df['sw'] = df['sw'].fillna(df['sw'].median())

# 결측치 대체: 바로 위 값으로 대체
df['sw'] = df['sw'].fillna(method='ffill')

# 결측치 대체: 바로 아래 값으로 대체
df['sw'] = df['sw'].fillna(method='bfill')

# 결측치 대체: group by 값으로 대체
# 사전 데이터 확인
df.groupby('Is Amazon Seller')['sw'].median()
#df에 있는 Is Amazon Seller컬럼을 그룹화해서 묶고, 각 그룹의 sw의 중앙값을 확인한다.

# group by한 데이터를 데이터프레임의 컬럼으로 추가하기 위해 
# transform 함수 사용
df['sw'] = df['sw'].fillna(df.groupby('Is Amazon Seller')['sw'].transform('median'))
#df의 sw컬럼에 결측값을 채워줄건데, Is Amazon Seller에 따라 그룹화해서 각 그룹의 sw 중앙값을 구하고 sw가 결측값인 경우에 속한 그룹의 sw 중앙값을 넣어주고, 값이 있으면 그대로 둔다.

이상치 판별
1. Z-score
: 평균으로부터 얼마나 떨어져 있는지를 수치화한 표준점수로 ±3을 벗어나면 이상치로 판단한다.
z score가 1이면 평균으로부터 1표준편차 더 큰 것을 의미한다.

# df 의 Shipping Weight를 기준으로 다양한 이상치 감지 기법을 적용해 보겠습니다. 
df = pd.read_csv("p.csv")

# string -> float -> int 
df['sw'] = df['Shipping Weight'].str.split().str[0]
df['sw'] = pd.to_numeric(df['sw'] , errors='coerce').fillna(0.0).astype(int)
#Shipping Weight에 있는 숫자 데이터를 문자 형식으로 바꾸고 1.8 kg 등의 형식으로 작성되어 있을 수 있어서 split().str[0]을 써서 공백 뒤에 있는 단위를 버려준다.
#이렇게 수정된 df['sw']를 숫자 형식으로 바꿀건데, 숫자로 못바꾸는 데이터는 NaN 처리한다. --> errors= 'coerce'
#결측값은 0.0으로 대체하고 정수형으로 변환한다.

# z-score 를 적용할 컬럼 선정
df1 = df[['sw']]
#sw 열만 따로 빼서 df1로 저장한다.

# 표준화 진행
# 표준화 :  평균을 0으로, 표준 편차를 1로 
# 데이터를 0을 중심으로 양쪽으로 데이터를 분포시키는 방법
# 표준화를 하게 되면 각 데이터들은 평균을 기준으로 얼마나 떨여져 있는지를 나타내는 값으로 변환
scale_df = StandardScaler().fit_transform(df1)
#df1의 값을 평균 0, 표준편차 1로 표준화 진행

merge_df = pd.concat([df1, pd.DataFrame(StandardScaler().fit_transform(df1))],axis=1)
#df1에 표준화한 값을 2차원 구조로 만들어서 수평으로 붙임
merge_df.columns = ['Shipping Weight', 'zscore']
#df1을 Shipping Weight, 표준화한 값을 zscore라고 컬럼 이름을 붙임

# 이상치 감지 
# Z-SCORE 기반, -3 보다 작거나 3보다 큰 경우를 이상치로 판별 
mask = ((merge_df['zscore']<-3) | (merge_df['zscore']>3))
#zscore가 3보다 크거나 -3보다 작을 경우 해당 데이터를 mask에 저장
#mask는 T/F로 판독하여 T인 경우만 저장함

# mask 메소드 사용
strange_df = merge_df[mask]
#mask가 T인 데이터를 모아서 strange_df라 명명

# 총 55 건 탐지 
strange_df.count()
  1. IQR
# df 의 Shipping Weight를 기준으로 다양한 이상치 감지 기법을 적용해 보겠습니다. 
df = pd.read_csv("p.csv")

# string -> float -> int 
df['sw'] = df['Shipping Weight'].str.split().str[0]
df['sw'] = pd.to_numeric(df['sw'] , errors='coerce').fillna(0.0).astype(int)

# 이상치를 감지할 컬럼 선정
df1 = df[['sw']]

# Q3, Q1, IQR 값 구하기
# 백분위수를 구해주는 quantile 함수를 적용하여 쉽게 구할 수 있음
# 데이터프레임 전체 혹은 특정 열에 대하여 모두 적용이 가능

q3 = df1['sw'].quantile(0.75) 
q1 = df1['sw'].quantile(0.25)

iqr = q3 - q1
q3, q1, iqr
# 7, 1, 6 출력

# 이상치 판별 및 dataframe 저장 
# Q3 : 100개의 데이터로 가정 시, 25번째로 높은 값에 해당합니다.
# Q1 : 100개의 데이터로 가정 시, 75번째로 높은 값에 해당합니다.
# IQR : Q3 - Q1의 차이를 의미합니다.
# 이상치 : Q3 + 1.5 * IQR보다 높거나 Q1 - 1.5 * IQR보다 낮은 값을 의미

def is_outlier(df1):
    score = df1['sw']
    if score > 7 + (1.5 * 6) or score < 1 - (1.5 * 6):
        return '이상치'
    else:
        return '이상치아님'

# apply 함수를 통하여 각 값의 이상치 여부를 찾고 새로운 열에 결과 저장
df1['이상치여부'] = df1.apply(is_outlier, axis = 1) # axis = 1 지정 필수

# IQR 방식으로 구한 이상치 개수는 349 개 
df1.groupby('이상치여부').count()
#이상치 xx, 이상치아님 xx로 출력
  1. 결정트리

    질문을 해서 어떤 항목에 속하는지 구분하는 방법인데, 이상치의 경우 어느 항목에도 속하지 않아서 짧은 경로를 가짐.

    경로 길이를 수치화해서(0-1) 1에 가까울 수록 이상치로 판단

  2. DBScan

    밀도를 기반으로 핵심 데이터들을 설정하고 핵심 데이터들을 연결하여 군집을 형성한다. 군집에 포함되지 않은 데이터를 이상치로 간주한다.

이상치 처리
1. 제거
2. 대체
(1) 로그변환
(2) 상한값 하한값으로 대체
(3) 평균 절대 편차: 중앙값으로부터 떨어진 거리의 평균을 구해서 중위수로부터 n편차 큰 값을 대체
3. 분리: 따로 저장해둔다

0개의 댓글