본문 바로가기

머신러닝/지도학습

[Machine Learning] 결정트리_회귀(Regression) 실습 사례- 보험비

320x100

 

 

서론

 

보험료는 우리 삶에 큰 영향을 끼치는 중요한 수치 중 하나입니다.

 

어떤 요소가 보험료에 영향을 미치고, 어떤 것이 보험료를 낮추는지 알아맞춘다면

여러분이 더 윤택한 삶을 사는데 도움을 주겠죠?

 

질병의 있고 없음이 보험료에 영향을 미칠까요? 성별이 영향을 미칠까요.

혹은 흡연 여부가 영향을 미칠까요? 이름이 영향을 미치진 않을까요?

 

 

이번 시간에는 지난번에 했던 Decision Tree를 이용하여, 범주형 데이터가 아닌

연속형 데이터를 사용하여 회귀 문제로 해외 건강보험에 대한 실제 사례를 분석해보겠습니다.

 

 

원본 csv 데이터는 캐글의 insuarance 데이터로, 짧은 크기에 feature를 갖고 있는

데이터 프레임 입니다.

아래 원본 링크에서 보실 수 있습니다.

 

 

https://www.kaggle.com/datasets/awaiskaggler/insurance-csv

 

Insurance Csv

 

www.kaggle.com

 

목표는 보험비용(expenses)에 대한 예측입니다.

사용하는 알고리즘은 연속형데이터인 관계로 결정트리의 회귀학습 입니다.

 

이 시간도 실습을 서술한 글이기 때문에, 오류와 오판이 있을 수 있음에 양해 드립니다

 

시작 , 파일 로드부터

 

필자는 직접 다운로드 받아서, insurance.csv파일을 colab에 업로드 후

직접 로드해서 진행했습니다.

 

먼저, 필요한 라이브러리를 불러왔습니다.

 

# 필요한 라이브러리 호출
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import sklearn

 

로드하여 원본을 확인합니다.

 

df = pd.read_csv('insurance.csv')
df

 

왼쪽부터 나이, 성별, bmi(체질량지수), 자녀 수, 흡연 여부, 지역(southwest, southeast,

northwest, northeast로 나뉩니다) , 비용입니다.

종속변수는 expenses(비용)가 되겠네요.

 

# 데이터 확인중
df.head()

 

type들도 확인해봅니다.

 

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1338 entries, 0 to 1337
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   age       1338 non-null   int64  
 1   sex       1338 non-null   object 
 2   bmi       1338 non-null   float64
 3   children  1338 non-null   int64  
 4   smoker    1338 non-null   object 
 5   region    1338 non-null   object 
 6   expenses  1338 non-null   float64
dtypes: float64(2), int64(2), object(3)
memory usage: 73.3+ KB

 

데이터 성질도 확인합니다.

 

df.describe()

 

소숫점이 과다하게 길어지는 관계로, 2개 정도로 줄이겠습니다.

 

pd.options.display.float_format = "{:.2f}".format #소수점 조정

 

이번에도 역시, 데이터 전처리가 필요하겠죠?

컴퓨터가 읽었을때 문제가 생기지 않도록 데이터의 object를 다듬고

결측치가 나오지 않도록 다듬어주는 과정은 중요합니다🤳

 

먼저 object값에 대해서 확인해봅니다.

 

df.describe(include="O")
# sex, smoker, region 피쳐

 

일단 성별과 지역은 나중에 하고, smoker부터 볼까요.

 

smoker(흡연 여부)에 대해서 value들을 확인해봅니다.

아마 피운다/안피운다로 나뉠것 같네요.

 

df.smoker.value_counts()
no     1064
yes     274
Name: smoker, dtype: int64

 

no가 1064네요. 숫자로 변환하기 위해서

yes에 1을 곱하겠습니다.

 

(df.smoker == 'yes')*1 # yes한 사람 1
0       1
1       0
2       0
3       0
4       0
       ..
1333    0
1334    0
1335    0
1336    0
1337    1
Name: smoker, Length: 1338, dtype: int64

 

smoker자체를 int타입으로 바꾸기 위해 저장시킵니다.

 

