회귀는 연속형 변수 값 중에 어떠한 값으로 결정(예측)하는 작업입니다.
독립 변수에 따라 결정(예측)할 종속 변수가 연속형 변수일 때 회귀 모델을 선택합니다.
파이썬의 머신 러닝 모듈인 사이킷 런에서는 다양한 회귀 모델을 제공하고 있습니다.
사이킷 런의 지도 학습 모델은 대부분 회귀와 분류 작업을 위한 모델을 제공합니다.
사이킷 런의 지도 학습 모델 – 회귀, 분류
Supervised learning 메뉴얼 사이트
사이킷 런의 회귀 모델 종류
사이킷 런에서는 다양한 회귀 모델을 제공합니다.
다음은 크게 회귀 모델을 제공하는 알고리즘과 대표적인 모델 이름입니다.
- 선형 모델 – LinearRegression
- 서포트 벡터 머신 – SVR
- 이웃 – KNeighborsRegressor
- 트리 – DecisionTreeRegressor
- 앙상블 – RandomForestRegressor
이들을 사용하기 위해 모듈 포함문은 다음과 같습니다.
from sklearn.linear_model import LinearRegression #선형 회귀
from sklearn.svm import SVR #서포트 벡터 머신 회귀
from sklearn.neighbors import KNeighborsRegressor #K 최근접 이웃 회귀
from sklearn.tree import DecisionTreeRegressor #결정 트리 회귀
from sklearn.ensemble import RandomForestRegressor #랜덤 포리스트 회귀
이러한 모델의 알고리즘은 별도의 항목에서 다루기로 할게요.
사용할 데이터
회귀 모델을 사용하는 예는 사이킷 런에서 제공하는 당뇨병 환자 데이터를 사용할게요.
sklearn.datasets.load_diabetes(*, return_X_y=False, as_frame=False, scaled=True)
당뇨병 환자 데이터
from sklearn.datasets import load_diabetes #당뇨병 환자 데이터 로드
from sklearn.model_selection import train_test_split #학습 및 테스트 데이터 분리
import pandas as pd
먼저 데이터를 로드한 후 간단히 살펴봅시다.
data 키에는 독립 변수, target은 종속 변수, feature_names는 독립 변수의 특성 이름들입니다.
diabetes = load_diabetes()
data = diabetes.data #나이, 성별, 체질량지수, 혈압, 콜레스트롤, 혈당 수치 등
target = diabetes.target #1년 후 질병 진행에 대한 실제 정량적 측정
df = pd.DataFrame(data,columns = diabetes.feature_names)
df['target'] = target
display(df.head(3))
![당뇨병 환자 데이터](https://ehpub.co.kr/wp-content/uploads/2023/08/당뇨병-환자-데이터.jpg)
독립 변수는 10개의 특성으로 구성하고 있습니다.
print(diabetes.DESCR)
[out]
.. _diabetes_dataset:
Diabetes dataset
----------------
Ten baseline variables, age, sex, body mass index, average blood
pressure, and six blood serum measurements were obtained for each of n =
442 diabetes patients, as well as the response of interest, a
quantitative measure of disease progression one year after baseline.
**Data Set Characteristics:**
:Number of Instances: 442
:Number of Attributes: First 10 columns are numeric predictive values
:Target: Column 11 is a quantitative measure of disease progression one year after baseline
:Attribute Information:
- age age in years
- sex
- bmi body mass index
- bp average blood pressure
- s1 tc, total serum cholesterol
- s2 ldl, low-density lipoproteins
- s3 hdl, high-density lipoproteins
- s4 tch, total cholesterol / HDL
- s5 ltg, possibly log of serum triglycerides level
- s6 glu, blood sugar level
Note: Each of these 10 feature variables have been mean centered and scaled by the standard deviation times the square root of `n_samples` (i.e. the sum of squares of each column totals 1).
Source URL:
https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html
For more information see:
Bradley Efron, Trevor Hastie, Iain Johnstone and Robert Tibshirani (2004) "Least Angle Regression," Annals of Statistics (with discussion), 407-499.
(https://web.stanford.edu/~hastie/Papers/LARS/LeastAngle_2002.pdf)
aeg: 나이
sex: 성별
bmi: 체질량 지수
bp: 평균 혈압
s1: 혈청 콜레스트롤 총량
s2: 저밀도 지단백질
s3: 고밀도 지단백질
s4: 콜레스트롤 총량
s5: possibly log of serum triglycerides level
s6: 혈당 수치
참고로 종속 변수는 1년 후 질병 진행에 대한 실제 정량적 측정 값이라고 나와 있네요.
개략적으로 독립 변수와 종속 변수의 타입과 개수를 확인해 봅시다.
print(df.info())
[out]
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 442 entries, 0 to 441
Data columns (total 11 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 age 442 non-null float64
1 sex 442 non-null float64
2 bmi 442 non-null float64
3 bp 442 non-null float64
4 s1 442 non-null float64
5 s2 442 non-null float64
6 s3 442 non-null float64
7 s4 442 non-null float64
8 s5 442 non-null float64
9 s6 442 non-null float64
10 target 442 non-null float64
dtypes: float64(11)
memory usage: 38.1 KB
None
보시는 것처럼 442개의 데이터가 있습니다.
모두 결측치(NULL)가 없고 수치(float64)라는 것을 알 수 있습니다.
기본 통계값도 확인합시다.
print(df.describe())
[out]
age sex bmi bp s1 \
count 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02
mean -2.511817e-19 1.230790e-17 -2.245564e-16 -4.797570e-17 -1.381499e-17
std 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02
min -1.072256e-01 -4.464164e-02 -9.027530e-02 -1.123988e-01 -1.267807e-01
25% -3.729927e-02 -4.464164e-02 -3.422907e-02 -3.665608e-02 -3.424784e-02
50% 5.383060e-03 -4.464164e-02 -7.283766e-03 -5.670422e-03 -4.320866e-03
75% 3.807591e-02 5.068012e-02 3.124802e-02 3.564379e-02 2.835801e-02
max 1.107267e-01 5.068012e-02 1.705552e-01 1.320436e-01 1.539137e-01
s2 s3 s4 s5 s6 \
count 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02
mean 3.918434e-17 -5.777179e-18 -9.042540e-18 9.293722e-17 1.130318e-17
std 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02
min -1.156131e-01 -1.023071e-01 -7.639450e-02 -1.260971e-01 -1.377672e-01
25% -3.035840e-02 -3.511716e-02 -3.949338e-02 -3.324559e-02 -3.317903e-02
50% -3.819065e-03 -6.584468e-03 -2.592262e-03 -1.947171e-03 -1.077698e-03
75% 2.984439e-02 2.931150e-02 3.430886e-02 3.243232e-02 2.791705e-02
max 1.987880e-01 1.811791e-01 1.852344e-01 1.335973e-01 1.356118e-01
target
count 442.000000
mean 152.133484
std 77.093005
min 25.000000
25% 87.000000
50% 140.500000
75% 211.500000
max 346.000000
10개의 특성들은 평균 값이 0에 가깝고 최솟값은 -0.1, 최댓값은 +1.0 근처의 값입니다.
종속 변수인 target은 25~346사이의 수치로 되어 있네요.
회귀 모델을 사용하기 위해 학습 데이터, 검증 데이터, 평가 데이터로 분리해 보기로 합시다.
*검증 데이터는 학습 데이터의 일부로 구성합니다.
x_train, x_test, y_train, y_test = train_test_split(data,target)
x_train_,x_val, y_train_,y_val = train_test_split(x_train,y_train)
print(y_train.shape, y_val.shape, y_test.shape)
[out]
(331,) (83,) (111,)
현재 학습 데이터는 331개, 검증 데이터는 83개, 테스트 데이터는 111개로 분리하였습니다.
모델 생성 및 학습
여러 가지 회귀 모델을 생성하고 학습한 후 어느 모델이 나은지 파악해 봅시다.
먼저 모델들을 생성하여 models 리스트에 보관할게요.
models = []
models.append(LinearRegression())
models.append(SVR())
models.append(KNeighborsRegressor())
models.append(DecisionTreeRegressor())
models.append(RandomForestRegressor())
models에 있는 각 모델을 순차적으로 학습 및 검증 데이터로 평가 해 봅시다.
참고로 회귀 모델은 R2 결정 계수를 이용하여 평가하는 것이 디폴트입니다.
R2 결정 계수에 관한 사항은 다음 항목(4. 회귀 모델 평가 도구)에서 다루기로 할게요.
from sklearn.metrics import r2_score #r2 결정 계수(회귀)
for model in models:
print(model.__class__.__name__,"###")
model.fit(x_train_,y_train_)
pred_val = model.predict(x_val)
print(f"R2 결정 계수:{r2_score(y_val,pred_val):.4f}")
[out]
LinearRegression ###
R2 결정 계수:0.4175
SVR ###
R2 결정 계수:0.0140
KNeighborsRegressor ###
R2 결정 계수:0.1834
DecisionTreeRegressor ###
R2 결정 계수:-0.0252
RandomForestRegressor ###
R2 결정 계수:0.3242
R2 결정 계수는 1에 가까우면 아주 좋은 결과입니다. 0에 가까우면 쓰기 어려운 수준으로 볼 수 있고 음수가 나오면 욕이 나올 수준입니다.
위 결과를 보면 검증 데이터로 평가했을 때 결정 트리, 랜덤 포레스트, K 최근접 이웃, 선형 회귀, 서프트 벡터 머신 순이라고 할 수 있네요.
검증 데이터로 평가한 결과를 보면 선형 회귀 모델로 선정하는 것이 바람직할 것입니다.
한 번 테스트 데이터로 평가를 다시 해 봅시다.
model = models[0]
print(model.__class__.__name__,"###")
pred_test = model.predict(x_test)
print(f"R2 결정 계수:{r2_score(y_test,pred_test):.4f}")
[out]
LinearRegression ###
R2 결정 계수:0.4687
테스트 결과도 검증 결과와 비슷하네요.
아직 충분히 만족할 만한 모델은 아닌 것 같습니다.
나머지 모델들도 테스트 데이터로 평가해 봅시다.
for model in models:
print(model.__class__.__name__,"###")
model.fit(x_train_,y_train_)
pred_val = model.predict(x_val)
print(f"R2 결정 계수:{r2_score(y_val,pred_val):.4f}")
pred_test = model.predict(x_test)
print(f"R2 결정 계수:{r2_score(y_test,pred_test):.4f}")
[out]
LinearRegression ###
R2 결정 계수:0.4175
R2 결정 계수:0.5307
SVR ###
R2 결정 계수:0.0140
R2 결정 계수:0.1144
KNeighborsRegressor ###
R2 결정 계수:0.1834
R2 결정 계수:0.5587
DecisionTreeRegressor ###
R2 결정 계수:-0.1214
R2 결정 계수:0.0854
RandomForestRegressor ###
R2 결정 계수:0.3490
R2 결정 계수:0.5546
테스트 데이터로 평가하면 K 최근접 이웃, 랜덤 포레스트, 선형 회귀 , 서포트 벡터 머신, 결정 트리 순이네요.
현재 이 상태로는 어떤 모델을 선정해야 할 지 판단하기 어렵습니다.
독립 변수의 특성을 새롭게 발굴하거나 모델의 하이퍼 파라미터 인자를 변경하면서 더 나은 학습 결과를 도출해야 결정할 수 있겠네요.
이러한 방법들은 모두 별도의 항목에서 다루기로 할게요.
여기에서는 교차 검증을 한 번 더 해보는 것으로 실험을 마감합시다.
사이킷 런에서는 cross_val_score 함수를 제공하고 있습니다.
sklearn.model_selection.cross_val_score(estimator, X, y=None, *, groups=None, scoring=None, cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch=’2*n_jobs’, error_score=nan)
cross_val_score 메뉴얼 사이트
전달할 인자는 머신 러닝 모델, 독립 변수, 종속 변수 순입니다.
from sklearn.model_selection import cross_val_score #교차 검증 점수
전체 데이터를 학습 데이터와 평가 데이터로 분리한 후에 모델 순으로 교차 검증하고 테스트 데이터로 다시 한 번 평가합시다.
x_train, x_test, y_train, y_test = train_test_split(data,target)
models = []
models.append(LinearRegression())
models.append(SVR())
models.append(KNeighborsRegressor())
models.append(DecisionTreeRegressor())
models.append(RandomForestRegressor())
for model in models:
print(model.__class__.__name__,"###")
scores = cross_val_score(model,x_train,y_train)
print(f"교차 검증 점수(평균):{scores.mean():.4f}")
model.fit(x_train,y_train)
pred_test = model.predict(x_test)
print(f"R2 결정 계수:{r2_score(y_test,pred_test):.4f}")
[out]
LinearRegression ###
교차 검증 점수(평균):0.4503
R2 결정 계수:0.5354
SVR ###
교차 검증 점수(평균):0.1044
R2 결정 계수:0.1632
KNeighborsRegressor ###
교차 검증 점수(평균):0.3553
R2 결정 계수:0.3765
DecisionTreeRegressor ###
교차 검증 점수(평균):-0.3206
R2 결정 계수:0.1554
RandomForestRegressor ###
교차 검증 점수(평균):0.3709
R2 결정 계수:0.4686
교차 검증의 점수와 테스트 검증 모두 선형 회귀 모델이 제일 나은 것으로 나오고 있습니다.
하지만 아직 모델마다 적합한 하이퍼 파라미터를 구하는 작업이나 독립 변수의 특성을 변환하는 등의 작업이 더 필요한 것으로 보입니다.
이러한 것들은 다른 항목에서 다루기로 할게요.