본문 바로가기

공부방/Upstage AI Lab 4기

판다스 | 결측치 제거팁

아파트 실거래가 데이터셋을 가지고 판다스 연습하던 과정 중

컬럼 중 is_test라는 컬럼이 테스트셋과 트레인셋을 구분하고 있었다. 이때, 테스트셋에서만 결측치, 그 중에서도 'x' 컬럼에 있는 결측치를 제거하고 싶은 경우.

참고로 is_test는 0과 1 두 개로만 구성되어 있고, 결측치가 없다. 

concat[concat['is_test'] == 1]['x'].isnull().sum()를 하면 is_test가 1인 데이터의 x 컬럼 결측치가 148이 나온다. is_test가 0인 데이터 중에서 x 컬럼 결측치만 제거한다면 is_test가 1인 데이터 중의 결측치 148개는 남아있어야 한다.

그런데 처음에 concat_xclear = concat[concat['is_test'] == 0].dropna(subset=['x'])를 하고, null 값을 체크했더니 x 컬럼의 널값이 모두 0이 돼있다. 당황;; 알고보니 is_test = 1인 데이터를 다시 합져줘야 했던 것! 이러면 x 컬럼 널값이 148로 잘 나온다. 

#is_test = 1인 데이터 중에서 x 컬럼 결측치는 148개 -> 작업 완료 후에 x가 148이 남아있으면 됨.
concat[concat['is_test'] == 1]['x'].isnull().sum()

# is_test = 0인 경우에 대해서만 결측치 제거. 
concat_xclear = concat[concat['is_test'] == 0].dropna(subset=['x'])

#concat_xclear의 x컬럼 null값 확인하면 0으로 나옴.
#is_test = 1인 데이터는 빠져있기 때문. 

#is_test = 1인 데이터들을 다시 합쳐주기
concat_xclear_1 = concat[concat['is_test'] == 1]
concat_xclear = pd.concat([concat_xclear, concat_xclear_1]).sort_index()

여기서 subset에는 딱 하나만 들어갈 필요 없고, 여러 개가 들어가도 된다. 

# 'x', 'y', 'z' 컬럼에서 결측치가 있는 행 제거
# 세 컬럼 중 하나라도 null이 있으면 그 행은 제거됨! 

concat_clean = concat[concat['is_test'] == 0].dropna(subset=['x', 'y', 'z'])

 

참고)

특정 컬럼 안의 결측치가 있는 행을 모두 제거하기 

df_cleaned = df.dropna(subset=['column_name'])
#모든 열이 결측치인 행만 제거
df_cleaned = df.dropna(how='all')

#원본 데이터프레임 수정
df.dropna(inplace=True)

 

혹시 inplace=True를 안에 넣어주면 바로 수정되지 않을까? 해봤는데 안됨.

#잘못된 코드!
concat = concat[concat['is_test'] == 0].dropna(subset=['x'], inplace=True)

'''
dropna() 메서드에 inplace=True를 사용할 때는 할당(=)을 하지 않습니다.
현재 코드는 concat의 부분집합(subset)에만 적용되고 있어, 전체 데이터프레임을 변경하지 않습니다.
'''

대신 인덱스를 사용하면 된다. 이렇게 해도 동일한 결과를 얻을 수 있다. 

# 결측치가 있는 행의 인덱스를 찾기
rows_to_drop = concat[(concat['is_test'] == 0) & (concat['x'].isnull())].index

# 해당 인덱스의 행을 제거
concat = concat.drop(rows_to_drop)