Py) 전처리 - ML 회귀모델용 - 01

Py) 전처리 - ML 회귀모델용 - 01

Python으로 머신러닝(ML) 회귀모델에 들어갈 데이터를 전처리하는 방법을 알아보자.


※ 본 내용에서 사용하는 ins_charges.csv 파일은 별도로 다운로드 받아야 한다.
ins_charges.csv 다운받기 [클릭]

개요

실무에서 주어지는 데이터는 바로 머신러닝 모델에 넣기 곤란한 경우가 많다. 그리고 이러한 데이터를 머신러닝 모델에 넣기 위해서는 전처리가 필요하다. 이번 게시물에서는 머신러닝 회귀모델에 들어갈 데이터를 전처리하는 방법을 알아본다.

본 전처리 예제는 다음의 게시물의 내용을 모두 이해하고난 후에 도전하기 바란다.

그리고 다음과 같은 내용을 다룬다.

대분류 소분류 여부
데이터유형 단일 데이터 O
다중 데이터
일반 전처리 문자 데이터 핸들링
숫자 데이터 핸들링
시간 데이터 핸들링
필터링
정렬
피보팅
그룹 연산
축 연산
특정 변수 제거 O
데이터 병합 조인 연산
이어붙이기
이상치 처리 극단치 확인 O
극단치 제거
극단치 대치
결측치 확인 O
결측치 제거 O
결측치 대치
수치형 데이터 처리 단순 데이터 변환
특수 지표 생성
구간화 O
표준화
범주형 데이터 처리 단순 데이터 변환
특수 지표 생성
레이블 인코딩 O
원핫 인코딩 O
데이터 분할 단순 분할
단순 표본추출 O
층화 표본추출

데이터 준비

보험사 고객 데이터를 사용하여 데이터 전처리를 실습하려고 하며 제공되는 데이터(ins_charges.csv)의 각 변수명과 설명은 다음과 같다.

변수명 설명
id 고유 식별자
age 보험 가입자의 나이
gender 보험 가입자의 성별(female, male)
bmi 체질량 지수(BMI, Body Mass Index)
children 보험 가입자의 자녀 수
is_smoker 흡연 여부(yes, no)
region 보험 가입자의 거주 지역
charges 보험료

이제 “ins_charges.csv” 데이터를 다운받아 불러온다.
ins_charges.csv 다운받기 [클릭]

1
2
3
import pandas as pd
df = pd.read_csv("ins_charges.csv")
df.head(2)
id age gender bmi children is_smoker region charges
0 10000 49 female 42.680 2.0 no A 9801
1 10001 32 male 37.335 1.0 no D 4668

전처리

이제 본격적인 전처리를 시작해보자. 전처리를 하기 위해 필요한 각종 라이브러리의 함수와 클래스를 호출하자.

1
2
3
4
from sklearn.model_selection import train_test_split # 데이터셋 분할
from sklearn.preprocessing import MinMaxScaler # 정규화(Min-Max)
from sklearn.preprocessing import OneHotEncoder # One-Hot Encoding
from sklearn.preprocessing import LabelEncoder # Label Encoding

결측치

우선 각 변수별 결측치를 확인한다.

1
2
3
4
5
6
7
8
9
10
df.isna().sum()
## id 0
## age 0
## gender 5
## bmi 5
## children 9
## is_smoker 0
## region 0
## charges 0
## dtype: int64

상기 결과를 보면 gender, bmi, children 변수에 결측치가 있는 것을 확인할 수 있다. 물론 해당 결측치는 Pandas 객체가 결측으로 처리하는 원소에 대한 확인이며 실제 데이터에는 빈칸이나 특수한 텍스트로 결측치가 표현되어 있을 수 있다.

여기에서 크게 두 개의 선택지가 있다. 바로 결측치가 있는 행의 “제거” 또는 “대치”이다. 이번에는 가장 간단하게 결측치가 있는 행을 제거하려고 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
df = df.dropna()
len(df)
## 1306

df.isna().sum()
## id 0
## age 0
## gender 0
## bmi 0
## children 0
## is_smoker 0
## region 0
## charges 0
## dtype: int64

