1. 이상치 : 전체 데이터 범위에서 벗어난 아주 작은 값이나 큰 값
2. 결측치 : 데이터 수집 과정에서 측정되지 않거나 누락된 데이터
1. 결측치 : 데이터의 누락된 부분
2. 결측치 처리 - 제거
# 컬럼별 결측치 식별
df3.isnull().sum()
# 결측치 제거1 - 열 제거하기
df3 = df3.drop('Unnamed: 4', axis=1)
# 결측치 제거2 - 결측치가 있는 행들은 모두 제거
df3.dropna()
# 같은 표현
df3.dropna(axis=0, how='any')
# 결측치 제거3 - 결측치가 있는 열을 모두 제거
# 열로 제거하면 컬럼이 제거되는 현상이 발생하므로 매우 위험합니다.
# df3.dropna(axis=1)
# 결측치 제거4 - 전체 행이 결측값인 경우만 삭제하고 싶은 경우
# how='all'을 사용해줍니다.
df3 = df3.dropna(how='all')
# 결측치 제거5 - 결측치 제거 후 결과를 바로 저장하고 싶을 때
# inplace=True 조건을 넣어줍니다.
df3.dropna(inplace=True)
# drop 이후 결측치가 잘 제거되었는지 체크가 필요하겠죠?
df3.isnull().sum()
3. 결측치 처리 - 대체
1) 최빈값 : 범주형 변수에 주로 사용, 데이터가 가장 많이 도출된 값으로 대체 가능
2) 중앙값, 평균값 : 수치형 변수에 사용, 결측치에 중앙값이나 평균값으로 대체
3) 그 외 : 행 기준 바로 위나 바로 아래 값 또는 group by 연산의 결과로 대체
# 결측치 대체: 최빈값
# mode 는 최빈값을 의미
# df3 의 Interaction type 컬럼을 fillna함수를 이용하여 채워주되, mode() 함수를 사용하여 최빈값으로 넣어줌
# mode 함수는 시리즈를 output으로 가집니다.
# 따라서,[0]을 통해 시리즈 중 단일값을 가져와야 합니다.
df3 = df3['Interaction type'].fillna(df3['Interaction type'].mode()[0])
# 결측치 대체: 평균값
df['sw'] = df['sw'].fillna(df['sw'].mean())
df.isnull().sum()
# 결측치 대체: 중간값
# inplace=True 로 하면 원본 데이터가 바뀌게 됩니다.
df['sw'] = df['sw'].fillna(df['sw'].median())
df.isnull().sum()
# 결측치 대체: 바로 위 값으로 대체
df['sw'] = df['sw'].fillna(method='ffill')
df.isnull().sum()
# 결측치 대체: 바로 아래 값으로 대체
df['sw'] = df['sw'].fillna(method='bfill')
#df.isnull().sum()
# 결측치 대체: group by 값으로 대체
# 사전 데이터 확인
df.groupby('Is Amazon Seller')['sw'].median()
# group by한 데이터를 데이터프레임의 컬럼으로 추가하기 위해
# transform 함수 사용
df['sw'] = df['sw'].fillna(df.groupby('Is Amazon Seller')['sw'].transform('median'))
df.isnull().sum()
# 기본구조
# df['sw'].fillna(df.groupby(기준컬럼)[계산할 컬럼].transform(계산방식))
1. 이상치 : 전체 데이터 범위에서 벗어난 아주 작은 값이나 큰 값
but, 정확한 기준에 대한 정답은 없기에 통계적 기법 + 데이터분석가의 주관이 필요
2. 이상치 식별 방법
1) Z-Score(StandardScaler) - ESD
# 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)
# z-score 를 적용할 컬럼 선정
df1 = df[['sw']]
# 표준화 진행
# 표준화 : 평균을 0으로, 표준 편차를 1로
# 데이터를 0을 중심으로 양쪽으로 데이터를 분포시키는 방법
# 표준화를 하게 되면 각 데이터들은 평균을 기준으로 얼마나 떨여져 있는지를 나타내는 값으로 변환
scale_df = StandardScaler().fit_transform(df1)
merge_df = pd.concat([df1, pd.DataFrame(StandardScaler().fit_transform(df1))],axis=1)
merge_df.columns = ['Shipping Weight', 'zscore']
# 이상치 감지
# Z-SCORE 기반, -3 보다 작거나 3보다 큰 경우를 이상치로 판별
mask = ((merge_df['zscore']<-3) | (merge_df['zscore']>3))
# mask 메소드 사용
strange_df = merge_df[mask]
# 총 55 건 탐지
strange_df.count()
2) IQR(Interquartile Range) - 사분위수
# 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
# 이상치 판별 및 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()
3) Isolation Forest (이미지 참고하면 이해하기 쉬움!)
4) DBScan (이미지 참고하면 이해하기 쉬움!)