본문 바로가기

ML&DL

기초적인 회귀 (Regression) 예측 모델 생성

mpg_regression_sample

seaborn의 기본 데이터셋인 연비(mpg) 예측 데이터를 사용한 회귀 모델 예시입니다.
정확도를 높이는 등의 학습 기법보단 데이터 전처리 위주로 작성하였습니다.

MPG 회귀 (Regression) 예측

0. 필요 library 호출

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
In [2]:
import warnings
warnings.filterwarnings("ignore")

1. 데이터셋 호출 및 탐색

In [3]:
mpg_df = sns.load_dataset('mpg')

구조 파악

In [4]:
print(mpg_df.shape)
mpg_df.head(5)
(398, 9)
Out[4]:
mpg cylinders displacement horsepower weight acceleration model_year origin name
0 18.0 8 307.0 130.0 3504 12.0 70 usa chevrolet chevelle malibu
1 15.0 8 350.0 165.0 3693 11.5 70 usa buick skylark 320
2 18.0 8 318.0 150.0 3436 11.0 70 usa plymouth satellite
3 16.0 8 304.0 150.0 3433 12.0 70 usa amc rebel sst
4 17.0 8 302.0 140.0 3449 10.5 70 usa ford torino

상관 계수 확인

In [5]:
corr = mpg_df.corr()

#mpg와 0.75 이상의 상관계수를 가진 특성들
high_corr = corr.index[abs(corr['mpg']) > 0.75]
corr['mpg'][high_corr].to_frame()
Out[5]:
mpg
mpg 1.000000
cylinders -0.775396
displacement -0.804203
horsepower -0.778427
weight -0.831741
In [6]:
#히트맵으로 확인
plt.figure(figsize=(7,7))
g = sns.heatmap(mpg_df[high_corr].corr(), annot=True, cmap='RdYlBu')

2. 데이터 전처리

  • 머신러닝 학습을 하기 전에 null값을 제거, 카테고리 변수 변경, outlier 제거 등과 같은
    데이터 전처리 작업이 필요합니다.

null값 확인 및 제거 or 채우기

In [7]:
print(mpg_df.isna().sum())
print('shape:', mpg_df.shape)
mpg             0
cylinders       0
displacement    0
horsepower      6
weight          0
acceleration    0
model_year      0
origin          0
name            0
dtype: int64
shape: (398, 9)

제거: horsepower가 null인 행 6개가 제거 되었습니다.

In [8]:
mpg_df = mpg_df.dropna()
print(mpg_df.isna().sum())
print('shape:', mpg_df.shape)
mpg             0
cylinders       0
displacement    0
horsepower      0
weight          0
acceleration    0
model_year      0
origin          0
name            0
dtype: int64
shape: (392, 9)

채우기

  • float/int: 해당 특성값의 평균 (mean)으로 채워줍니다.
  • object: 가장 많이 등장한 값 (mode)으로 채워줍니다.
  • 해당 예제에서는 object인 특성 값이 null인 경우가 없기 때문에, 임의로
    가장 첫번째 열의 origin 값을 null로 만든 후 진행을 해보겠습니다.
In [9]:
#데이터셋 다시 불러오기
mpg_df = sns.load_dataset('mpg')
In [10]:
# 임의로 string null값 생성
mpg_df['origin'][0] = np.nan
In [11]:
# null값이 있는 특성 list 생성
null_col = list(mpg_df.columns[mpg_df.isna().any()])
null_col
Out[11]:
['horsepower', 'origin']
In [12]:
mpg_df.loc[mpg_df.horsepower.isnull()]
Out[12]:
mpg cylinders displacement horsepower weight acceleration model_year origin name
32 25.0 4 98.0 NaN 2046 19.0 71 usa ford pinto
126 21.0 6 200.0 NaN 2875 17.0 74 usa ford maverick
330 40.9 4 85.0 NaN 1835 17.3 80 europe renault lecar deluxe
336 23.6 4 140.0 NaN 2905 14.3 80 usa ford mustang cobra
354 34.5 4 100.0 NaN 2320 15.8 81 europe renault 18i
374 23.0 4 151.0 NaN 3035 20.5 82 usa amc concord dl
In [13]:
mpg_df.loc[mpg_df.origin.isnull()]
Out[13]:
mpg cylinders displacement horsepower weight acceleration model_year origin name
0 18.0 8 307.0 130.0 3504 12.0 70 NaN chevrolet chevelle malibu
In [14]:
# null값을 채운 이후 확인을 위한 index값 받기
horse_null_idx = list(mpg_df.loc[mpg_df.horsepower.isnull()].index)
origin_null_idx = list(mpg_df.loc[mpg_df.origin.isnull()].index)