결측치가 있는 행을 제거하였으며 남은 데이터는 1306개가 되었다. 그리고 결측치가 있는 변수는 모두 0개가 되었다. 이렇게 결측치를 처리하고 나서 그 결과를 꼭 확인하도록 하자.

극단치

각 변수에 극단치가 있는지 확인해보자. .agg() 메서드를 사용하기 위해 먼저 수치형 변수를 선별하는 것이 필요할 수 있어서 그 앞에 select_dtypes() 메서드를 사용하였다.

1
df.select_dtypes(include = "number").agg(["min", "mean", "max"])
id age bmi children charges
min 10000.00000 18.0000 15.960000 0.000000 1122.000000
mean 10658.88438 39.2366 30.682967 1.098775 13319.652374
max 11314.00000 64.0000 53.130000 5.000000 63770.000000

당장은 각 변수별로 극단치가 있다고 판단되지 않으므로 극단치 처리는 넘어가도록 한다.

데이터 분할

학습 데이터와 평가 데이터로 분할하기 위해 train_test_split() 함수를 사용한다.

1
2
3
4
5
df_train, df_test = train_test_split(df, train_size = 0.7, random_state = 123)
df_train = df_train.reset_index(drop = True)
df_test = df_test.reset_index(drop = True)
len(df_train), len(df_test)
## (914, 392)

여기서 gender변수에 따른 층화표본추출(stratifed sampling)을 하려면 train_test_split() 함수의 “stratify” 인자에 다음과 같이 gender 변수 데이터를 할당한다.

1
2
3
4
5
6
df_train, df_test = train_test_split(df, train_size = 0.7, random_state = 123,
stratify = df["gender"])
df_train = df_train.reset_index(drop = True)
df_test = df_test.reset_index(drop = True)
len(df_train), len(df_test)
## (914, 392)

정규화

Min-Max 정규화를 하기 위해 MinMaxScaler() 클래스를 사용하자. 해당 클래스를 사용하기 전에 수치형 변수만 뽑기 위해 “ls_cols_drop” 객체에 범주형 변수 목록을 저장하고 .drop() 인자를 활용하여 범주형 변수를 제거하였다. 이 때 .select_dtype() 메서드를 사용하여 수치형 변수만 뽑을 수도 있지만 단순히 표현이 숫자인데 의미는 범주형인 경우가 있을 수 있기 때문에 일부러 .drop() 메서드를 사용하였다.

1
2
3
4
5
6
7
8
9
10
ls_cols_drop = ["id", "region", "charges", "gender", "is_smoker"]
df_train_x_nums = df_train.drop(columns = ls_cols_drop)
df_test_x_nums = df_test.drop(columns = ls_cols_drop)

model_nor = MinMaxScaler().fit(df_train_x_nums)
arr_train_nor = model_nor.transform(df_train_x_nums)
arr_test_nor = model_nor.transform(df_test_x_nums)

df_train_nor = pd.DataFrame(arr_train_nor, columns = df_train_x_nums.columns)
df_test_nor = pd.DataFrame(arr_test_nor, columns = df_test_x_nums.columns)

정규화 된 결과는 다음과 같다.

1
df_train_nor.head(2)
age bmi children
0 0.326087 0.641916 0.2
1 0.826087 0.476190 0.8
1
df_test_nor.head(2)
age bmi children
0 0.717391 0.195050 0.2
1 0.826087 0.641916 0.0

범주형 변수 처리

처리가 필요한 독립변수는 “gender”, “is_smoker”, “region”이다. 여기서 모두 OneHotEncoder() 클래스를 사용하여 처해도 되지만, “gender”와 “is_smoker”는 LabelEncoder() 클래스를 사용하여 처리하고 “region”은 OneHotEncoder() 클래스를 사용하려고 한다. 먼저 labelEncoder() 관련 코드이다.

1
2
3
4
5
6
7
model_label_gender = LabelEncoder().fit(df_train["gender"])
df_train["gender"] = model_label_gender.transform(df_train["gender"])
df_test["gender"] = model_label_gender.transform(df_test["gender"])

model_label_is_smoker = LabelEncoder().fit(df_train["is_smoker"])
df_train["is_smoker"] = model_label_is_smoker.transform(df_train["is_smoker"])
df_test["is_smoker"] = model_label_is_smoker.transform(df_test["is_smoker"])

