데이터 분석/머신러닝

[ML] 3. 규제 (Regulation)

eunnys 2023. 11. 20. 18:51

① [보스톤 집값 예측]

 

# 패키지 로딩
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, Lasso, Ridge, ElasticNet
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error

import numpy as np
import pandas as pd
# 데이터 로드 및 확인
boston = pd.read_csv('./Dataset/HousingData.csv')
print(boston.shape) # (506, 14)
display(boston.head())

# 결측값이 있는 레코드 삭제
boston.dropna(inplace=True)

# MEDV 주택 가격의 중위값은 종속변수
data_x = boston.drop('MEDV', axis=1) # MEDV 컬럼을 제외한 모든 컬럼은 독립변수
data_y = boston['MEDV']

 

data_x.describe()

 

# 학습, 평가 데이터 분리
scaled_data = StandardScaler().fit_transform(data_x)
x_train, x_test, y_train, y_test = train_test_split(scaled_data, data_y, test_size=0.3, random_state=10)

 
알파값 변화에 따른 회귀계수 및 상관계수 계산
- 알파값 : 규제의 강도를 제어하는 상수, [0, inf) 범위의 부동 소수점 값을 사용할 수 있다.
   - alpha=0이면 LinearRegression에서 사용하는 일반적인 최소제곱법과 같아진다.
- 회귀계수 : weight값
- 상관계수 : r square깂
 

# 규제 비교 함수 (alpha값은 리스트로 반환, 회귀모형 종류) 
def regulation_compare(alpha, model_name):
    df = pd.DataFrame() # 결과를 데이터프레임으로 반환
    for a in alpha:     # alpha값의 종류만큼 반복
        print('회귀모형:', model_name)
        print('알파값:', a)

        if model_name == 'Ridge': 
            model = Ridge(alpha=a)
        elif model_name == 'Lasso':
            model = Lasso(alpha=a)
        elif model_name == 'ElasticNet': # Ridge와 Lasso 혼합 (l1_ratio 비율 지정)
            model = ElasticNet(alpha=a, l1_ratio=0.5)

        model.fit(x_train, y_train)
        print(f'결정계수: {model.score(x_test, y_test):.3f}')
        # 각 독립변수의 weight값을 만들기 위해서 딕셔너리 사용
        # zip(f=컬럼의 이름, w=weight값)
        weight = {f:w for f, w in zip(data_x.columns, model.coef_)}
        y_hat = model.predict(x_test) # 예측값
        # 정답과 예측값을 넣어서 MSE를 구하고 그 값을 근의 값으로 넣어서 RMSE를 구함
        print(f'RMSE: {np.sqrt(mean_squared_error(y_test, y_hat)):.2f}') 
        print('='*20)
        # 시리즈 값으로 딕셔너리를 넣어줌 (딕셔너리의 키가 인덱스가 됨)
        df['alpha='+str(a)] = pd.Series(weight) 

    return df

 
라쏘 회귀모델 생성 (L1 규제)
 

# alpha값은 아주 작은 값부터 시작
alpha = [0.07, 0.1, 0.5, 1, 3]
regulation_compare(alpha, 'Lasso')
# 알파값이 증가할수록 제거되는 항이 많아지고 결정계수는 낮아짐
회귀모형: Lasso
알파값: 0.07
결정계수: 0.796
RMSE: 3.38
====================
회귀모형: Lasso
알파값: 0.1
결정계수: 0.798
RMSE: 3.37
====================
회귀모형: Lasso
알파값: 0.5
결정계수: 0.770
RMSE: 3.59
====================
회귀모형: Lasso
알파값: 1
결정계수: 0.738
RMSE: 3.84
====================
회귀모형: Lasso
알파값: 3
결정계수: 0.585
RMSE: 4.82
====================

 
 
릿지 회귀모델 생성 (L2 규제)
 

alpha = [0, 1, 5, 10, 100]
regulation_compare(alpha, 'Ridge')
# alpha값을 10으로 더 높였을 때 결정계수도 높아지고 오차율도 낮아짐
# 완전히 제외되는 항은 존재하지 않음
회귀모형: Ridge
알파값: 0
결정계수: 0.782
RMSE: 3.50
====================
회귀모형: Ridge
알파값: 1
결정계수: 0.784
RMSE: 3.48
====================
회귀모형: Ridge
알파값: 5
결정계수: 0.791
RMSE: 3.42
====================
회귀모형: Ridge
알파값: 10
결정계수: 0.796
RMSE: 3.39
====================
회귀모형: Ridge
알파값: 100
결정계수: 0.776
RMSE: 3.54
====================

 
엘라스틱 회귀모델 생성 (L1 + L2)
 

