회귀모델은 다양한 종류가 있지만, 이번 글에서는 "선형회귀모델(LR; Liner Regression Model)"과 "다항회귀모델(PR; Polynomial Regression Model)"에 대해 다루어보려 한다. 선형회귀모델은 단일 독립변수를 기반으로 한 직선을 이용하여 데이터의 선형 관계를 모델링하는 간결한 방법이다. 반면, 다항회귀모델은 독립변수의 거듭제곱을 활용한 곡선을 이용하여 데이터의 비선형 관계를 보다 정교하게 모델링하는 방법이다.
이외에도 다중회귀, 릿지, 라쏘 등과 같은 다양한 회귀모델이 존재하며, 각각의 특성에 따라 적합한 상황에서 활용된다. 또한, 랜덤포레스트나 그레디언트부스트, XGBoost 등의 모델들은 회귀와 분류 문제 모두 적용이 가능하며, 복잡한 데이터 구조를 적절하게 다루는 데 있어 효과적이다.
그러나 이번 글에서는 선형회귀모델과 다항회귀모델(ex. 2차 항)에 초점을 맞춰 원리와 사용 방법, 그리고 선형회귀모델에서 발생할 수 있는 문제점과 그에 대한 해결 방법을 살펴보도록 하겠다.
차례와 사용 툴 및 라이브러리는 아래와 같다.
[차례]
예제 1: 생선 구분하기 - 선형회귀모델
예제 2: 생선 구분하기 - 다항회귀모델(2항)
[순서]
1. 데이터 불러오기
2. 데이터 전처리
- 원본 데이터를 numpy 배열로 변환
- 원본 데이터를 훈련 및 테스트 데이터 세트로 분리
- 독립변수를 2차원 배열로 변환
- 다항회귀모델의 경우, 독립변수의 거듭제곱 항 추가
3. 회귀모델 구축
4. 모델 훈련(학습)
5. 모델 성능 평가
- 훈련 및 테스트 데이터 세트의 결정계수 확인
6. 모델 예측 및 결과 시각화
- 임의 값 입력을 통한 예측
- 추세선 생성을 위한 계수(가중치) 및 y절편 추출
7. 문제점 파악 및 해결방안 제시
- KNN 모델과 선형회귀모델의 비교
- 선형회귀모델에서의 문제: 이상치 데이터의 존재 가능성
- 이에 대한 해결방안: 다항회귀모델을 활용한 이상치 처리
[사용 툴]
- Jupyter notebook(웹 기반 대화형 코딩 환경)
[사용 라이브러리 및 모듈]
- 연산 라이브러리: numpy
- 시각화 라이브러리 및 모듈: matplotlib의 pyplot 모듈
- 머신러닝 라이브러리 및 모델: scikit-learn
- sklearn.linear_model.LinearRegression: 회귀모델 생성
- sklearn.model_selection.train_test_split: 훈련 및 테스트 데이터 세트 분리
예제 1: 생선 구분하기 - 선형회귀모델
1. 데이터 불러오기
# 농어 길이
perch_length = [8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0,
21.0, 21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5,
22.5, 22.7, 23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5,
27.3, 27.5, 27.5, 27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0,
36.5, 36.0, 37.0, 37.0, 39.0, 39.0, 39.0, 40.0, 40.0, 40.0,
40.0, 42.0, 43.0, 43.0, 43.5, 44.0]
# 농어 무게
perch_weight = [5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0,
110.0, 115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0,
130.0, 150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0,
197.0, 218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0,
514.0, 556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0,
820.0, 850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0,
1000.0, 1000.0]
2. 데이터 전처리
2.1 원본 데이터를 numpy 배열로 변환
numpy 라이브러리의 array 함수를 사용하여 원본 데이터를 numpy 배열로 변환한다. 이를 통해, 통계 관련 함수, 선형 함수 등 수학적 연산을 위한 다양한 함수를 제공하고, 다차원의 데이터를 쉽게 처리할 수 있게 된다.
import numpy as np
# 농어 길이
perch_length = np.array(
[8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0,
21.0, 21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5,
22.5, 22.7, 23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5,
27.3, 27.5, 27.5, 27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0,
36.5, 36.0, 37.0, 37.0, 39.0, 39.0, 39.0, 40.0, 40.0, 40.0,
40.0, 42.0, 43.0, 43.0, 43.5, 44.0]
)
# 농어 무게
perch_weight = np.array(
[5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0,
110.0, 115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0,
130.0, 150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0,
197.0, 218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0,
514.0, 556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0,
820.0, 850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0,
1000.0, 1000.0]
)
2.2 훈련 및 테스트 데이터 세트로 분리하기
'train_test_split' 함수를 사용하여 원본 데이터를 훈련 데이터와 테스트 데이터 세트로 분리한다. 해당 함수에는 독립변수(길이), 종속변수(무게), 훈련 및 테스트 데이터의 비율(75:25), 그리고 랜덤 규칙을 인자로 전달한다. 일반적으로 훈련 데이터와 테스트 데이터는 '8:2', '7.5:2.5', '7:3' 등의 비율로 분리한다.
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(perch_length,
perch_weight,
test_size=0.25,
random_state=42)
print(f"{train_input.shape} : {train_target.shape}")
print(f"{test_input.shape} : {test_target.shape}")
2.3 훈련 및 테스트 데이터의 독립변수를 2차원 배열로 변환
reshape 함수를 이용해 훈련 데이터와 테스트 데이트의 전체 행에 대해 1열로 구성된 2차원 배열로 변환한다. 해당 함수의 첫 번째 인자로는 전체 행을 의미하는 '-1'을, 두 번째 인자로는 1열을 의미하는 '1'을 전달한다.
train_input = train_input.reshape(-1, 1)
test_input = test_input.reshape(-1, 1)
print(f"{train_input.shape} / {test_input.shape}")
3. 모델 구축
3.1 라이브러리 호출하기
sklearn 라이브러리에서 회귀모델 생성을 위한 LinearRegression 모듈을 호출한다.
from sklearn.linear_model import LinearRegression
3.2 선형회귀모델 생성하기
LinearRegression 함수를 사용하여 선형회귀모델(lr)을 생성한다.
lr = LinearRegression()
lr
4. 모델 학습(훈련)
선형회귀모델에 fit 함수를 사용하여, 훈련 데이터의 독립변수와 종속변수에 대한 특성의 가중치를 학습시켜 특성의 중요도를 반영하도록 한다. 이는 특성 간의 상호작용을 적절히 고려할 수 있게 하는 것으로, 모델의 예측 성능을 향상시킨다.
lr.fit(train_input, train_target)
5. 모델 성능 평가
5.1 훈련 및 테스트 데이터 세트의 결정계수 확인
훈련 데이터와 테스트 데이터에 score 함수를 적용하여 선형회귀모델(lr)에 대한 결정계수를 학인한다.
train_r2 = lr.score(train_input, train_target)
test_r2 = lr.score(test_input, test_target)
print(f"훈련={train_r2} / 테스트={test_r2}")
5.1.1 해석
- 선형회귀모델의 결정계수를 확인한 결과, 훈련 데이터에 대한 결정계수가 테스트 데이터에 대한 결정계수보다 높게 나타나는 것으로 보아, 이는 '과소적합'이 발생하지 않았음을 알 수 있음
- 그러나 두 결정계수의 차이가 0.12로, 이는 일반적으로 '과대적합'이 의심됨
- 이번에 사용한 선형회귀 모델의 출력 결과는 KNN 모델에 비해 다소 낮은 경향을 보임
- 그러나 KNN 모델의 한계점을 고려하여, 이번 케이스에서는 선형회귀 모델을 사용함
5.1.2 참고
- 과대적합
학습 데이터의 결정계수가 테스트 데이터의 결정계수보다 0.1 이상 높게 나타나는 경우, '과대적합'이 의심된다는 표현을 사용한다. 과적합(과소적합 또는 과대적합)이 발생하는 주요 원인은 다음과 같다:
- 데이터의 수가 충분하지 않을 때
- 모델의 파라미터 튜닝이 적절하지 않을 때
- 모델의 성능이 개선되지 않을 때 등
- KNN 모델의 한계 및 선형회귀모델을 사용한 이유
KNN 모델의 한계는 '거리 기반'의 특성으로 인해 예측하려는 독립변수가 훈련 데이터의 범위를 벗어나면 새로운 예측을 제공하지 못하며, 그 결과 동일한 예측값만을 제공한다는 것이다. 또한, 모든 특성을 동일한 중요도로 취급하여 특성 간의 상호작용을 고려하지 못하는 것이다.
반면, 선형회귀모델은 데이터의 범위를 넘어선 독립변수에 대한 예측도 가능하다. 이는 선형회귀모델이 각 특성의 가중치(계수)를 학습하여, 이를 통해 독립변수의 범위를 초월한 예측값을 계산할 수 있기 때문이다. 또한, 이러한 가중치(계수)는 특성의 중요도를 반영하므로, 특성 간의 상호작용을 적절히 고려하게 된다.
따라서, KNN 모델의 한계점 때문에 특정 상황에서는 선형회귀모델의 사용이 더 적합할 수 있다.
6. 모델 예측 및 결과 시각화
학습된 모델을 통해 임의의 입력 값에 대한 출력 값을 예측하고, 이를 기존의 훈련 데이터와 함께 그래프에 표시함으로써, 모델이 어떻게 데이터를 해석하고 예측하는지를 직접적으로 확인할 수 있다. 이는 모델의 성능을 평가하고, 필요한 경우 모델을 수정하거나 개선하는 데 도움이 된다.
6.1 임의 데이터로 예측하기
predict 함수에 임의의 독립변수 값을 전달하여, 모델이 학습한 관계를 기반으로 해당 독립변수에 대한 종속변수의 예측값을 출력한다.
lr.predict([[50]])
6.1.1 해석
- 선형회귀모델과 KNN 모델의 예측값을 비교하면, 선형회귀모델이 더 높은 예측값을 갖는 것으로 보임
- KNN 모델은 가장 근접한 이웃 데이터를 기반으로 예측값을 도출하는 반면, 선형회귀모델은 전체 데이터 패턴을 가중치(계수)로 학습하여 보다 일반화된 예측을 제공하는 것으로 분석됨
6.2 (추세선을 그리기 위한) 계수(가중치) 및 y절편 추출하기
직선의 방정식(y = ax + b)에 사용되는 계수 'a'와 'b'에 대한 값을 사용하여 추세선(예측선)을 그릴 수 있다.
'lr.coef_'는 'a'에 해당하는 부분으로, 독립변수 'x'의 계수 또는 가중치를 의미한다. 이 값은 'x'가 'y'에 미치는 영향력을 나타내며, 'x'의 변화에 따른 'y'의 변화량(기울기)을 의미한다.
'lr.intercept_'는 'b'에 해당하는 부분으로, y절편을 의미한다. 이 값은 독립변수 'x'가 0일 때, 종속변수 'y'의 값을 나타낸다.
lr.coef_, lr.intercept_
6.3 추세선(예측선) 생성
선형회귀모델에서 'y = ax + b'라는 직선의 방정식을 사용한다. 여기서 'y'는 예측하고자 하는 종속변수, 'x'는 독립변수를 의미하며, 'a'와 'b'는 모델이 학습하여 결정하는 계수(가중치)이다.
plt.plot 함수의 인자로 x 좌표, y 좌표, 스타일 옵션(기본값 실선)을 전달하여 추세선을 생성한다. plt.plot 함수에서 첫 번째 인자는 x 좌표들을 나타내고, 두 번째 인자는 해당 x 좌표들에 대응하는 y 좌표들을 나타낸다. 즉, 이 두 인자는 각각 x 좌표와 y 좌표의 리스트를 제공한다.
import matplotlib.pyplot as plt
#훈련데이터 산점도
plt.scatter(train_input, train_target)
# 예측값 산점도
plt.scatter(50, 1241.839)
# 추세선
plt.plot([0, 50], [lr.coef_ * 0 + lr.intercept_,
lr.coef_ * 50 + lr.intercept_])
plt.xlabel("length")
plt.ylabel("weight")
plt.grid()
plt.show()
위 코드는 x 좌표 '0'과 '50'에 대응하는 y 좌표들을 계산하고, 이 두 점을 잇는 선을 그리라는 의미이다. 이를 통해, 선형회귀모델이 학습하여 얻은 결과(즉, 독립변수와 종속변수의 관계)를 나타내는 추세선이 생성된다.
6.3.1 해석
- 선형회귀모델은 KNN 모델에 비해 훈련 데이터의 범위를 벗어난 독립변수에 대해서도 예측이 가능하며, 임의 값에 대한 예측 성능이 좋아 보임
- 하지만, 모델의 y 절편 값이 음수인 경우 예측값 또한 음수로 나올 가능성이 있어 보임
- 즉, 종속변수인 '무게'가 '0' 이하의 값을 가질 수 없음을 고려하면, 이상치 예측 등의 문제가 발생될 수 있어 보임
- 이로 인해, 이 모델은 현재 사용하는 데이터에 대한 예측에는 부적합해 보임
6.3.2 해결 방안
- y 절편이 음수 값이 나오지 않도록 다항회귀모델(곡선)을 적용하여 모델을 재확인하는 과정이 필요해 보임
예제 2: 생선 구분하기 - 다항회귀모델(2항)
다항회귀모델은 선형회귀모델을 확장한 것으로, 독립변수의 거듭제곱을 추가하여 복잡한 형태의 데이터 패턴을 더 잘 설명할 수 있게 한다. 이는 선형 회귀만으로는 설명이 어려운 비선형 관계를 모델링할 수 있게 해 준다. 여기서는 '2차 다항회귀모델'을 생성하여 위의 추세선과 비교하여 그 효과를 직접 살펴보려 한다.
2차 다항회귀모델의 수식은 다음과 같다.
y = ax^2 + bx + c
여기서 'x^2'와 'x'는 각각 2차 항과 1차 항을 나타내며, 'c'는 y절편을 나타낸다. 'a', 'b', 'c'는 모델 파라미터로, 학습 과정 중에 최적화된다. 이 모델에서 사용하는 독립변수는 원래의 'x' 값과 그 제곱인 'x^2'이며, 이들을 사용해 종속변수 'y'를 예측한다. 다만, 차수를 높이면 높일수록 모델의 복잡도가 증가하므로, 과적합 문제에 주의해야 한다.
1. 데이터 불러오기
데이터는 위의 train_input, train_targer, test_input, test_target 데이터를 사용할 것이다.
2. 데이터 전처리
2.1 훈련 및 테스트 데이터의 독립변수에 거듭제곱 항 추가하기
numpy 라이브러리의 column_stack 함수는 입력된 1-D 배열들을 열 기준으로 쌓아서 2-D 배열을 생성한다. 여기서 'D'는 'Dimension'의 약자로, 차원을 의미한다. 즉, 입력으로 주어진 'train_input**2'와 'train_input'이라는 두 배열을 열 방향으로 쌓아서 더 높은 차원인 새로운 2-D 배열 'train_poly'를 생성한다. 이를 통해, 원래의 독립변수 데이터에 거듭제곱 값을 추가하여, 선형회귀모델이 독립변수의 거듭제곱에 대한 계수(가중치)를 학습하게 함으로써 다양한 회귀를 수행할 수 있게 된다.
train_poly = np.column_stack((train_input**2, train_input))
test_poly = np.column_stack((test_input**2, test_input))
print(train_poly.shape, test_poly.shape)
print(train_poly)
3. 회귀모델 구축
LinearRegression 함수를 사용하여 회귀모델 생성한다.
lr = LinearRegression()
lr
4. 모델 학습(훈련) 시키기
독립변수로 'x^2'과 'x'의 값을 가지는 train_poly를, 종속변수는 train_target을 사용하여 모델을 훈련(학습)시킨다. 이 과정에서 모델 파라미터인 'a', 'b', 'c'는 자동으로 최적화되어, 예측 오차를 최소화하는 최적의 값들로 설정된다. 이렇게 학습된 모델은 주어진 데이터에서 가장 잘 맞는 곡선을 찾아낼 수 있다.
lr.fit(train_poly, train_target)
5. 모델 평가
5.1 훈련 및 테스트 데이터 세트의 결정계수 확인
lr.score(train_poly, train_target)
lr.score(test_poly, test_target)
print(f"훈련:{train_r2} / 테스트:{test_r2}")
5.1.1 해석
- 훈련 데이터의 결정계수가 테스트 데이터의 결정계수보다 0.07 낮은 것으로 보아, 과소적합이 의심됨
6. 모델 예측 및 결과 시각화
6.1 모델 예측하기
predict 함수에 임의의 독립변수 값을 전달하여, 모델이 학습한 관계를 기반으로 해당 독립변수에 대한 종속변수의 예측값을 출력한다.
lr.predict([[50**2, 50]])
6.2 (추세선을 그리기 위한) 계수(가중치) 및 y절편 추출하기
선형모델의 속성인 'lr.coef_'와 'lr.intercept_'를 사용하여 계수(가중치)와 y절편을 확인한다. 'a'는 'x^2'의 계수, 'b'는 'x'의 계수를 의미하며, 'c'는 y절편을 의미한다. 이러한 계수와 y절편은 모델이 학습한 결과로, 이를 통해 'x^2'와 'x'가 'y'에 얼마나 영향을 미치는지 알 수 있다.
print(f"계수={lr.coef_} / 절편={lr.intercept_}")
a = lr.coef_[0]
b = lr.coef_[1]
c = lr.intercept_
print(f"a={a}, b={b}, c={c}")
6.3 추세선(예측선) 생성
plt.plot 함수를 사용하여 추세선을 생성한다. 이 함수는 첫 번째 인자로 x 좌표를, 두 번째 인자로 y 좌표를 전달받는다.
x 좌표로는 numpy 라이브러리의 np.arrange 함수를 사용하여 '0 ~ 51'까지의 배열을 생성하고, y 좌표로는 해당 x 값에 대응하는 2차 방정식의 결과(y = ax^2 + bx + c)를 사용한다. 즉, x 값이 '0'에서 '51'까지 변할 때, 이에 대응하는 y 값을 2차 방정식으로 계산하여 그래프의 추세선으로 그린다.
plt.scatter(train_input, train_target)
plt.scatter(50, pred[0], marker="^")
point = np.arrange(0, 51)
plt.plot(point, a*point**2 + b*point + c)
plt.xlabel("length")
plt.ylabel("weight")
plt.grid()
plt.show()
6.3.1 해석
- 선형회귀모델에서는 음수의 y절편 값이 나타나는 문제가 있었지만, 다항회귀모델을 통해 이 문제를 해결할 수 있었음
- 그러나, '길이'가 10 이하인 독립변수는 모델의 성능에 부정적 영향을 미칠 수 있으므로 사용을 자제하는 것이 좋아 보임
- 다항회귀모델의 훈련과 테스트 데이터에 대한 결정계수를 확인해 보면, 약간의 과소적합이 나타나지만, 이는 여전히 모델이 사용 가능한 수준인 것으로 보임
- 또한, 선형회귀모델에 비해 다항회귀모델에서는 데이터 포인트들이 추세선에 더 가까이 위치하고 있는 것으로 보아, 이는 모델의 예측과 실제 값의 차이, 즉 예측 오차가 더 적다는 것을 의미하며, 이를 통해 다항회귀모델이 더 우수한 성능을 보이고 있다고 판단됨
6.3.2 참고
추세선에 위치하는 값들은 모델이 예측한 값(예측값)을 나타내며, 실제 데이터 포인트가 추세선에 가까운 위치에 있다는 것은 실제 값과 예측 값 사이의 오차가 적다는 것을 의미한다. 이는 모델이 데이터를 잘 예측하고 있다는 것을 나타낸다.
이번 글에서는 선형회귀모델의 특성, 사용 방법, 그리고 KNN 모델과의 차이점을 살펴보았다. 또한 선형회귀모델의 한계점을 극복하기 위해 다항회귀모델을 적용하였고, 이에 대한 특성과 사용 방법, 그리고 선형회귀모델과의 차이점에 대해서도 알아보았다. 다음 글에서는 다중회귀모델에 대해 알아보도록 하겠다.
'[파이썬] > 머신러닝' 카테고리의 다른 글
[머신러닝] 릿지·라쏘모델의 성능비교와 알파값 조정 (0) | 2023.12.25 |
---|---|
[머신러닝] 특성공학을 활용한 다중회귀모델 성능 향상(+예제, 해석, 개념) (0) | 2023.12.24 |
[머신러닝] K최근접이웃모델(KNN) - 회귀분석의 기초(+ 예제) (0) | 2023.12.22 |
[머신러닝] K최근접이웃모델(KNN) - 분류분석의 기초 (1) | 2023.12.20 |
[머신러닝] 머신러닝이란? (Machine Learning, 기계학습) (1) | 2023.12.20 |