pandas 전처리 (결측치, 이상치처리)

김수경·2024년 3월 27일

파이썬

목록 보기
9/9
import seaborn as sns
df = sns.load_dataset("titanic")

1. 결측치 처리

결측치 삭제

dropna

df.info() #결측치 확인
df.isna().sum() #결측치 확인

#결측치 그래프로 보기
import missingno as msno
msno.bar(df)

# 결측치 있는 행 삭제
df.dropna(axis=0)

#결측치 있는 열 학제
df.dropna(axis=0)

df.dropna(axis=0, how='any')  # 해당 행이나 열에 결측치가 하나라도 있다면 제거. (default)

df.dropna(axis=0, how='all')  # 해당 행이나 열의 '모든 값'이 결측치라면 제거.

df.dropna(axis=1, thresh=800)  # 결측치가 아닌 값이 thresh보다 적게 있을 때 제거. how와 함께 사용 불가.

df.dropna(axis=0, subset=['age'])  # 고려해야할 다른 축의 레이블 (ex. 행을 삭제하는 경우엔 열 지정.)

df.dropna(axis=0, ignore_index=True)  # True로 지정할 경우 결측치가 제거된 DataFrame의  index가 reset됨.

df.dropna(axis=0, ignore_index=True, inplace=True)  # True로 지정할 경우 해당 DataFrame 의 값이 변경됨.

결측치 대치

fillna()

#결측치 0으로 채우기
new_df['age'] = new_df['age'].fillna(0)

#평균값으로 대체
new_df['age'] = new_df['age'].fillna(new_df['age'].mean())

#최빈값으로 대체
new_df['age'] = new_df['age'].fillna(new_df['age'].mode()[0])

fowardfill, backwardfill

import yfinance as yf
import pandas as pd
df1 = yf.download( '005930.KS', '2023-03-01','2024-03-01')  # 종목코드(삼성전자), 시작일자, 종료일자
df2 = yf.download( '035420.KS', '2023-03-01','2024-03-01')   # 종목코드(네이버), 시작일자, 종료일자
df3 = yf.download( '035720.KS', '2023-03-01','2024-03-01')   # 종목코드(카카오), 시작일자, 종료일자

# 각 데이터프레임에서 'High'와 'Volume' 컬럼만 선택하고, 컬럼명 변경
df1_selected = df1[['High', 'Volume']].rename(columns={'High': 'High_samsung', 'Volume': 'Volume_samsung'})
df2_selected = df2[['High', 'Volume']].rename(columns={'High': 'High_naver', 'Volume': 'Volume_naver'})
df3_selected = df3[['High', 'Volume']].rename(columns={'High': 'High_kakao', 'Volume': 'Volume_kakao'})

# 인덱스를 기준으로 세 데이터 프레임 합치기
df_merged = pd.concat([df1_selected, df2_selected, df3_selected], axis=1)
#인덱스 설정
df_merged.index = pd.to_datetime(df_merged.index)

#연습을 위해 임의로 결측치 넣어줌
import numpy as np
np.random.seed(0)  # 재현 가능성을 위해 랜덤 시드 고정

# 모든 컬럼에 대해 10%의 값들을 랜덤으로 선택하여 NaN으로 설정
for column in df_merged.columns:
    # 결측치로 만들 인덱스를 랜덤 선택
    idxs = np.random.choice(df_merged.index, size=int(len(df_merged) * 0.3), replace=False)
    df_merged.loc[idxs, column] = np.nan

# np.random.choice(모집단, random으로 추출할 표본의 size, 복원추출여부(똑같은 값을 또 뽑을 수 있는지 여부))
np.random.choice(df_merged.index, size=int(len(df_merged) * 0.1), replace=False)

#결측치 확인
df_merged.isnull().sum()

ffill(), bfill()

#결측치를 앞 방향으로 채우기(가장 최근의 비결측치로)
df_merged.ffill()
#결측치를 뒷 방향으로 채우기(해당 열에서 이후의 값으로 채우기)
df_merged.fillna(method='ffill')

보간법(interpolation)

#결측치를 선형으로 채움
plt.figure(figsize=(20,10))

plt.plot(df_merged['High_samsung'].interpolate(method='linear'))
plt.plot(df_merged['High_samsung'], marker='o')

# 결측치를 spline(곡선)으로 채움
# 더 과장될 수 있음
plt.figure(figsize=(20,10))
plt.plot(df_merged['High_samsung'].interpolate(method='spline', order=2))
plt.plot(df_merged['High_samsung'], marker='o')

2. 이상치 처리

#주식데이터 불러오기
import yfinance as yf

samsung_df = pd.DataFrame(yf.download('005930.KS', '2023-03-01','2024-03-01'))
naver_df = pd.DataFrame(yf.download('035420.KS', '2023-03-01','2024-03-01'))
kakao_df = pd.DataFrame(yf.download('035720.KS', '2023-03-01','2024-03-01'))


samsung_df = samsung_df[['High', 'Volume']].rename(columns = {'High' : 'High_samsung', 'Volume' : 'Volume_samsung'})
naver_df = naver_df[['High', 'Volume']].rename(columns = {'High' : 'High_naver', 'Volume' : 'Volume_naver'})
kakao_df = kakao_df[['High', 'Volume']].rename(columns = {'High' : 'High_kakao', 'Volume' : 'Volume_kakao'})

z-score 기반 이상치 확인
naver_df['Valume_naver']열 이상치 확인

# 컬럼 선택
data = df_merged['Volume_naver']

# 평균과 표준편차 계산
mean = np.mean(data)
std_dev = np.std(data)

# 각 데이터 포인트에 대한 Z-score 계산
z_scores = [(x - mean) / std_dev for x in data]

# Z-score의 절댓값이 3 이상인 데이터 포인트를 이상치로 판별
outliers = [data[i] for i in range(len(z_scores)) if abs(z_scores[i]) > 3]

print("이상치:", outliers) # 이상치: [2725703, 3102468, 2561625, 3055268, 3013711]

#z-score 값 붙이기
merge_df['Volume_naver_z_score'] = z_scores

boxplot 그래프

df = sns.load_dataset("titanic")
plt.boxplot(df['age'].dropna())
plt.xlabel('age')
plt.show()

IQR

# 1사분위수(Q1)와 3사분위수(Q3) 계산
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)

# IQR 계산
IQR = Q3 - Q1

# 하한과 상한 계산
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 이상치 필터링
outliers = df[(df['age'] < lower_bound) | (df['age'] > upper_bound)]

print("이상치를 포함하는 행:\n")
outliers
profile
잘 하고 있는겨?

0개의 댓글