alpha = [0, 1, 5, 10, 100]
regulation_compare(alpha, 'ElasticNet')
# L1 규제 특성 포함 -> 알파값이 증가할수록 결정계수가 확 낮아짐
회귀모형: ElasticNet
알파값: 0
결정계수: 0.782
RMSE: 3.50
====================
회귀모형: ElasticNet
알파값: 1
결정계수: 0.725
RMSE: 3.93
====================
회귀모형: ElasticNet
알파값: 5
결정계수: 0.406
RMSE: 5.77
====================
회귀모형: ElasticNet
알파값: 10
결정계수: 0.108
RMSE: 7.07
====================
회귀모형: ElasticNet
알파값: 100
결정계수: -0.014
RMSE: 7.54
====================

 


 

② [대한민국 육군 몸무게 예측하기]

 

# 패키지 로딩
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, Lasso, Ridge
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error, r2_score

import numpy as np
import pandas as pd
# 데이터 로드 및 확인
army = pd.read_csv('./Dataset/Army-Dataset.csv')
print(army.shape) # (59996, 7)
display(army.head())

 

# Seq 컬럼 삭제
army.drop('Seq', axis=1, inplace=True)
army.describe()

 

# Weight는 종속변수, 나머지는 독립변수
data_x = army.drop('Weight', axis=1) 
data_y = army['Weight']
# 독립변수간 상관관계 확인
import seaborn as sns
import matplotlib.pyplot as plt
sns.pairplot(data_x)
plt.show()

 

data_x.corr()

 

# 데이터 스케일링
# 스케일러를 먼저 만들고 transform으로 변형, fit과 transform 분리
scaler = StandardScaler().fit(data_x)
scaled_data = scaler.transform(data_x)

# 학습, 평가 데이터 분리
x_train, x_test, y_train, y_test = train_test_split(scaled_data, data_y, test_size=0.2, random_state=10)
ridge_alpha = 10
lasso_alpha = 1
linear = LinearRegression()
ridge = Ridge(alpha=ridge_alpha)
lasso = Lasso(alpha=lasso_alpha)
linear.fit(x_train, y_train)
ridge.fit(x_train, y_train)
lasso.fit(x_train, y_train)
# 예측 및 평가
linear_y_hat = linear.predict(x_test)
ridge_y_hat = ridge.predict(x_test)
lasso_y_hat = lasso.predict(x_test)
# r2_score는 정답과 예측값을 넣어줌
linear_r2 = r2_score(y_test, linear_y_hat) 
ridge_r2 = r2_score(y_test, ridge_y_hat)
lasso_r2 = r2_score(y_test, lasso_y_hat)

linear_mae = mean_absolute_error(y_test, linear_y_hat)
ridge_mae = mean_absolute_error(y_test, ridge_y_hat)
lasso_mae = mean_absolute_error(y_test, lasso_y_hat)

print(f'R2 score - Linear: {linear_r2:.2f}, Ridge: {ridge_r2:.2f}, Lasso: {lasso_r2:.2f}')
print(f'MAE score - Linear: {linear_mae:.2f}, Ridge: {ridge_mae:.2f}, Lasso: {lasso_mae:.2f}')
# 규제를 썼을 때와 안 썼을 때 차이 없음
R2 score - Linear: 0.89, Ridge: 0.89, Lasso: 0.88
MAE score - Linear: 3.54, Ridge: 3.54, Lasso: 3.68

 

# 모든 컬럼의 0행 확인
data_x.iloc[0]
Chest      96.3
Height    185.5
Waist      82.5
Head       57.1
Foot       28.5
Name: 0, dtype: float64

 

# 새로운 값이 들어왔을 때의 예측
# 가슴둘레 90, 키 178, 허리둘레 80, 머리둘레 55, 발길이 26.5
new_data = np.array([90, 178, 80, 55, 26.5]).reshape(1,5) # 1행5열의 2차원으로 변환
linear.predict(scaler.transform(new_data)) # 그냥 new_data값을 넣어주면 값이 너무 크게 나오기 때문에 스케일러를 써줘야 함
array([65.2490275])