AI/머신러닝
실무에 쓰는 머신러닝 기초 1주차 (회귀)
edcrfv458
2025. 3. 13. 14:01
목표
- 휘귀분석 개념
- 규제(Regularization) 기법
- 회귀 모델 평가 지표
1. 회귀 분석 개요
회귀 분석
- 종속 변수(Y)와 하나 이상의 독립 변수(X) 간의 관계를 추정하여, 연속형 종속 변수를 예측하는 통계/머신러닝 기법
- 공부한 시간(X)에 따라 시험 점수(y)가 어떻게 변하는 가를 예측
- 지도 학습에서 분류와 회귀 차이
- 분류: 결과값이 이산형(클래스 라벨)
- 회귀: 결과값이 연속형(숫자 값)
- 사람의 지능적인 작업을 기계가 수행하도록 만드는 광범위한 개념
사용 이유
- 미래 값 예측: 판매가, 주가, 온도 등 실수값 예측에 사용
- 인과 관계 해석(통계 관점): 특정 독립변수가 종속변수에 미치는 영향력을 해석하기 위해
- 데이터 기반 의사결정: 추세(trend) 파악, 자원 배분 등
대표적 활용 사례
- 경제: 주식 가격 예측, 판매량 예측
- 건강: 혈압, 콜레스테롤 수치 예측
- 제조업: 불량률, 생산량 예측규제(Regularization) 기법
- 회귀 모델 평가 지표
2. 선형 회귀(Linear Regression)
가정
- 독립변수(X)와 종속변수(y)가 선형적(일차 방정식 형태)으로 관계를 맺고 있다고 가정
회귀식
- Y = B_0 + B_1*X_1 + B_2*X_2 + B_n*X_n
- B_0: 절편(intercept) ➡️ 편향
- B_i: 각 독립변수의 회귀계수(coefficient) ➡️ 가중치 or 파라미터
선형 회귀 모델 학습 과정
- 가중치(회귀계수) 초기화
- 손실함수(Loss Function) 설정 ➡️ 오차
- 주로 MSE(Mean Squared Error) 사용
- 최적화
- 수학적인 방법(최소자승법), 경사하강법(Gradient Descent) 등을 통해 가중치 업데이트
- 최소자승법: 계산을 해서 베타값 찾는 방법
- 경사하강법: 경험적으로 베타값 찾는 방법
- 수학적인 방법(최소자승법), 경사하강법(Gradient Descent) 등을 통해 가중치 업데이트
- 학습 완료 후
- B_0, B_1 ... 을 얻어 새로운 입력 값에 대한 예측 수행
장단점
- 장점: 해석이 간단하고 구현이 쉬움
- 단점: 데이터가 선형성이 아닐 경우 예측력이 떨어짐
코드
- sklearn 에서 제공하는 데이터는 전처리가 다 되어있음
- 당뇨병 데이터 사용
- LinearRegression: 수학적인 방법
import numpy as np
import pandas as pd
from sklearn.datasets import load_diabets
from sklearn.linear_model import LinearRegression, SGDRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# 1. 데이터 호출
diabetes = load_diabetes()
X = diabets.data
y = diabets.target
# 2. 학습/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3. 선형회귀
model = LinearRegression()
model.fit(X_train, y_train)
# 예측
y_pred = model.predict(X_test)
# 성능
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("가중치:", model.coef_)
print("절편:", model.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred))
- SGDRegressor: 베타 값을 경험적으로 바꿔가며 학습
- max_iter: 학습을 반복할 횟수
- tol: 오차 범위 설정
- 1e-3은 10^-3
model = SGDRegressor(max_iter=6000, tol=1e-3, random_state=42)
model.fit(X_train, y_train)
# 예측
y_pred = model.predict(X_test)
# 성능
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("가중치:", model.coef_)
print("절편:", model.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred))
3. 다항 회귀(Polynomial Regression)
- 비선형적인 관계를 다항식 형태로 모델링
- ex) 2차 다항식 ➡️ Y = B_0 + B_1 * X + B_2 * X^2
- 단순 선형항 뿐만 아니라 고차항을 추가해 비선형 패턴을 학습
적용 예시
- 제조 공정에서의 온도와 반응률 관계가 곡선 형태인 경우
- 건강 데이터에서 나이와 특정 지표(근육량 등)가 단순 선형보다 곡선 형태로 나타나는 경우
주의점
- 고차항을 무작정 늘리면 과적합 문제 발생 가능성 존재
- 모델 복잡도와 일반화 성능 간의 균형을 맞춰야 함
코드
- 일부러 비선형 데이터로 만듦
- n_samples: 샘플의 수
- n_features: 특성의 수
- noise: 잡음 크기
- 다항 회귀
- 비선형 회귀를 할 때는 데이터를 가공해줘야 함 ➡️ PolynomialFeatures
- degree=2 ➡️ 2차 다항식
import numpy as np
import pandas as pd
from sklearn.datasets import make_friedman1
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.pipeline import Pipeline
# 1) 비선형 데이터
X, y = make_friedman1(n_samples=1000, n_features=5, noise=1.0, random_state=42)
# 2) 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3) 다항 회귀
poly_model = Pipeline([
("Poly", PolynomialFeatures(degree=2, include_bias=False)),
("lin_reg", LinearRegression())
])
poly_model.fit(X_train, y_train)
# 예측
y_pred = poly_model.predict(X_test)
# 성능
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("가중치:", poly_model.coef_)
print("절편:", poly_model.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred))
4. 회귀 모델 평가 방법
MSE (Mean Squared Error)
- 예측값과 실제값의 차이를 제곱하여 평균
- 오차가 클수록 제곱에 의해 더 큰 벌점이 매겨지므로, 큰 오차에 민감
- 회귀 모델 평가에서 사용
MAE (Mean Absolute Error)
- 예측값과 실제값의 차이를 절댓값으로 측정한 후 평균
- 예측이 평균적으로 실제값에서 얼마나 벗어났는지 직관적으로 표현
RMSE (Root Mean Squared Error)
- MSE에 root를 씌움
- MAE와 달리 제곱을 통해 큰 오차에 가중치를 더 주는 특징
- 오차가 클수록 패널티가 커지므로 큰 오차가 중요한 문제에 자주 사용
R-2 Score (결정 계수)
- 값의 범위
- 0~1 (음수도 가능)
- 해석
- 1에 가까울수록 학습된 모델이 데이터를 잘 설명한다는 의미
- 0이라면 모델이 종속변수를 전혀 설명하지 못한다는 의미
5. 고급 회귀 기법 - Lasso & Ridge Regression
- 선형 회귀에 규제(Regularization) 항을 추가해 과적합을 방지
Ridge(릿지) 회귀
- 오차에 가중치를 제곱합(L2 Norm)을 더함
- 가중치가 큰 것이 나오면 오차를 크게 만들어 모델을 일반화
- 앞에 람다 값이 있음
- 효과: 가중치가 너무 커지지 않도록 방지 (가중치 값을 부드럽게 줄임)
Lasso(라쏘) 회귀
- 릿지와 같지만 가중치의 절댓값합(L1 Norm)을 패널티로 추가
- 효과: 가중치를 0으로 만들어 변수 선택(Feature Selection) 효과
- 앞에 람다 값이 있음
코드
- 릿지
- alpha가 람다 값
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge, Lasso
from sklearn.metrics import mean_squared_error, r2_score
# 1. 데이터 로드
housing = fetch_california_housing()
X = housing.data
y = housing.target
# 2. 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3. Ridge 회귀
# alpha = 1.0 (규제 세기)는 필요에 따라 조정
ridge_reg = Ridge(alpha=1.0, random_state=42)
ridge_reg.fit(X_train, y_train)
# 예측
y_pred = ridge_reg.predict(X_test)
# 성능
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("가중치:", ridge_reg.coef_)
print("절편:", ridge_reg.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred))
- 라쏘
# Lasso 회귀
# alpha=0.1 정도로 조금 낮춤(기본 1.0)
# alpha 너무 크면 가중치가 0이 되어 과소적합의 위험
lasso_reg = Lasso(alpha=0.1, random_state=42, max_iter=1000)
lasso_reg.fit(X_train, y_train)
# 예측
y_pred = lasso_reg.predict(X_test)
# 성능
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("가중치:", lasso_reg.coef_)
print("절편:", lasso_reg.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred))
실습
import numpy as np
import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge, Lasso
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
diabetes = load_diabetes()
X, y = diabetes.data, diabetes.target
feature_names = diabetes.feature_names
df = pd.DataFrame(X, columns=feature_names)
df['target'] = y
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
ridge = Ridge(alpha=1.0, random_state=42)
ridge.fit(X_train, y_train)
y_pred_ridge = ridge.predict(X_test)
mse = mean_squared_error(y_test, y_pred_ridge)
r2 = r2_score(y_test, y_pred_ridge)
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred_ridge) / y_true) * 100
print("가중치:", ridge.coef_)
print("절편:", ridge.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred_ridge))
lasso = Lasso(alpha=0.1, random_state=42, max_iter=1000)
lasso.fit(X_train, y_train)
y_pred_lasso = lasso.predict(X_test)
mse = mean_squared_error(y_test, y_pred_lasso)
r2 = r2_score(y_test, y_pred_lasso)
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred_lasso) / y_true) * 100
print("가중치:", lasso.coef_)
print("절편:", lasso.intercept_)
print("MSE:", mse)
print("R2:", r2)
print("평균 비율 오차:", MPE(y_test, y_pred_lasso))