본문 바로가기
Bigdata

머신러닝 - 선형 회귀 핵심 정리

by 올엠 2024. 12. 27.
반응형

머신러닝을 할때 선형 회귀는 가장 기본적으로 알고 있어야 하는 알고리즘 이라고 할 수 있다.

선형 회귀는 가장 기초적인 데이터 과학이고 이를 확장하면 자연스럽게 딥러닝까지 이해할 수 있어, 선형회귀에 대해서 여기에서는 다루어보도록 하겠다.

그럼 회귀 알고리즘을 왜 사용하는지에 대해서도 궁금증이 발생할 것이다.

회귀 알고리즘은 주어진 데이터를 기반으로 연속적인 값을 예측하는 데 사용되는 통계적 기법입니다. 주로 두 변수 사이의 관계를 모델링하고, 독립 변수(입력값)가 주어졌을 때 종속 변수(출력값)를 예측하는 데 사용되는데, 일반적인 머신러닝, 데이터 분석, 경제학, 생물학등에서 결과 도출에 많이 사용되어지고, 연속적인 예측값을 도출에 뛰어나다고 할 수 있다.

 

1. 가장 먼저 해야 할 것은? 선형 회귀와 다항 회귀 구분

선형 회귀와 다항 회귀는 특성이 몇개있는지에 따라서 달라지게 된다.

1개의 특성으로 학습한 데이터를 기본적으로 선형 회귀라고 하며 2개 이상의 특성으로 학습한 데이터를 다항 회귀라고 한다.

- 1개의 특성인 선형 회귀를 KNN(K 최근접 이웃) 알고리즘을 통해서 데이터에 없는 결과를 추측할 수 있게 된다.

다항 회귀는 특성이 2개 이상이다 보니, 서로 다른 특성의 오차를 줄이기 위해 규제가 들어가게 된다. 즉 특정 특성에 치우치지 않도록 하기 위해서 만들어진 조건이라고 보면 된다.

이때 많이 사용되는 것이 릿지 회귀, 라쏘 회귀인데, 다항 회귀(특성 2개 이상)의 과적합을 개선하기 위해 나온 알고리즘이다. 릿지 회귀는 L2 정규화를, 라쏘 회귀는 L1 정규화를 사용하는데, 여기서 라쏘는 값이 종종 0이 될 수 있기 때문에 대부분 릿지 회귀를 선호하게 된다. 아래 특성 참조

L2 정규화 (Ridge Regression) 공식:
모델의 손실 함수에 가중치의 제곱합을 페널티 항으로 추가합니다.
특징:
가중치의 제곱합을 사용하기 때문에 모든 가중치가 조금씩 작아집니다. 큰 가중치 값을 더 강하게 억제하여 모델을 단순화합니다. 모든 변수들이 조금씩 영향을 받기 때문에 모델의 가중치를 완전히 0으로 만들지는 않습니다. 비교적 부드럽게 가중치 값을 조절합니다.

L1 정규화 (Lasso Regression) 공식:
모델의 손실 함수에 가중치의 절댓값 합을 페널티 항으로 추가합니다.
특징:
가중치의 절댓값 합을 사용하기 때문에 일부 가중치가 정확히 0이 될 수 있습니다. 변수 선택 효과가 있어 불필요한 변수들을 제거합니다. 희소한 모델을 만들 수 있어 해석이 용이합니다. 변수 선택에 효과적이며, 중요한 변수만을 남기는 경향이 있습니다.

 

2. 릿지 회귀의 정규화를 통해 사용하는 alpha 값

릿지 회귀는 alpha값을 통해서 훈련한 데이터가 여러개의 특성 값으로 인해 발생하는 외곡을 줄 수 있는데,이를 어떻게 가능한지 실제 코드를 통해서 이해해보자.

먼저 관련 라이브러리를 설치하자

pip install numpy pandas matplotlib scikit-learn

 

이후 학습 데이터를 가져와야 하는데, 여기에서는 사이키런에서 기본적으로 제공하는 boston 집값 데이터를 활용해보겠다.

