✅ 회귀 분석
종속변수(Y)와 하나 이상의 독립변수(X) 간의 관계를 추정하여, 연속형 종속변수를 예측하는 통계/머신러닝 기법
ex) “공부한 시간(X)에 따라 시험 점수(Y)가 어떻게 변하는가?” 를 예측
🔸 개요
- 지도학습에서의 분류와 회귀의 차이
- 분류 (Classification) : 결과값이 이산형(클래스 라벨)
- 회귀 (Regression) : 결과값이 연속형(숫자 값)
- 사람의 지능적인 작업을 기계가 수행하도록 만드는 광범위한 개념
- 회귀 모델을 사용하는 이유
- 1️⃣ 미래 값 예측 : 실수값 예측에 사용 ex) 매량, 주가, 온도 등…
- 2️⃣ 인과 관계 해석 (통계 관점) : 특정 독립변수가 종속변수에 미치는 영향력을 해석하기 위해
- 3️⃣ 데이터 기반 의사결정 : 추세 파악, 자원 배분 등
- 회귀 모델 대표적 활용 사례
- 경제 - 주식 가격 예측, 판매량 예측
- 건강 - 혈압, 콜레스테롤 수치 예측
- 제조업 - 불량률, 생산량 예측
🔸 선형 회귀 (Linear Regression)
독립변수(X)와 종속변수(Y)가 선형적(일차 방정식 형태)으로 관계를 맺고 있다고 가정
❓ 선형적 관계
: 변수가 증가하면, 다른 변수도 일정한 비율로 증가/감소 하는 관계
ex) 키가 커지면 몸무게도 증가하는 경향 / 공부 시간을 늘리면 시험 점수가 오르는 경향
- 장점 : 해석 간단, 구현 쉬움
- 단점 : 데이터가 선형성이 아닐 경우 예측력이 떨어짐
- 독립변수 한 개인 상황에서는 직선이 나오는데, 독립변수가 많으면 평면이 나오게 됨
회귀식

- β0 : 절편(intercept) = 편향
- βi : 각 독립변수의 회귀계수(coefficient) = x의 계수 = 가중치 = 파라미터 = 베타
⇒ 독립변수가 많아질수록 항이 늘어난다
선형 회귀 모델 학습 과정
1️⃣ 가중치 (회귀계수) 초기화 ⇒ 베타값을 처음엔 모르니까 아무 값이나 해서 정해둠
2️⃣ 손실함수(Loss Function) 설정 : 주로 MSE(Mean Squared Error) 사용
❓ 손실함수 : 얼마나 오차가 나는지, 손실이 나는지 평가 해주는 지표
⇒ 좋은 베타값은 오차가 적게 나오는 베타값
3️⃣ 최적화 : 수학적인 방법(최소자승법), 경사하강법(Gradient Descent) 등을 통해 가중치 업데이트
4️⃣ 학습 완료 후 : β0, β1, …를 얻어서 새로운 입력 값에 대한 예측 수행
- 예시
- 데이터
- X = 공부 시간, Y = 시험 점수
- (1시간, 40점), (2시간, 50점), (3시간, 60점), (4시간, 70점) …
- 모델
- 데이터

1시간 공부 → 40점, 2시간 공부 → 50점 …
🔎 선형회귀 코드
import numpy as np
import pandas as pd
from sklearn.datasets import load_diabetes
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 = diabetes.data # X : 특성(독립변수)
y = diabetes.target # y : 타겟(종속변수)
print(X.shape)
print(y.shape

📌 train_test_split()
# 2. 학습/테스트 데이터 분리
# 80% 학습용, 20% 테스트용으로 데이터 분할 (재현성을 위한 random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)

: 전체 데이터셋을 학습용 세트와 테스트용 세트로 분할하는 데 사용
📌 LinearRegression()
# 3. 선형회귀 (LinearRegression) 모델
lin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)