# smoker를 int타입으로 조작
df.smoker = (df.smoker == 'yes')*1
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1338 entries, 0 to 1337
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   age       1338 non-null   int64  
 1   sex       1338 non-null   object 
 2   bmi       1338 non-null   float64
 3   children  1338 non-null   int64  
 4   smoker    1338 non-null   int64  
 5   region    1338 non-null   object 
 6   expenses  1338 non-null   float64
dtypes: float64(2), int64(3), object(2)
memory usage: 73.3+ KB

 

좋습니다. 이제 sex와 region 데이터들을 수정해야겠습니다.

사용하는 처리방법은 one-hot encoding 입니다.

 

# sex, region 피쳐 수정

pd.get_dummies(df, columns = ['sex','region'])

 

이미지는 추가작업을 한 후에 띄울 것인데요?

 

이때, dummy 변수를 만들어서 각 변수별로 1, 0 으로 표현하는

방식을 사용할 것입니다. (one-hot)

그 과정에서 성별의 경우, 여성/남성 중 0이나 1로 표현되는

한 가지 column만 필요로 하므로 하나는 제거해줍니다.

 

지역의 경우에도, 북서, 북동, 남서, 남동 네 가지 중

한 가지 데이터 정도는 0,1 둘중 하나로 표현되므로 제거해줍니다.

 

# 불필요한 열 drop
dfdrop = pd.get_dummies(df, columns = ['sex','region'], drop_first = True)
dfdrop

 

이제 사용할 데이터프레임으로 저장해줍니다.

 

df = dfdrop
df

 

이제 훈련셋과 시험셋을 분리하면서, 모델링을 시작하겠습니다.

 

# 훈련셋과 시험셋 분리 시작
# 패키지 호출

from sklearn.model_selection import train_test_split

 

독립변수, 종속변수를 지정합니다.

 

X = df.drop('expenses', axis = 1)
y = df['expenses']

# 훈련

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)

 

훈련이 되었습니다. 이제 사이킷런에 내장되있는 패키지를 불러올것 인데요.

DecisionTreeRegressor를 사용합니다.

 

# 모델링
# DecisionTreeRegressor 패키지 호출

from sklearn.tree import DecisionTreeRegressor

 

결정트리 회귀에서 랜덤값은 위에서 훈련셋/시험셋 분리할때의

랜덤값과 동일하게 해야 합니다.

 

# 모델 설정

model = DecisionTreeRegressor(random_state=10)

 

작성한 모델을 적용하겠습니다.

 

# 모델 적용
model.fit(X_train, y_train)
pred = model.predict(X_test)

 

예측값은 pred를 뽑으면 조회됩니다.

여기서는 분량이 길어지므로 생략하겠습니다.

 

모델 평가를 진행합니다.

mean_squarred_error 패키지를 호출합니다.

 

# mean_squared_error 호출

from sklearn.metrics import mean_squared_error

 

평균제곱오차를 구합니다.

 

# mse 계산

mse = mean_squared_error(y_test, pred)
mse
51670746.29778283

 

에러는 작을수록 효과적인 예측을 했다는 증명입니다.

rmse는 mse에 루트를 씌워서 구합니다.

 

# rmse 계산

rmse = mean_squared_error(y_test, pred, squared = False)
rmse
188.236661225257

 

결정계수 R^2를 구합니다.

 

# 결정계수 계산

R_2 = model.score(X_train, y_train)
R_2
0.6315829603764953

 

마지막으로, 결정트리를 위한 시각화 패키지를 호출합니다.

 

# 트리 시각화
# plot_tree 호출
from sklearn.tree import plot_tree

 

시각화를 진행합니다.

 

트리의 깊이가 너무 깊어질 경우, 학습이 과적합(over-fitting)되어

도리어 실용적으로 사용하기 힘든 모델이 될 수 있겠죠?

 

# max_depth 6로 제작
plt.figure(figsize=(18,10))
plot_tree(model, max_depth = 6, fontsize = 15, feature_names = X_train.columns)

 

깊이는 6으로 지정했습니다. feature name은 독립변수 학습셋의

컬럼을 지정하여, 피쳐별로 나타날 수 있도록 했구요.

 

 

이상으로, 결정트리를 사용한 회귀문제를 진행해보았습니다.

다음 시간에도 다양한 문제 해결 사례를 제시해보겠습니다.

 


 

728x90