# 데이터셋 로드
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 데이터셋 분할
X = pd.DataFrame(data, columns=["CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX", "PTRATIO", "B", "LSTAT"])
y = pd.Series(target)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

 

이후 실제 값과 선형일때, alpha값을 줬을 때의 차이점을 비교해 보도록 하자.

정확한 비교를 위해서 기본적인 다중 선형 회귀와 릿지 회귀를 알파값을 다르게 주어서 테스트 해보았다.

# 선형 회귀 모델 훈련
lin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)
y_pred_lin = lin_reg.predict(X_test)

# 릿지 회귀 모델 훈련 (alpha=0.1)
ridge_reg_low = Ridge(alpha=0.1)
ridge_reg_low.fit(X_train, y_train)
y_pred_ridge_low = ridge_reg_low.predict(X_test)

# 릿지 회귀 모델 훈련 (alpha=1.0)
ridge_reg = Ridge(alpha=1.0)
ridge_reg.fit(X_train, y_train)
y_pred_ridge = ridge_reg.predict(X_test)

# 릿지 회귀 모델 훈련 (alpha=10.0)
ridge_reg_high_alpha = Ridge(alpha=10.0)
ridge_reg_high_alpha.fit(X_train, y_train)
y_pred_ridge_high_alpha = ridge_reg_high_alpha.predict(X_test)

# 릿지 회귀 모델 훈련 (alpha=100.0)
ridge_reg_high_alpha = Ridge(alpha=100.0)
ridge_reg_high_alpha.fit(X_train, y_train)
y_pred_ridge_highx_alpha = ridge_reg_high_alpha.predict(X_test)


# 선형 회귀 모델 평가
lin_mse = mean_squared_error(y_test, y_pred_lin)
lin_rmse = np.sqrt(lin_mse)
print(f"Linear Regression RMSE: {lin_rmse:.2f}")

# 릿지 회귀 모델 평가 (alpha=0.1)
ridge_low_mse = mean_squared_error(y_test, y_pred_ridge_low)
ridge_low_rmse = np.sqrt(ridge_low_mse)
print(f"Ridge Regression RMSE (alpha=0.1): {ridge_low_rmse:.2f}")

# 릿지 회귀 모델 평가 (alpha=1.0)
ridge_mse = mean_squared_error(y_test, y_pred_ridge)
ridge_rmse = np.sqrt(ridge_mse)
print(f"Ridge Regression RMSE (alpha=1.0): {ridge_rmse:.2f}")

# 릿지 회귀 모델 평가 (alpha=10.0)
ridge_high_alpha_mse = mean_squared_error(y_test, y_pred_ridge_high_alpha)
ridge_high_alpha_rmse = np.sqrt(ridge_high_alpha_mse)
print(f"Ridge Regression RMSE (alpha=10.0): {ridge_high_alpha_rmse:.2f}")

# 릿지 회귀 모델 평가 (alpha=100.0)
ridge_high_alphax_mse = mean_squared_error(y_test, y_pred_ridge_highx_alpha)
ridge_high_alphax_rmse = np.sqrt(ridge_high_alphax_mse)
print(f"Ridge Regression RMSE (alpha=100.0): {ridge_high_alphax_rmse:.2f}")


# 시각화
plt.figure(figsize=(12, 6))
plt.plot(y_test.values, label="True")
plt.plot(y_pred_lin, label="Linear")
plt.plot(y_pred_ridge_low, label="Ridge (alpha=0.1)")
plt.plot(y_pred_ridge, label="Ridge (alpha=1.0)")
plt.plot(y_pred_ridge_high_alpha, label="Ridge (alpha=10.0)")
plt.plot(y_pred_ridge_highx_alpha, label="Ridge (alpha=100.0)")
plt.legend()
plt.show()


print("done")

 

테스트 결과를 보면, 릿지 회귀를 통해 결과 값이 날카롭지 않고 완만해지는 것을 알 수 있다.

 

반응형