[범주형 데이터분석] 1. 회귀
by Rev_해당 과목은 3학년 2학기 전공과목이며, '머신러닝'에 대하여 공부하는 과목이다.
교재는 '파이썬 머신러닝 완벽 가이드'를 참고하였으며, 5장 회귀부터 시작한다.
- 회귀란?
: 회귀 분석은 데이터 값이 평균과 같은 일정한 값으로 돌아가려는 경향을 이용한 통계학 기법이다. 회귀는 여러 개의 독립변수와 한 개의 종속변수 간의 상관관계를 모델링하는 기법을 통칭한다.
* 독립변수 : 함수에서 다른 변수의 변화와 관계없이 독립적으로 변하고, 다른 변수의 값을 결정하는 변수
* 종속변수 : 독립변수의 조작결과에 관련하여 이에 따라 변하는 변수
y=2x+5를 예로 들면, x값에 따라 y값이 정해지기 때문에 x가 독립변수, y가 종속변수가 된다.
이 독립변수의 값에 영향을 주는 것을 회귀 계수라고 하는데, 최적의 회귀 계수를 찾아내는 것이 목표이다.
- 편향-분산 Trade off
먼저 편향-분산 트레이드오프에 대해 알아야한다. 이는 머신러닝이 극복해야 할 가장 중요한 이슈 중 하나이다.
저편향/저분산 양궁 그래프는 예측 결과가 실제 결과와 아주 유사한 뛰어난 성능을 보여준다. 이는 아주 드문 경우이며, 일반적으로 편향과 분산은 한 쪽이 높으면 한 쪽이 낮아지는 경향이 있다.
편향-분산 tradeoff는 모형의 복잡성과 관계있다. 모형의 복잡도가 높아지면 분산이 커지고 편향이 작아지며, 복잡도가 낮이지면 분산이 줄어드는 대신 편향이 커진다.
- 규제(regularization)
회귀 모형을 만들 때는 실제 데이터 값과 모형 값 사이의 오차를 최소로 만든다. 하지만 오차를 줄이는 데에만 신경쓸 경우 자주 문제가 되는 것이 과대적합이다. 이와 같은 문제를 피하기 위해 이용하는 것이 회귀계수의 크기를 제어하는 규제이다.
일반선형회귀, 릿지(ridge), 라쏘(lasso), 엘라스틱넷(elasticnet)등이 규제 여부, 규제 종류에 따른 회귀 모델의 종류들이다.
단순선형회귀
단순 선형 회귀는 독립변수도 하나, 종속변수도 하나인 선형 회귀이다.
예를 들어, 주택 가격이 주택의 크기로만 결정된다고 할 때 주택의 크기가 클수록 가격이 높아지는 것이 일반적이기 때문에 주택 가격은 주택 크기에 대해 선형관계로 표현할 수 있다.
- 잔차
: 회귀 모델을 1차 함수로 모델링했을때, 실제 값은 1차 함수 값에서 오류 값을 더하거나 뺀 값이 된다. 여기서 이 오류값을 남은 오류, 즉 잔차라고 부른다.
최적의 회귀모델을 만든다는 것은 바로 전체 데이터의 잔차 합이 최소가 되는 모델을 만든다는 의미이다.
- RSS(잔차제곱합)
위에서 설명했던 잔차는 양수일수도, 음수일수도 있기 때문에 잔차의 합은 절대값 또는 제곱한 값으로 더해서 구해야한다. 그 중 오류 값의 제곱을 구해서 더하는 방식을 RSS이라고 한다.
회귀에서 이 RSS는 비용(cost)이며, 회귀 계수로 구성되는 RSS를 비용 함수라고 한다.
- 데이터 준비
X = 2 * np.random.rand(100)
y = 4 + 3*X + np.random.randn(100)
랜덤 함수를 통해 100개의 데이터를 만들었다.
print(X.shape, X.ndim)
실행 결과 : (100, ) 1
shape와 ndim을 확인해보면, 100개의 데이터를 가진 1차원 배열이라는 것을 알 수 있다.
plt.plot(X, y, "b.")
plt.xlabel("x", fonsize=18)
plt.ylabel("y", rotation=0, fontsize=18)
plt.axis([0, 2, 0, 15])
plt.show()
해당 X, y 배열에 그래프를 그려보았다.
첫번째 줄에서 "b." 옵션은 그래프 선 옵션인데 파란색 원으로 표시하라는 의미이다. 그 외에도 여러가지 종류의 옵션이 있다.
각각 x, y축의 라벨을 "x"와 "y"로 설정하고, axis()를 통해 각각 x와 y축의 범위를 지정한다. x는 0부터 2까지, y는 0부터 15까지의 값을 표현하는 그래프를 그린다.
그래프 결과는 위와 같다.
- 단순선형회귀 모델 회귀계수 추정
X_b = np.c_[np.ones((100)), X]
np.c\_()
는 배열 두개를 열 방향으로 차례로 결합한다.
X_b 변수는 100개의 데이터를 가진 2차원 배열이다. (100 X 2)
w_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
w_best
실행 결과 : array([3.79212432, 3.16405769])
정규방정식의 해를 구하는 식은 위의 코드로 나타낼 수 있다.
그리하여 각각 절편, 기울기의 추정값을 구했다.
이 값으로 X값이 0과 2일 때의 예측 값을 계산해보자.
X_new = np.array([0, 2])
X_new_b = np.c_[np.ones((2)), X_new]
y_predict = X_new_b.dot(w_best)
y_predict
실행 결과 : array([3.79212432, 10.12023969])
plt.plot(X_new, y_predict, "r-", label="regression line")
plt.plot(X, y, "b.")
plt.axis([0, 2, 0, 15])
plt.legend() # 범례 표시
plt.show
실행 결과:
100개 데이터와 최소제곱법으로 구한 회귀 직선을 그림으로 나타내었다.
사이킷런을 이용한 회귀
사이킷런의 linear_models 모듈은 매우 다양한 종류의 선형 기반 회귀를 클래스로 구현해 제공한다.
절차는 분류 알고리즘들과 마찬가지로 객체를 만들고 fit()
과 predict()
로 모델과 예측값을 구한다.
np.random.seed(52)
X = 2 * np.random.rand(100)
y = 4 + 3*X + np.random.randn(100)
100개의 데이터를 랜덤하게 만들었다. 차원은 1차원이다.
from sklearn.linear_model import LinearRegression
X = X.reshape(-1, 1)
y = y.reshape(-1, 1)
lin_reg = LinearRegression()
lin_reg.fit(X, y)
X.reshape(-1, 1)
은 배열의 모양을 바꾸는 것인데, 행은 데이터에 맞추고 열은 1로 설정했다.
lin_reg.intercept_, lin_reg.coef_
실행 결과 : (array([3.79212432]), array([[3.16405769]]))
데이터로 추정한 절편항 회귀계수값, 기울기값
위에서 구한 w_best 값과 동일하다.
X_new = np.array([0, 2]).reshape(-1,1)
lin_reg.predict(X_new)
실행 결과 : array([[ 3.79212432],
[10.12023969]])
새로운 데이터 X_new에서 Y값을 예측하면 위와 같다.
이도 위의 y_predict과 동일한 값임을 알 수 있다.
로지스틱 회귀
로지스틱 회귀는 선형 회귀 방식을 분류에 적용한 알고리즘이다. 데이터를 두 개의 그룹으로 분류하는 문제에서 가장 기본적인 방법이다.
로지스틱 회귀가 선형 회귀와 다른 점은 학습을 통해 선형 함수의 회귀 최적선을 찾는 것이 아니라 시그모이드 함수 최적선을 찾고 이 시그모이드 함수의 반환 값을 확률로 간주해 확률에 따라 분류를 결정한다.
- 데이터 불러오기
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
cancer = load_breast_cancer()
로지스틱 회귀를 위하여 사이킷런의 load_breast_cancer()를 호출해 전체 데이터 세트를 생성한다.
cancer 데이터는 가슴에 생긴 혹 영상 자료에서 얻은 세포핵의 10가지 특성과 그 혹이 유방암인지 아닌지 여부를 나타내는 데이터다.
cancer.keys()
실행 결과 : dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
cancer 데이터에서 Key들의 값을 보여준다.
import numpy as np
np.bincount(cancer.target)
실행 결과 : array([212, 357], dtype=int64)
이 데이터의 target 변수는 두 값을 갖는데, 전체 569개 데이터 중에서 212개는 악성종양, 357개는 악성이 아닌 종양이다.
- 데이터 전처리, 데이터 분할
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
data_scaled = scaler.fit_transform(cancer.data)
cancer 데이터의 30개 변수를 평균 0, 분산 1이 되도록 scale을 조정했다.
조정하는 이유는 크기 차이가 많이 나기 때문
data_scaled.mean(axis = 0)
data_scaled.std(axis = 0)
위의 코드로 평균과 표준편차를 알 수 있다.
axis = 0
는 열별로 계산하게 해준다.
from sklearn.model_selection import train_test_split
X_train , X_test, y_train , y_test = train_test_split(data_scaled, cancer.target,
test_size=0.3, random_state=0)
feature와 target 데이터를 7:3 비율로 학습 데이터 세트와 테스트 데이터 세트로 분리하였다.
Train data는 모델의 훈련을 위한 훈련용 데이터이고,
Test data는 모델을 평가하기 위해 정답을 이미 알고 있는 테스트용 데이터이다.
이 과정은 지도학습을 위한 데이터 샘플링 과정 중 하나이다.
- 로지스틱 회귀
lr_clf = LogisticRegression()
lr_clf.fit(X_train, y_train)
lr_preds = lr_clf.predict(X_test)
로지스틱 회귀를 시행하였다.
predict() 함수는 해당 속성들이 해당 레이블에 속하는지 아닌지를 0또는 1로 구성된 벡터값을 반환해준다.
- 회귀계수 추정 결과
pred_pr = lr_clf.predict_proba(X_test)
pred_pr[:3]
실행 결과 : array([[0.99864569, 0.00135431],
[0.03842822, 0.96157178],
[0.00130563, 0.99869437]])
predict_proba()는 위에서 predict() 함수로 분류된 속성들이 해당 레이블로 분류될 확률 값을 보여준다.
target 변수를 0, 1로 분류할 확률을 위와 같이 구할 수 있다. 이는 두 확률을 비교해서 확률이 큰 범주로 분류한다.
결과값 : 0이 될 확률, 1이 될 확률 이며, 각 줄 당 큰 값을 따라 0인지 1인지 결정한다.
- 최적 hyper parameter 선택
from sklearn.model_selection import GridSearchCV
params={'penalty':['l2', 'l1'],
'C':[0.01, 0.1, 1, 1, 5, 10]}
grid_clf = GridSearchCV(lr_clf, param_grid=params, scoring='accuracy', cv=3 )
grid_clf.fit(data_scaled, cancer.target)
print('최적 하이퍼 파라미터:{0}, 최적 평균 정확도:{1:.3f}'.format(grid_clf.best_params_,
grid_clf.best_score_))
실행 결과 : 최적 하이퍼 파라미터:{'C': 1, 'penalty': 'l2'}, 최적 평균 정확도:0.975
회귀 트리
기존에는 회귀 함수를 통해 결과값을 예측하였지만, 여기서는 회귀 함수를 기반으로 하지 않고 트리를 기반으로 하는 회귀 방식을 다룬다.
회귀 트리는 leaf node에 속한 데이터 값의 평균값을 구해 회귀 예측값을 계산한다.
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
import pandas as pd
import numpy as np
boston = load_boston()
bostonDF = pd.DataFrame(boston.data, columns = boston.feature_names)
bostonDF['PRICE'] = boston.target
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'], axis=1,inplace=False)
X_train , X_test, y_train , y_test = train_test_split(X_data, y_target,
test_size=0.3, random_state=0)
교재에서는 보스턴 주택가격 데이터를 사용하였다.
tree_reg = DecisionTreeRegressor(max_depth=2, random_state=0)
tree_reg.fit(X_train, y_train)
pred = tree_reg.predict(X_test)
tree_reg.score(X_test, y_test)
실행 결과 : 0.622596538377147
결정계수 값을 구하였다.
사이킷런에서 제공하는 DecisionTree 라이브러리를 사용하여 모델학습을 한다. 여기서 max_depth는 트리의 최대 깊이를 설정하는 것이다.
* 결정계수 : 내가 만든 모델이 타겟 변수를 얼마나 잘 예측하는지 평가지표의 하나로 사용된다.
import graphviz
from sklearn.tree import export_graphviz
export_graphviz(tree_reg, out_file ="tree.dot", feature_names=boston.feature_names, filled=True)
with open("tree.dot") as f:
dot_graph = f.read()
graphviz.Source(dot_graph)
실행 결과 :
위에서 만든 회귀 트리를 Graphviz를 이용하여 그려보았다.
from sklearn.ensemble import RandomForestRegressor
rf_reg = RandomForestRegressor(random_state=0, n_estimators=1000)
rf_reg.fit(X_train, y_train)
pred = rf_reg.predict(X_test)
rf_reg.score(X_test, y_test)
실행 결과 : 0.8286153119401956
이번에는 랜덤 포레스트 회귀모형으로 분석해보았다.
import seaborn as sns
%matplotlib inline
rf_reg.fit(X_train, y_train)
feature_series = pd.Series(data=rf_reg.feature_importances_, index=X_data.columns )
feature_series = feature_series.sort_values(ascending=False)
sns.barplot(x= feature_series, y=feature_series.index)
실행 결과 :
rf_reg.feature_importances_를 이용해서 feature 변수들의 중요도를 알아보았다.
RM과 LSTAT의 중요도가 압도적으로 높다.
'복수전공' 카테고리의 다른 글
[데이터 시각화] 2. 분포 시각화 (0) | 2021.10.23 |
---|---|
[데이터 시각화] 1. 데이터 입출력 (0) | 2021.10.23 |
[현대사회의 데이터와 통계학] 3. Numpy : 배열의 인덱싱과 슬라이싱 (0) | 2021.10.20 |
[현대사회의 데이터와 통계학] 2. NumPy : 배열의 연산 (0) | 2021.10.20 |
[표본조사론] 2. 단순임의추출법 (0) | 2021.10.20 |
블로그의 정보
Hi Rev
Rev_