결측치 다루기:pandas

Sam (토론 | 기여)님의 2023년 2월 1일 (수) 13:45 판 (→‎채우기)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

1 개요

판다스를 이용하여 결측치를 다루는 방법에 대해 정리한 분류.

2 시작하기 전에

특성공학:pandas를 보고 오자.

결측치를 처리하기 전에 전체적인 데이터셋이 어떤 형태인지 파악할 필요가 있다.

전략 설명 예시
전체형태 파악 df의 형태를 튜플로 반환한다. train data와 test data의 차이를 비교하기 위한 작업으로 봐도 좋겠다. df.shape
칼럼별 형태 파악 df의 칼럼별 기본적인 정보들을 알려준다.
  • 총 몇칼럼인지(칼럼별 데이터형태는 어떠한지.)
  • 칼럼별 NaN이 아닌 데이터가 몇개인지
  • 얼마만큼의 메모리를 먹는지
df.info()
칼럼별 null 파악 칼럼별로 몇 개의 데이터가 비었는지 표시해준다. 위 방법보다 조금 더 간략한 형태. df.isnull().sum()
셀별 null 파악 각 데이터가 비었는지, 채워져 있는지 True, False로 보여준다. pd.isna(df)

3 기본 방향

Kaggle의 'Missing Values'에서 제공한 코드를 약간 변형하여 정리하였다.

3.1 버리기

전략 예시
열 단위
# 열 단위로 버리기
# 결측치가 하나라도 있는 열을 찾는다.
cols_with_missing = [col for col in X_train.columns if X_train[col].isnull().any()]
# 해당 열 버리기
reduced_X_train = X_train.drop(cols_with_missing, axis=1)
reduced_X_valid = X_valid.drop(cols_with_missing, axis=1)
행 단위 버리기
# 행 단위로 버리기
df = df.dropna()  # 하나의 속성이라도 비어있으면 행 째로 버린다.
df = df.dropna(subset = ['검사할열', '검사할열2', ...])  # 검사할 열에 결측치가 있으면 버린다.

3.2 채우기

다양한 방식의 채우기가 가능하다.

fillna 함수를 이용한다.

채우기
from sklearn.impute import SimpleImputer

imputer = SimpleImputer()
imputed_train_X = pd.DataFrame(imputer.fit_transform(train_X))  # 학습용 자료에 결측치 채워넣기.
test_train_X = pd.DataFrame(imputer.transform(test_X))  # 테스트용 데이터에 결측치 채워넣기.(위에서 사용하는 메서드와 다르다. 무슨 차이일까..)
[어떤 값으로 채우는 걸까?]

결측치를 채우는 것만으로도 정밀도가 올라가는 경우가 많다.

SimpleImputer(strategy='median')


평균으로 채우기 열2 안의 결측치를 채우고 싶을 때 단순 평균을 넣을 수도 있지만, 열1이 같은 집단의 평균을 구해 넣는 게 더 정확할 것이다.(예컨대, 평균나이가 빠졌다면 남성의 결측치는 남성의 평균나이를 넣는 것.)

df.filna(df.groupby['열1'])['열2'].transform('median'), inplace=True)

바로 위 데이터로 해당 결측치가 위 데이터와 별반 다르지 않으리라 예상되는 경우 위 데이터의 값을 그대로 사용한다.

df.fillna(method = 'ffill') # 비어 있을 경우, 바로 위 데이터를 입력

바로 아래 데이터로 df.fillna(method = 'bfill') # 비어 있을 경우, 바로 아래 데이터를 입력

3.3 채우고 표시하기

채우고, 표시하기
X_train_plus = X_train.copy()
X_valid_plus = X_valid.copy()

# 해당 값이 원랜 비어있었다는 것을 표시하기 위한 열 만들기.
for col in cols_with_missing:
    X_train_plus[col + '_was_missing'] = X_train_plus[col].isnull()
    X_valid_plus[col + '_was_missing'] = X_valid_plus[col].isnull()

# 채우기
my_imputer = SimpleImputer()
imputed_X_train_plus = pd.DataFrame(my_imputer.fit_transform(X_train_plus))
imputed_X_valid_plus = pd.DataFrame(my_imputer.transform(X_valid_plus))

# imputer가 열 이름을 다 지워버리기 때문에 열을 다시 복사한다.(굳이 열을 다시 살릴 이유가 있나??)
imputed_X_train_plus.columns = X_train_plus.columns
imputed_X_valid_plus.columns = X_valid_plus.columns
복잡한 작업을 했기 때문에 단순 채우기보다 성능이 좋아질 것 같지만.. 오히려 나빠지는 경우도 있다.