7 Ways to Handle Missing Values in Machine Learning
7 Ways to Handle Missing Values in Machine Learning
데이터셋에서 손실값을 다루는 유명한 전략들
실제 데이터는 많은 손실값(missing value)를 갖는다. 손실값의 원인은 데이터 변질 또는 데이터 기록 실패가 될 수 있다. 손실값 처리는 많은 머신러닝 알고리즘이 손실값을 지원하지 않기 때문에 데이터의 전처리 동안 매우 중요하다.
이 글은 데이터셋에서 손실값을 다루는 7가지 방법에 대해 다룬다.
- Deleting Rows with missing values (손실값을 포함하는 열 삭제)
- Impute missing values for continuous variable (연속형 변수에 대한 손실값 대체)
- Impute missing values for categorical variable (범주형 변수에 대한 손실값 대체)
- Other Imputation Methods (다른 대체 방법들)
- Using Algorithms that support missing values (손실값을 지원하는 알고리즘 사용)
- Prediction of missing values (손실값 예측_
- Imputation using Deep Learning Library — Datawig (딥러닝 라이브러리(Datawig)를 사용한 대체)
데이터는 캐글의 타이타닉 데이터셋(titanic dataset)을 사용한다.
titanic.zip
data = pd.read_csv("train.csv")
msno.matrix(data)
(Image by Author), Visualization of Missing Values: white lines denote the presence of missing value
Delete Rows with Missing Values:
손실값은 null 값을 갖는 열(row) 또는 행(column)을 삭제하여 처리할 수 있다. 행이 열의 절반이상을 null로 가지고 있다면 전체 컬럼을 뺄 수 있다. 하나이상의 컬럼값이 null인 열 또한 뺄 수 있다.
(Image by Author) Left: Data with Null values, Right: Data after removal of Null values
Pros:
- 모든 손실값이 제거되어 훈련된 모델은 견고한 모델을 생성한다.
Cons:
- 많은 정보의 손실
- 손실값의 비율이 전체 데이터셋 대비 과도하다면 제대로 동작하지 않는다.
Impute missing values with Mean/Median: (평균/중간값으로 대체)
수치형 연속 값을 갖는 데이터셋에서 컬럼은 컬럼에서 남은 값의 평균(mean), 중간값(median) 또는 최빈값(mode)으로 대체될 수 있다. 이 방법은 앞선 방법(데이터 삭제)에 비해 데이터의 손실을 막을 수 있다. 위의 두 근사치(평균, 중간값)로의 대체는 손실값을 다루기 위한 통계적인 접근 방법이다.
(Image by Author) Left: Age column before Imputation, Right: Age column after imputation by the mean value
위 예제에서 손실값은 평균값으로 대체되었다. 동일한 방법으로 중간값으로 대체될 수도 있다.
data["Age"] = data["Age"].replace(np.NaN, data["Age"].mean())
data["Age"] = data["Age"].replace(np.NaN, data["Age"].median())
Pros:
- 열 또는 컬럼의 삭제로 이어지는 데이터 손실을 방지
- 작은 데이터셋으로도 잘 동작하고 구현이 쉽다.
Cons:
- 오로지 수치형 연속 변수에서만 동작
- 데이터 누출을 일으킬 수 있음
- 특성간 공분산을 고려하지 않음.
Imputation method for categorical columns: (범주형 대체)
손실값이 범주형 컬럼이라면 손실값은 가장 빈번한 범주로 대체될 수 있다. 만약 손실값의 수가 매우 크다면 새로운 범주로 대체될 수도 있다.
(Image by Author) Left: Data before Imputation, Right: Cabin column after imputation by ‘U’
Pros:
- 열 또는 컬럼의 삭제로 이어지는 데이터 손실을 방지
- 작은 데이터셋으로도 잘 동작하고 구현이 쉽다.
- 유일한 범주를 추가하여 데이터의 손실을 무효화 한다.
Cons:
- 오직 범주형 변수에서만 동작
- 인코딩동안 모델에 새로운 특성의 추가는 나쁜 성능으로 이어질 수 있다.
Other Imputation Methods:
데이터의 본질 또는 데이터 형태에 따라 몇몇 다른 대체 방법이 손실값을 대체는데 더 적합할 수 있다.
예를 들면, 세로방향(경도)의 행동을 하는 데이터 변수에 대해서는 손실값을 채우기 위해 마지막 유효한 관측을 사용하는 것이 타당할 수 있다. 이 방법이 LOCF(Last Observation Carried Forward) 방법이다.
data["Age"] = data["Age"].fillna(method='ffill')
시간 연속적인 데이터셋 변수에 대해서는 손실 데이터에 대한 타임스탬프 전후에 보간법을 사용하는 것이 타당하다.
data["Age"] = data["Age"].interpolate(method='linear', limit_direction='forward', axis=0)
Using Algorithms that support missing values:
모든 머신러닝 알고리즘이 손실값을 지원하는 것은 아니지만 몇몇 ML 알고리즘은 데이터셋내 손실값에 견고하다. K-NN 알고리즘은 값이 없을 때 거리 측정에서 열을 무시할 수 있다. 나이브 베이즈(Naive Bayes) 또한 예측할 때 손실값을 지원할 수 있다. 이러한 알고리즘은 데이터셋이 null 또는 손실값을 포함할때 사용할 수 있다.
파이썬에서 나이브 베이즈와 K-NN의 sklearn 구현은 손실값의 존재를 지원하지 않는다.
여기서 사용할 수 있는 또 다른 알고리즘은 비선형과 범주형 데이터에서 잘 동작하는 랜덤포레스트(random forest)이다. 이 알고리즘은 높은 분산(high variance) 또는 편향(bias) 고려를 포함하여 데이터 구조에 적응한다. 그래서 대규모 데이터셋에서 더 나은 결과를 보인다.
Pros:
- ML 알고리즘이 효과적으로 손실값을 처리하기 때문에 각 컬럼내 손실값을 처리할 필요가 없다.
Cons:
- sckikit-learn 라이브러리에서 이러한 ML 알고리즘의 구현이 없다.
Prediction of missing values:
손실값을 처리하는 앞선 방법에서는 손실값과 다른 변수를 포함하는 변수의 상관관계 이점을 사용하지 않는다. null을 갖지않는 다른 특성을 사용하는 것은 손실값 예측에 사용될 수 있다.
회귀 또는 분류 모델은 손실값을 갖는 특성의 본질(범주형 또는 연속형)에 따라 손실값 예측에 사용될 수 있다.
Here 'Age' column contains missing values so for prediction of null values the spliting of data will be,
y_train: rows from data["Age"] with non null values
y_test: rows from data["Age"] with null values
X_train: Dataset except data["Age"] features with non null values
X_test: Dataset except data["Age"] features with null values
from sklearn.linear_model import LinearRegression
import pandas as pd
data = pd.read_csv("train.csv")
data = data[["Survived", "Pclass", "Sex", "SibSp", "Parch", "Fare", "Age"]]
data["Sex"] = [1 if x=="male" else 0 for x in data["Sex"]]
test_data = data[data["Age"].isnull()]
data.dropna(inplace=True)
y_train = data["Age"]
X_train = data.drop("Age", axis=1)
X_test = test_data.drop("Age", axis=1)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
Pros:
- 앞선 방법보다 더 나은 결과를 보인다.
- 손실값 컬럼과 다른 컬럼간 공분산을 고려한다.
Cons:
- 단지 참값(true value)에 대한 대리값(proxy)로써만 고려된다.
Imputation using Deep Learning Library — Datawig
이 방법은 범주형(categorical), 연속형(continuous), 숫자가 아닌 특성(non-numerical feature)에서 매우 잘 동작한다. Datawig는 데이터그램(datagram)에서 손실값을 대체하기 위해 심층신경망(DNN)을 사용하여 ML 모델을 학습한 라이브러리이다.
# Install datawig library,
pip3 install datawig
Datawig는 dataframe을 취할 수 있고 손실값이 있는 각 컬럼을 위해 다른 모든 컬럼을 입력으로 대체 모델을 맞출 수 있다.(fit)
아래 코드는 Age 컬럼에서 손실값을 대체하는 코드이다.
import pandas as pd
pip install datawig
import datawig
data = pd.read_csv("train.csv")
df_train, df_test = datawig.utils.random_split(data)
#Initialize a SimpleImputer model
imputer = datawig.SimpleImputer(
input_columns=['Pclass','SibSp','Parch'], # column(s) containing information about the column we want to impute
output_column= 'Age', # the column we'd like to impute values for
output_path = 'imputer_model' # stores model data and metrics
)
#Fit an imputer model on the train data
imputer.fit(train_df=df_train, num_epochs=50)
#Impute missing values and return original dataframe with predictions
imputed = imputer.predict(df_test)
Pros:
- 다른 방법 대비 꽤 정확하다.
- CPU와 GPU를 지원한다.
Cons:
- 대규모 데이터셋에서 꽤 느려질 수 있다.
Conclusion
모든 데이터셋은 견고한 모델을 만들기 위해 현명하게 처리되어야 하는 손실값이 있다. 이 글에서는 컬럼 모든 형태에서 손실값을 처리할 수 있는 7가지 방법을 다뤘다. 특정 방식으로 손실값을 처리하는 원칙은 없고 최고의 성능을 갖는 견고한 모델을 얻는 것이 방법이다. 누군가는 데이터가 무엇을 어떻게에 따라 다른 특성으로 다양한 방법을 사용할 수 있다. 데이터셋에 대한 도메인 지식을 갖는 것도 중요하다. 이것은 어떻게 데이터를 처리하고 손실값을 다룰지에 대한 통찰력을 줄 수 있다.
References:
[1] Datawig: https://github.com/awslabs/datawig