- : 종속 변수(대상)와 하나 이상의 독립 변수(특징) 간의 선형 관계를 구하는 것을 목표로 함
- fit() : 모델을 학습하기 위해 객체에 호출되는 메서드
📌 predict()
# 예측
y_pred_lin = lin_reg.predict(X_test)
# 성능 측정
mse_lin = mean_squared_error(y_test, y_pred_lin)
r2_lin = r2_score(y_test, y_pred_lin)
# 평균 비율 오차 - 실제값 대비 예측값이 몇 % 오차가 났는지
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("[LinearRegression 결과]")
print("가중치(coefficient):", lin_reg.coef_)
print("절편(intercept):", lin_reg.intercept_)
print("MSE:", mse_lin)
print("R2 점수:", r2_lin)
print("평균 비율 오차 : ", MPE(y_test, y_pred_lin))

- predict() : 테스트 세트에 대한 예측 수행
- mean_squared_error(x, y) : MSE 오차를 계산하는 어떤 지표. x, y 두 개의 값의 오차 계산
- r2_score(x, y) : 얼마나 예측이 잘 되어져 있는지 점수로 나타내는 값
⇒
10열이 있었기 때문에 가중치는 10개가 나옴.
절편은 베타값을 처음에는 모르니까 임의로 지정해주는 상수값
📌 SGDRegressor()
# 4. SGDRegressor 모델
sgd_reg = SGDRegressor(max_iter=6000, tol=1e-3, random_state=42)
sgd_reg.fit(X_train, y_train)

- : 확률적 경사하강법
# 예측
y_pred_sgd = sgd_reg.predict(X_test)
# 성능 측정
mse_sgd = mean_squared_error(y_test, y_pred_sgd)
r2_sgd = r2_score(y_test, y_pred_sgd)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("[SGDRegressor 결과]")
print("가중치(coefficient):", sgd_reg.coef_)
print("절편(intercept):", sgd_reg.intercept_)
print("MSE:", mse_sgd)
print("R2 점수:", r2_sgd)
print("평균 비율 오차 : ", MPE(y_test, y_pred_sgd))

- 예측 후, MSE와 R2 점수를 통해 모델 성능 확인
🔸 다항 회귀 (Polynomial Regression)
비선형적인 관계를 다항식(polynomial) 형태로 모델링
- ex) 2차 다항식
- 선형 회귀와 다른 점 : 단순 선형항(X) 뿐만 아니라 $X^2, X^3$,... 같은 고차항을 추가해 비선형 패턴을 학습할 수 있다
- 적용 예시
- 제조 공정에서 온도와 반응률 관계가 곡선 형태인 경우
- 건강 데이터에서 나이와 특정 지표(근육량 등)가 단순 선형보다 곡선 형태로 나타나는 경우
- 주의점
- 고차항을 무작정 늘리면 훈련 데이터에는 과도하게 맞춰져 과적합(overfitting) 문제가 발생
- 모델 복잡도와 일반화 성능 간의 균형을 맞춰야 함
🔎 다항회귀 코드
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) 비선형 데이터 생성 (make_friedman1)
# n_samples: 샘플 개수, n_features: 특성 개수, noise: 잡음 크기
X, y = make_friedman1(n_samples=1000, n_features=5, noise=1.0, random_state=42)
print(X.shape)
print(y.shape)

# 2) 학습/테스트 분리
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)

📌 LinearRegression()
# 3) 단순 선형회귀 모델 (비교용)
lin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)
y_pred_lin = lin_reg.predict(X_test)
mse_lin = mean_squared_error(y_test, y_pred_lin)
r2_lin = r2_score(y_test, y_pred_lin)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("[단순 선형회귀 결과]")
print("MSE:", mse_lin)
print("R2:", r2_lin)
print("평균 비율 오차 : ", MPE(y_test, y_pred_lin))
print()

⇒ 비선형을 고려하지 않고, LinearRegression만 적용했을 때의 성능을 MSE, R^2, MPE로 측정
📌 PolynomialFeatures()
# 4) Polynomial Regression (2차 예시)
poly_model = Pipeline([
("poly", PolynomialFeatures(degree=2, include_bias=False)),
("lin_reg", LinearRegression())
])
poly_model.fit(X_train, y_train)
y_pred_poly = poly_model.predict(X_test)
mse_poly = mean_squared_error(y_test, y_pred_poly)
r2_poly = r2_score(y_test, y_pred_poly)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("[다항회귀(2차) 결과]")
print("MSE:", mse_poly)
print("R2:", r2_poly)
print("평균 비율 오차 : ", MPE(y_test, y_pred_poly))