학습 데이터셋과 평가 데이터셋을 각각 확인해보자.

1
df_train.head(2)
id age gender bmi children is_smoker region charges
0 10182 33 0 39.82 1.0 0 A 4796
1 11118 56 1 33.66 4.0 0 A 12949
1
df_test.head(2)
id age gender bmi children is_smoker region charges
0 10278 51 1 23.21 1.0 1 A 22218
1 10083 56 0 39.82 0.0 0 A 11091

이제 One-Hot Encoding을 하기 위해 “region” 변수를 처리하자. 앞의 labelEncoder() 클래스를 사용한 것과 마찬가지로 OneHotEncoder() 클래스 또한 NumPy 배열을 반환하기 떄문에 Pandas 데이터프레임으로 변환하려면 손이 많이 간다. 그리고 OneHotEncoder() 클래스의 “drop” 인자에 “first”를 할당하여 “region” 변수의 첫 번째 범주를 제거하였다.

1
2
3
4
5
6
7
8
9
10
11
model_OHE = OneHotEncoder(drop = "first", sparse = False).fit(df_train[["region"]])

arr_train_OHE = model_OHE.transform(df_train[["region"]])
df_train_OHE = pd.DataFrame(arr_train_OHE,
columns = model_OHE.get_feature_names(input_features = ["region"]))
df_train_cat = pd.concat([df_train_nor, df_train_OHE], axis = 1)

arr_test_OHE = model_OHE.transform(df_test[["region"]])
df_test_OHE = pd.DataFrame(arr_test_OHE,
columns = model_OHE.get_feature_names(input_features = ["region"]))
df_test_cat = pd.concat([df_test_nor, df_test_OHE], axis = 1)

그럼 학습 데이터셋과 평가 데이터셋을 확인해보자.

1
df_train_cat.head(2)
age bmi children region_B region_C region_D
0 0.326087 0.641916 0.2 0.0 0.0 0.0
1 0.826087 0.476190 0.8 0.0 0.0 0.0
1
df_test_cat.head(2)
age bmi children region_B region_C region_D
0 0.717391 0.195050 0.2 0.0 0.0 0.0
1 0.826087 0.641916 0.0 0.0 0.0 0.0

데이터 통합

이제 모든 전처리가 끝났으니 학습 데이터셋과 평가 데이터셋을 통합하자. 먼저 수치형 변수와 범주형 변수를 통합한다.

1
2
3
4
5
6
df_train_model = pd.concat([df_train[["id", "charges", "gender", "is_smoker"]],
df_train_cat],
axis = 1)
df_test_model = pd.concat([df_test[["id", "charges", "gender", "is_smoker"]],
df_test_cat],
axis = 1)

각각을 확인하면 다음과 같다.

1
df_train_model.head(2)
id charges gender is_smoker age bmi children region_B region_C region_D
0 10182 4796 0 0 0.326087 0.641916 0.2 0.0 0.0 0.0
1 11118 12949 1 0 0.826087 0.476190 0.8 0.0 0.0 0.0
1
df_test_model.head(2)
id charges gender is_smoker age bmi children region_B region_C region_D
0 10182 4796 0 0 0.717391 0.195050 0.2 0.0 0.0 0.0
1 11118 12949 1 0 0.826087 0.641916 0.0 0.0 0.0 0.0

그리고 다음 과정은 바로 머신러닝 단계로 이어지면 관계없으나 일단 저장을 위해서 학습 데이터와 평가 데이터셋을 구분할 수 있는 “Xgrp” 변수를 추가하고 이어붙여 “df_model” 객체를 만든다.

1
2
3
4
5
df_train_model["Xgrp"] = "train"
df_test_model["Xgrp"] = "test"
df_model = pd.concat([df_train_model, df_test_model])

df_model.head(2)
age bmi children region_B region_C region_D charges Xgrp
0 0.326087 0.641916 0.2 0.0 0.0 0.0 4796 train
1 0.826087 0.476190 0.8 0.0 0.0 0.0 12949 train

마무리

적당히 저장하면 끝.

1
df_model.to_csv("model_regression_ins_charges.csv", index = False)
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×