따로 처리를 하기 위해 type별 list를 생성하고, 해당 type에 맞는 특성 이름을 담아둡니다.

In [15]:
float_int_null_list = []
obj_null_list = []

for col in null_col:
    dtype = mpg_df[col].dtypes
    if dtype == 'float64' or dtype == 'int64':
        float_int_null_list.append(col)
    else:
        obj_null_list.append(col)
In [16]:
print(float_int_null_list)
print(obj_null_list)
['horsepower']
['origin']
In [17]:
# float, int null값 채우기

for col in float_int_null_list:
    mpg_df[col] = mpg_df[col].fillna(mpg_df[col].mean())

# object null값 채우기

for col in obj_null_list:
    mpg_df[col] = mpg_df[col].fillna(mpg_df[col].mode()[0])

null값이 정상적으로 채워졌습니다

In [18]:
mpg_df.loc[horse_null_idx]
Out[18]:
mpg cylinders displacement horsepower weight acceleration model_year origin name
32 25.0 4 98.0 104.469388 2046 19.0 71 usa ford pinto
126 21.0 6 200.0 104.469388 2875 17.0 74 usa ford maverick
330 40.9 4 85.0 104.469388 1835 17.3 80 europe renault lecar deluxe
336 23.6 4 140.0 104.469388 2905 14.3 80 usa ford mustang cobra
354 34.5 4 100.0 104.469388 2320 15.8 81 europe renault 18i
374 23.0 4 151.0 104.469388 3035 20.5 82 usa amc concord dl
In [19]:
mpg_df.loc[origin_null_idx]
Out[19]:
mpg cylinders displacement horsepower weight acceleration model_year origin name
0 18.0 8 307.0 130.0 3504 12.0 70 usa chevrolet chevelle malibu
In [20]:
print(mpg_df.isna().sum().max())
0

object 변수 확인 및 변경

  • 기계는 기본적으로 문자를 인식하지 못하기 때문에, 문자로 된 카테고리 특성의 경우 숫자로
    변경을 해줘야 합니다. 또한, 숫자로 구성된 특성이라 할지라도 카테고리 특성일 경우가 있기 때문에
    사전에 확인이 필요합니다.
In [21]:
mpg_df.head()
Out[21]:
mpg cylinders displacement horsepower weight acceleration model_year origin name
0 18.0 8 307.0 130.0 3504 12.0 70 usa chevrolet chevelle malibu
1 15.0 8 350.0 165.0 3693 11.5 70 usa buick skylark 320
2 18.0 8 318.0 150.0 3436 11.0 70 usa plymouth satellite
3 16.0 8 304.0 150.0 3433 12.0 70 usa amc rebel sst
4 17.0 8 302.0 140.0 3449 10.5 70 usa ford torino
In [22]:
mpg_df.dtypes
Out[22]:
mpg             float64
cylinders         int64
displacement    float64
horsepower      float64
weight            int64
acceleration    float64
model_year        int64
origin           object
name             object
dtype: object

origin과 name 변수를 확인해줍니다.

In [23]:
mpg_df.select_dtypes(include=['object']).head()
Out[23]:
origin name
0 usa chevrolet chevelle malibu
1 usa buick skylark 320
2 usa plymouth satellite
3 usa amc rebel sst
4 usa ford torino
In [24]:
mpg_df['origin'].value_counts()[:10]
Out[24]:
usa       249
japan      79
europe     70
Name: origin, dtype: int64
In [25]:
mpg_df['name'].value_counts()[:10]
Out[25]:
ford pinto            6
amc matador           5
toyota corolla        5
ford maverick         5
amc hornet            4
toyota corona         4
chevrolet impala      4
peugeot 504           4
amc gremlin           4
chevrolet chevette    4
Name: name, dtype: int64

3개의 카테고리로 구성된 origin 변수를 카테고리 타입으로 바꿔줍니다.

In [26]:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
label_origin = le.fit_transform(mpg_df['origin'])
mpg_df['origin'] = label_origin

각 순서별 europe: 0, japan: 1, usa: 2 로 변경이 되었습니다.

In [27]:
mpg_df['origin'].value_counts()
Out[27]:
2    249
1     79
0     70
Name: origin, dtype: int64
In [28]:
# inverse_transform을 통해 원래대로 되돌리는 것도 가능합니다.
# le.inverse_transform(label_origin)