- PolynomialFeatures(degree=2)로 2차 항까지 고려하도록 변한 후, 다시 선형회귀를 적용하는 파이프라인을 구성
- 비선형 패턴을 어느 정도 학습할 수 있으므로, 단순 선형회귀보다 더 좋은 성능이 기대됨 (물론 과적합 위험도 존재
- 결과 비교
- MSE, R^2 등을 비교하여 단순 선형회귀 대비 다항회귀가 Friedman1 데이터셋에서 어떤 차이를 보이는지 확인 가능
- 만약 더 높은 차수(예: 3차, 4차)를 적용하거나, 다른 비선형 모델(예: 랜덤 포레스트, SVM 회귀 등)을 사용하면 성능이 달라질 수 있음
🔸 회귀 모델 평가 방법
🔎 MSE (Mean Squared Error)
- 예측값과 실제값의 차이를 제곱하여 평균
- 오차가 클수록 제곱에 의해 더 큰 벌점이 매겨지므로, 큰 오차에 특히 민감
- 평균 제곱 오차라고도 하며, 회귀 모델 평가에서 매우 자주 사용됨
🔎 MAE (Mean Absolute Error)
- 예측값과 실제값의 차이를 절댓값으로 측정한 후 평균
- 예측이 평균적으로 실제값에서 얼마나 벗어났는지 직관적으로 표현
🔎 RMSE (Root Mean Squared Error)
- MAE와 달리 제곱을 통해 큰 오차에 가중치를 더 주는 특징
- 오차가 클수록 패널티가 커지므로, 큰 오차가 중요한 문제에서 자주 사용
🔎 R² (결정 계수)
- yˉ: 종속변수의 평균
- 값의 범위
- 0 ~ 1 (음수가 될 수도 있음)
- 해석
- 1에 가까울수록 학습된 모델이 데이터를 잘 설명한다고 볼 수 있음
- 0이라면 모델이 종속변수를 전혀 설명하지 못한다는 의미
🔸 고급 회귀 기법 - Ridge & Lasso Regression
선형 회귀에 규제(Regularization) 항을 추가하여 과적합을 방지
🔎 Ridge(릿지) 회귀
- 가중치 제곱합(L2 Norm)을 패널티로 추가
- 효과 : 가중치가 너무 커지지 않도록 방지 (가중치 값을 부드럽게 줄임)
🔎 Lasso(라쏘) 회귀
- 가중치 절댓값합(L1 Norm)을 패널티로 추가
- 효과 : 가중치를 0으로 만들어 변수 선택(Feature Selection) 효과
🔎 릿지회귀 & 라쏘회귀 코드
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
print(X.shape)
print(y.shape)

# 2. 학습/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)

📌 Ridge()
# 3. Ridge 회귀
# alpha=1.0 (규제 세기) 는 필요에 따라 조정 가능
ridge_reg = Ridge(alpha=1.0, random_state=42)
ridge_reg.fit(X_train, y_train)

- L2 규제항을 포함하는 Ridge 모델
- alpha가 클수록 규제 강도가 세어져, 모델 가중치(계수)들의 크기를 더욱 제약
- 학습 후, 예측 결과에 대해 MSE와 R^2 점수를 계산
# 예측
y_pred_ridge = ridge_reg.predict(X_test)
# 성능 평가
mse_ridge = mean_squared_error(y_test, y_pred_ridge)
r2_ridge = r2_score(y_test, y_pred_ridge)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("[Ridge 회귀 결과]")
print(" 가중치(coefficient):", ridge_reg.coef_)
print(" 절편(intercept):", ridge_reg.intercept_)
print(" MSE:", mse_ridge)
print(" R^2 점수:", r2_ridge)
print("평균 비율 오차 : ", MPE(y_test, y_pred_ridge))
print()

📌 Lasso()
# 4. Lasso 회귀
# alpha=0.1 정도로 조금 낮춰 볼 수도 있음 (기본값 1.0)
# alpha가 너무 크면 가중치가 0이 되어 과소적합 위험이 있습니다.
lasso_reg = Lasso(alpha=0.1, random_state=42, max_iter=10000)
lasso_reg.fit(X_train, y_train)

- L1 규제항을 사용하는 Lasso 모델
- alpha가 클수록 일부 가중치가 정확히 0으로 수렴(특성 선택 효과)
- 마찬가지로 MSE, R^2를 통해 성능을 평가
# 예측
y_pred_lasso = lasso_reg.predict(X_test)
# 성능 평가
mse_lasso = mean_squared_error(y_test, y_pred_lasso)
r2_lasso = r2_score(y_test, y_pred_lasso)
# 평균 비율 오차
def MPE(y_true, y_pred):
return np.mean((y_true - y_pred) / y_true) * 100
print("[Lasso 회귀 결과]")
print(" 가중치(coefficient):", lasso_reg.coef_)
print(" 절편(intercept):", lasso_reg.intercept_)
print(" MSE:", mse_lasso)
print(" R^2 점수:", r2_lasso)
print("평균 비율 오차 : ", MPE(y_test, y_pred_lasso))

💥 정리 / Q&A
🔎 정리
- 회귀 모델은 연속형 결과 변수를 예측하는 데 사용
- 선형 회귀는 가장 기본적인 형태지만, 데이터의 패턴이 비선형일 경우 다항 회귀 등을 고려
- 규제(Regularization) 기법을 활용한 모델(Lasso, Ridge)은 가중치를 규제하여 과적합을 방지
- 앙상블 기법(Gradient Boosting, XGBoost 등)을 사용하는 경우 복잡한 비선형 패턴을 더 잘 포착할 수 있다 (추후 배울 내용)
- 모델의 성능 평가는 MAE, RMSE, R² 등 다양한 지표를 통해 진행
🔎 Q&A
📚 Q1: 선형 회귀와 다항 회귀 중 어느 것을 선택해야 하나요?
A1: 데이터의 분포와 잔차(오차) 패턴을 확인하여, 단순 선형 모델로 설명이 어렵다면 다항 회귀를 고려합니다. 먼저, 선형회귀와 다항회귀 모두를 진행해보고 나서 판단해보는 방법도 있습니다.
📚 Q2: Lasso와 Ridge 중 어느 규제 기법을 써야 하나요?
A2: Lasso는 변수 선택(가중치를 0으로 만들어 불필요한 변수 제거)에 유리하며, Ridge는 모든 가중치를 부드럽게 줄여 모델 안정성을 높이는 데 유리합니다. 분석 목적과 데이터 특성에 따라 선택하거나, Elastic Net처럼 두 기법을 혼합하는 방법도 있습니다.
📚 Q3: 앙상블 기법은 항상 선형 회귀보다 좋은가요?
A3: 대부분의 경우 앙상블 기법이 예측 성능이 높지만, 데이터의 규모나 특징, 문제의 복잡도에 따라 다릅니다. 또한 하이퍼파라미터 튜닝이 까다롭고 계산 비용이 큰 단점도 있으므로 상황에 맞춰 선택합니다.
📚 Q4: 회귀 모델에서 독립변수가 많아질수록 항상 성능이 좋아지나요?
A4: 독립변수가 많아지면 모델이 복잡해져 과적합될 가능성이 커집니다. 변수 선택 기법(Feature Selection)이나 규제(Regularization)를 통해 불필요한 변수를 제거하고, 교차검증으로 모델 일반화 성능을 평가해야 합니다.
📚 Q5: 회귀 모델을 만들 때 어떤 지표(R², MAE, RMSE)를 우선적으로 봐야 하나요?
A5: 문제의 특성에 따라 달라집니다. 예측 오차의 크기가 중요하면 RMSE나 MAE, 모델이 데이터를 얼마나 잘 설명하는지 보려면 R²를 사용합니다. 여러 지표를 종합적으로 살펴보는 것이 바람직합니다.
'Sparta > Theory' 카테고리의 다른 글
| [251002] 통계검정 실습 01 - t-test (0) | 2025.10.02 |
|---|---|
| [251001] 머신러닝 04 - 분류 (0) | 2025.10.01 |
| [250929] 머신러닝 02 (0) | 2025.09.29 |
| [250929] 머신러닝 01 (0) | 2025.09.29 |
| [250925] 스파르타코딩 본캠프 38일차 (0) | 2025.09.25 |