name도 동일하게 변경해줍니다.

In [29]:
mpg_df['name'] = le.fit_transform(mpg_df['name'])

Outlier 확인 및 제거

In [30]:
# 특성 list 생성
mpg_df_col = list(mpg_df.columns)

# 카테고리 특성 따로 분류
mpg_df_cat = mpg_df[['mpg', 'origin', 'name']]
mpg_df.drop(columns=list(mpg_df_cat.columns),inplace=True)

# outlier 개수 확인
q1 = mpg_df.quantile(0.25)
q3 = mpg_df.quantile(0.75)
iqr = q3 - q1
((mpg_df < (q1 - 1.5*iqr)) | (mpg_df > (q3 + 1.5*iqr))).sum().to_frame(name='outliers')
Out[30]:
outliers
cylinders 0
displacement 0
horsepower 11
weight 0
acceleration 9
model_year 0

아래와 같이 scipy.stats의 zscore를 통해 간단히 제거 가능합니다.

In [31]:
from scipy import stats
mpg_df_no_outlier = mpg_df[(np.abs(stats.zscore(mpg_df))< 3).all(axis=1)]
In [32]:
print(mpg_df.shape)
print(mpg_df_no_outlier.shape)
(398, 6)
(391, 6)
In [33]:
#하나의 특성만으로도 제거 가능
# mpg_df_dummy[(np.abs(stats.zscore(mpg_df_dummy['horsepower'])) < 3)]

index를 기준으로 카테고리 특성과 합쳐준 후, 순서를 복원해줍니다.

In [34]:
mpg_df_no_outlier = pd.merge(mpg_df_no_outlier, mpg_df_cat, left_index=True, right_index=True, how='inner')
mpg_df_no_outlier = mpg_df_no_outlier[mpg_df_col]
mpg_df_no_outlier.shape
Out[34]:
(391, 9)
In [ ]:
 

데이터 분리 및 표준화

학습할 데이터, 시험할 데이터를 기존 데이터셋에서 분리해줍니다.

분리

  • 학습: 80%, 시험: 20%로 유지를 해보겠습니다.
In [35]:
from sklearn.model_selection import train_test_split

features = mpg_df_no_outlier.drop(columns=['mpg'])
target = mpg_df_no_outlier['mpg']


#순서는 중요하지 않으므로 shuffle=True로 데이터를 섞어줍니다.
x_train, x_test, y_train, y_test = train_test_split(features, target, test_size=0.2, 
                                                    shuffle=True, random_state=42)
In [36]:
x_train.head()
Out[36]:
cylinders displacement horsepower weight acceleration model_year origin name
66 8 304.0 150.0 3672 11.5 72 2 2
344 4 86.0 64.0 1875 16.4 81 2 217
360 6 145.0 76.0 3160 19.6 81 0 299
224 8 302.0 130.0 4295 14.9 77 2 189
87 8 350.0 145.0 3988 13.0 73 2 55
In [37]:
y_train[:5]
Out[37]:
66     17.0
344    39.0
360    30.7
224    15.0
87     13.0
Name: mpg, dtype: float64

데이터 표준화

  • 특성들이 모두 비슷한 영향력을 가질 수 있도록 표준화를 시켜줘야 합니다.
  • 평균과 표준편차를 사용한 기본 스케일러인 StandardScaler를 사용해보겠습니다.
In [38]:
#기초통계 확인

# stats = mpg_df_no_outlier.loc[:, mpg_df_no_outlier.columns != 'mpg'].describe().transpose()
stats = mpg_df_no_outlier.describe().transpose()
stats
Out[38]:
count mean std min 25% 50% 75% max
mpg 391.0 23.574425 7.738897 9.0 17.5 23.0 29.00 46.6
cylinders 391.0 5.429668 1.688434 3.0 4.0 4.0 7.00 8.0
displacement 391.0 190.604859 101.087297 68.0 102.5 146.0 260.00 440.0
horsepower 391.0 103.147868 35.879049 46.0 76.0 95.0 120.00 215.0
weight 391.0 2956.048593 838.487310 1613.0 2221.5 2790.0 3572.00 5140.0
acceleration 391.0 15.593862 2.625919 8.0 14.0 15.5 17.15 23.7
model_year 391.0 76.048593 3.671120 70.0 73.0 76.0 79.00 82.0
origin 391.0 1.450128 0.772571 0.0 1.0 2.0 2.00 2.0
name 391.0 148.370844 89.122204 0.0 66.5 150.0 224.50 304.0

StandardScaler를 불러온 후, 표준화 진행을 해줍니다

In [39]:
from sklearn.preprocessing import StandardScaler
In [40]:
# 변환 확인 예시를 위한 DataFrame

sc = StandardScaler()
x_train[x_train.columns] = sc.fit_transform(x_train[x_train.columns])
x_train.head(5)
Out[40]:
cylinders displacement horsepower weight acceleration model_year origin name
66 1.490817 1.079574 1.302399 0.824851 -1.565828 -1.170315 0.710266 -1.639014
344 -0.867281 -1.046933 -1.098948 -1.283325 0.359253 1.328730 0.710266 0.763894
360 0.311768 -0.471411 -0.763877 0.224191 1.616448 1.328730 -1.912254 1.680352
224 1.490817 1.060064 0.743946 1.555733 -0.230058 0.218043 0.710266 0.450957
87 1.490817 1.528286 1.162786 1.195571 -0.976517 -0.892643 0.710266 -1.046669
In [41]:
# 변환
x_train_scaled = sc.fit_transform(x_train)
x_test_scaled = sc.fit_transform(x_test)

이제 데이터 전처리 작업이 끝났습니다.

3. 모델 학습 및 시험

간단한 Linear Regression, RandomForest, GradientBoost 3가지로 학습을 해보겠습니다.

In [42]:
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor,  GradientBoostingRegressor
In [43]:
# LR
lr = LinearRegression()
lr.fit(x_train_scaled, y_train)

# 정확도 계산
lr_score = lr.score(x_test_scaled,y_test)
print('LinearRegression: {0:.2f}'.format(lr_score))

# RF
rf = RandomForestRegressor()
rf.fit(x_train_scaled, y_train)

# 정확도 계산
rf_score = rf.score(x_test_scaled,y_test)
print('RandomForest: {0:.2f}'.format(rf_score))

# GB
gb = GradientBoostingRegressor()
gb.fit(x_train_scaled, y_train)

# 정확도 계산
gb_score = gb.score(x_test_scaled,y_test)
print('GradientBoost: {0:.2f}'.format(gb_score))
LinearRegression: 0.77
RandomForest: 0.84
GradientBoost: 0.83

predict를 통한 실제 예측값 확인

In [44]:
lr_res = lr.predict(x_test_scaled)
lr_res
Out[44]:
array([15.54642683, 20.36117534, 18.19866686, 29.29091094, 34.98718544,
       33.21124835, 25.51876221, 32.71973775, 20.78481179, 29.31099684,
       26.51476281, 11.57451555, 27.97815355, 23.94436817, 36.61915828,
       22.28594742, 20.43448519, 25.18127172, 29.1702149 , 29.81521573,
       15.29149184, 18.04218661, 26.17059668, 30.82602986, 25.21369396,
       13.15697348, 30.37911202, 27.67663346, 19.59076687, 31.78196064,
       35.00725153, 24.94263682, 20.48653066, 12.74962567, 19.66037124,
       24.12284879, 30.69987296,  4.83265894, 25.43409484, 25.47116709,
       28.91864967, 27.04330003, 12.16518166, 30.07204461, 26.75183145,
        6.02102455, 27.61091423, 20.34137164, 19.30639364, 22.4454448 ,
       18.54086622, 21.98891802, 23.97331907,  6.89631128, 16.50722942,
       13.11661   , 14.94647409, 34.30534154, 22.42610445, 22.45413329,
       27.40754868, 33.03079408, 25.32943345, 31.40162577, 25.66742153,
       31.01697432, 11.13613912, 19.48336935, 25.16016949, 25.83220151,
       28.98465611, 23.29688981, 27.55034916, 30.43584416, 15.39706556,
       23.99332413, 19.26866436, 26.30046984, 29.67697374])
In [45]:
import copy
x_test_res = copy.deepcopy(x_test)
x_test_res['mpg'] = np.array(y_test)
x_test_res['mpg_pred'] =lr_res
In [46]:
x_test_res[['mpg','mpg_pred']].head()
Out[46]:
mpg mpg_pred
11 14.0 15.546427
45 18.0 20.361175
36 19.0 18.198667
318 29.8 29.290911
376 37.0 34.987185

정리

  • 본 예습에서는 학습 과정에 중점을 두기 보단, 데이터 전처리 기법에 좀 더 초점을 맞춰 진행을 하였습니다.
  • 추후에는 GridSearch, Stacking 및 딥러닝 등의 고도화 된 학습 방법으로 예시를 진행해보겠습니다.