보스톤 주택 가격 예측
- Data Load
# 데이터 가져오기 y_target=bostonDF['PRICE'] X_data=bostonDF.drop(['PRICE'],axis=1,inplace=False) print(y_target.head()) print(X_data.head())
- Data split
# 훈련 데이터와 테스트 데이터 분리 (7:3) from sklearn.model_selection import train_test_split X_train,X_test,y_train,y_test=train_test_split(X_data,y_target, test_size=0.3, random_state=42) # shape를 print해서 구조가 맞는지 확인한다. print(X_train.shape) print(X_test.shape) print(y_train.shape) print(y_test.shape)
- Model Train
# 회귀 모델을 생성하고 훈련하기 from sklearn.linear_model import LinearRegression lr=LinearRegression() lr.fit(X_train,y_train)
- Model Evaluate
# 평가 y_pred=lr.predict(X_test) from sklearn.metrics import mean_squared_error, r2_score mse=mean_squared_error(y_test,y_pred) # mse는 제곱을 하기에 실제 데이터보다 스케일이 큰 경우가 있다. # 제곱근해서 많이 사용합니다. rmse=np.sqrt(mse) r2score=r2_score(y_test,y_pred) print('mse : ', mse) print('rmse : ',rmse) print('r2_score : ',r2score)
# 회귀 계수와 절편 값을 확인하자 print('절편 : ', lr.intercept_) print('기울기 : ',lr.coef_)
- 간단하게 이 값을 보고도 중요도를 대충 짐작 할 수 있다.
# data load df=pd.read_csv('./data/score.csv', encoding='cp949') df.head()
import statsmodels.formula.api as sm result=sm.ols(formula='score ~ iq + academy + game + tv', data=df).fit() print('절편과 기울기 : ', result.params) print("p-value(유의확률) : ", result.pvalues) print("결정 계수 ", result.rsquared) # 1에 가까우면 좋다.
- 결정 계수가 높아서 아주 신뢰할 만한 결과인 것 같지만, pvalue 값도 높다. 0.05 ~ 0.1
# 예측 # iq 130 학원 3개 게임 2시간 tv 1시간 보는 학생의 예상점수 y=result.params.Intercept+130*result.params.iq+ 3*result.params.academy+2*result.params.game+1*result.params.tv print('예상 점수 : ', y)
- 예상 점수 : 83.28448678034155
# 예측 값과 실제 값의 시각화 plt.figure() plt.plot(df['score'],label='실제 성적') plt.plot(result.predict(),label='예측성적') plt.xticks(range(0,10,1),df['name']) plt.legend() plt.show()
- 결정 계수가 높기 때문에, 오차가 별로 없음
# VIF(분산 팽창 요인) 출력하기 # 관련 없는 feature drop하기 X=df.drop(['score','name'], axis=1) from statsmodels.stats.outliers_influence import variance_inflation_factor vif=pd.DataFrame() vif["VIF Factor"]=[variance_inflation_factor(X.values,i) for i in range(X.shape[1])] vif["features"]=X.columns print(vif)
- academy를 빼보자. 너무 값이 크다.
X=df.drop(['score','name', 'iq'], axis=1)
- 좀 괜찮아졌다.
- 그럼 academy를 빼고 식을 세워서 다시 봐보자.
import statsmodels.formula.api as sm result=sm.ols(formula='score ~ iq + game + tv', data=df).fit() print('절편과 기울기 : ', result.params) print("p-value(유의확률) : ", result.pvalues) print("결정 계수 ", result.rsquared) # 1에 가까우면 좋다.
- 많이 좋아졌다.
boston에 Ridge 적용
from sklearn.linear_model import Ridge y_target=bostonDF['PRICE'] X_data=bostonDF.drop(['PRICE'],axis=1,inplace=False)
from sklearn.model_selection import cross_val_score # 적용할 규제 값 alphas=[0,0.1,1,10,100] for alpha in alphas: ridge=Ridge(alpha=alpha) neg_mse_scores=cross_val_score(ridge,X_data,y_target, scoring='neg_mean_squared_error',cv=5) avg_rmse=np.mean(np.sqrt(-1*neg_mse_scores)) print('alpha {0} 일 때 folds의 평균 RMSE : {1}'.format(alpha,avg_rmse))
- 점점 규제를 가하고 있다.
- KNN
from sklearn.neighbors import KNeighborsRegressor # 거리를 가지고 가중 평균을 구해서 예측 # uniform을 설정하면 일반 평균 regressor=KNeighborsRegressor(n_neighbors=3,weights='distance') X_train=[ [0.5,0.2,0.1], [0.9,0.7,0.3], [0.4,0.4,0.7], [0.2,0.3,0.5] ] y_train=[5.0,6.8,9.0,4.3] regressor.fit(X_train,y_train)
X_test=[ [0.8,0.1,0.2], [0.4,0.7,0.6], ] pred=regressor.predict(X_test) print(pred)
# 샘플 데이터 생성 np.random.seed(42) m=200 X=np.random.rand(m,1) y=y*(X-0.5)**2 y=y+np.random.randn(m,1)/10
from sklearn.tree import DecisionTreeRegressor tree_reg=DecisionTreeRegressor(max_depth=2, random_state=42) tree_reg.fit(X,y) from graphviz import Source from sklearn .tree import export_graphviz export_graphviz( tree_reg, out_file='decision_tree.dot', feature_names=['X'], class_names=['y'], rounded=True, filled=True ) #화면출력 with open('decision_tree.dot')as f: dot_graph=f.read() src=Source(dot_graph) src
from sklearn.tree import DecisionTreeRegressor # 터미널(자식이 없는 노드 - LEAF NODE)의 개수가 10이상이어야 한다는 제약도 가능함 # min_samples_leaf 설정하면 각 터미널의 dpeth가 일정하지 않을 수 있다. tree_reg=DecisionTreeRegressor(min_samples_leaf=10, random_state=42) tree_reg.fit(X,y)
- depth가 다르다.
np.random.seed(42) m=50 X=2*np.random.rand(m,1) #ravel은 차원을 하나 줄이는 역할을 수행해주는 함수 # X 떄문에 2차원 배열로 만들어지는 타겟은 # 1차원이어야 하기 때문에 차원을 수정 # flatten이나 reshape도 가능합니다. # flatten() # reshape는 데이터의 개수를 알아야 한다. y=(4+3*X+np.random.randn(m,1)).ravel() print(y)
X_train=X[:40] X_test=X[40:] y_train=y[:40] y_test=y[40:] from sklearn.svm import LinearSVR svm_reg=LinearSVR(epsilon=1.5,random_state=42) svm_reg.fit(X_train,y_train)
y_pred=svm_reg.predict(X_test) mse=mean_squared_error(y_test,y_pred) rmse=np.sqrt(mse) print(y_test) print(y_pred) print(rmse)
- MSE로 하면 너무 큰 값이 나올 수 있기에 root 해주기
- epsilon(margin) 줄이면 rmse 줄어들 것이다.
- 비선형 데이터도 할 수 있다.
## 비선형 데이터 생성 np.random.seed(42) m = 100 X = 2* np.random.rand(m,1) -1 y = (0.2 + 0.1 * X + 0.5 * X**2 + np.random.randn(m,1) / 10).ravel() X_train = X[:80] X_test = X[80:] y_train = y[:80] y_test = y[80:]
- 이걸 기존 있던거 그대로 해주면
- 이런 문제가 생긴다.
from sklearn.svm import SVR # 샘플 데이터를 2차 방정식으로 했기 때문에 지금은 degree가 2인 경우가 잘 맞습니다. svm_poly_reg = SVR(kernel='poly', gamma='auto', degree=2, C=10, epsilon=0.1) svm_poly_reg.fit(X_train,y_train) # 예측 및 결과 비교 y_pred = svm_poly_reg.predict(X_test) print(y_test) print(y_pred) mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) print(rmse) plt.plot(y_test, "b-", linewidth=3, label="test set") plt.plot(y_pred, "r--", linewidth=2, label="predict set") plt.legend(loc="upper right", fontsize=14) plt.show()
- 다항식도 괜찮다 이러면.
# 데이터 생성 from sklearn.model_selection import train_test_split from sklearn.datasets import make_moons X, y = make_moons(n_samples=500, noise=0.30, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42) #모델 생성 및 훈련 from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import VotingClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC log_clf = LogisticRegression(solver="lbfgs", random_state=42) rnd_clf = RandomForestClassifier(n_estimators=100, random_state=42) svm_clf = SVC(gamma="scale", random_state=42) voting_clf = VotingClassifier( estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)], voting='hard') voting_clf.fit(X_train, y_train)
# 각 모델의 정확도 확인해보기 from sklearn.metrics import accuracy_score for clf in (log_clf, svm_clf, rnd_clf, voting_clf): clf.fit(X_train,y_train) y_pred=clf.predict(X_test) print(clf.__class__.__name__,"정확도 : ",accuracy_score(y_test,y_pred))
- 개별 분류기로 가장 높게 나온 RandomForest 분류기보다 투표 기반의 VotingClassifier가 더 정확도가 높다.
# 간접 투표 방식 log_clf = LogisticRegression(solver="lbfgs", random_state=42) rnd_clf = RandomForestClassifier(n_estimators=100, random_state=42) svm_clf = SVC(gamma="scale",probability=True, random_state=42) voting_clf = VotingClassifier( estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)], voting='soft') from sklearn.metrics import accuracy_score for clf in (log_clf, svm_clf, rnd_clf, voting_clf): clf.fit(X_train,y_train) y_pred=clf.predict(X_test) print(clf.__class__.__name__,"정확도 : ",accuracy_score(y_test,y_pred))
bootstrap=False
설정하면 Pasting으로 된다.Bagging을 이용한 앙상블
from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier bag_clf=BaggingClassifier( DecisionTreeClassifier(), n_estimators=500, max_samples=100, bootstrap=True, random_state=42 ) bag_clf.fit(X_train,y_train) y_pred=bag_clf.predict(X_test) print("정확도 : ", accuracy_score(y_test,y_pred))
tree_clf = DecisionTreeClassifier(random_state=42) tree_clf.fit(X_train, y_train) y_pred_tree = tree_clf.predict(X_test) print(accuracy_score(y_test, y_pred_tree))
- 부스트트래핑은 각 예측기가 학습하는 서브 세트에 다양성을 증가시키기 때문에, bagging이 pasting보다 편향이 조금 더 높지만, 다양성을 추가한다는 것은 예측기들의 상관 관계를 줄이기 떄문에 앙상블의 분산을 감소시킴
- 일반적으로는 배깅이 페이스팅보다 더 나은 모델을 만들기 떄문에 더 선호
oob_score=Ture
라는 매개변수를 추가하면 oob 평가를 수행하고, 결과를 oob_score_
로 저장#oob 평가 bag_clf = BaggingClassifier( DecisionTreeClassifier(), n_estimators=500, max_samples=100, bootstrap=True, random_state=42, oob_score=True ) bag_clf.fit(X_train, y_train) print(bag_clf.oob_score_)
샘플링은 max_features, bootstrap_features 두 매개변수로 조절
각 예측기는 무작위로 선택한 입력 특성의 일부분으로 훈련
훈련하는 특성 과 데이터를 모두 샘플링하는 방식을 random patches method 라고 합니다.
훈련 데이터는 모두 사용하고(bootstrap=False 이고 max_samples=1.0) 특성만 샘플링(bootstrap_features=True 그리고 max_features는 1.0 보다 작게)하는 것을 random subspaces method 라고 합니다.
특성 샘플링을 하게 되면 더 다양한 예측기를 만들기 때문에 편향을 늘리는 대신 분산을 낮춤
Bagging과 Random Forest
- 배깅
bag_clf = BaggingClassifier( DecisionTreeClassifier(max_features="sqrt", max_leaf_nodes=16), n_estimators=500, random_state=42) bag_clf.fit(X_train, y_train) y_pred = bag_clf.predict(X_test
- 랜덤 포레스트
from sklearn.ensemble import RandomForestClassifier rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, random_state=42) rnd_clf.fit(X_train, y_train) y_pred_rf = rnd_clf.predict(X_test) print(np.sum(y_pred == y_pred_rf) / len(y_pred))
- 결과는 1.0 : bag_clf 와 rnd_clf 가 예측한 결과가 정확히 일치
feature_importances_
변수에 저장타이타닉 데이터에 RandomForest 적용
- 데이터 가져오기
df = sns.load_dataset('titanic') df
- 결측치 처리
rdf = df.drop(['deck', 'embark_town'], axis=1) rdf = rdf.dropna(subset=['age'], how='any', axis=0) most_freq=rdf['embarked'].value_counts(dropna=True).idxmax() rdf['embarked'].fillna(most_freq, inplace=True) rdf.info()
- 원핫 인코딩
#분석에 사용할 데이터 골라내기 ndf = rdf[['survived', 'pclass', 'sex', 'age', 'sibsp', 'parch', 'embarked']] #순서가 없는 범주형 데이터의 원 핫 인코딩 onehot_sex = pd.get_dummies(ndf['sex']) ndf = pd.concat([ndf, onehot_sex], axis=1) onehot_embarked = pd.get_dummies(ndf['embarked'], prefix='town') ndf = pd.concat([ndf, onehot_embarked], axis=1) ndf.drop(['sex', 'embarked'],axis=1, inplace=True) print(ndf.head())
- 정규화 - RandomForest 만 사용할 거라면 하지 않아도 결과에 별 영향이 없음
#피처 와 타겟을 분리 X = ndf[['pclass', 'age', 'sibsp', 'parch', 'female', 'male', 'town_C', 'town_Q', 'town_S']] y = ndf['survived'] #정규화 from sklearn import preprocessing X = preprocessing.StandardScaler().fit(X).transform(X) print(X[0:5])
- 훈련 데이터 와 테스트 데이터 분할
#훈련 데이터 와 테스트 데이터 분할 #데이터가 랜덤하게 배치되어 있다면 분할을 할 때 순서대로 앞에서 일정 부분은 #훈련 데이터로 사용하고 일정 부분은 테스트 데이터로 할당하면 됨 #타겟의 비율을 고려 #타겟의 비율이 고르지 않다면 여러가지 고려 #층화 추출이나 oversampling 이나 undersampling #이상치 탐지에서 이 부분이 항상 고려 대상 #훈련 데이터의 비율 - 일반적으로 0.7 이나 0.8을 많이 사용 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42)
- 모델을 만들어서 훈련
#불순도 지표는 entropy - 기본은 gini 계수 #트리의 개수는 25개 #코어는 최대한 사용 forest = RandomForestClassifier(criterion='entropy', n_estimators=25, random_state=42, n_jobs=-1) forest.fit(X_train, y_train)
- 평가 지표 확인
y_hat = forest.predict(X_test) print(y_hat[0:10]) print(y_test.values[0:10]) from sklearn import metrics #오차 행렬 확인 tree_matrix = metrics.confusion_matrix(y_test, y_hat) print(tree_matrix) #정확도 계산 print((tree_matrix[0, 0] + tree_matrix[1,1]) / np.sum(tree_matrix)) tree_report = metrics.classification_report(y_test, y_hat) print(tree_report)
- 특성 중요도 확인
n_features = X.data.shape[1] plt.barh(np.arange(n_features), forest.feature_importances_, align='center') plt.yticks(np.arange(n_features), ['pclass', 'age', 'sibsp', 'parch', 'female', 'male', 'town_C', 'town_Q', 'town_S']) plt.xlabel('특성 중요도') plt.ylabel('특성') plt.ylim(-1, n_features) plt.show()
✔ Boosting
개요
- 약한 학습기 여러 개를 연결해서 강한 학습기를 만드는 앙상블 기법
- 앞의 모델을 보완해 가면서 예측기를 학습시키는 것
## AdaBoost from sklearn.ensemble import AdaBoostClassifier #algorithm 은 확률을 계산할 수 있으면 SAMME.R 이고 없으면 SAMME #learning_rate 는 학습률 #학습률이 너무 크면 최적화 되지 않을 가능성이 높아지고 너무 작으면 훈련 속도가 느려지고 #overfitting 될 가능성이 발생 ada_clf = AdaBoostClassifier( DecisionTreeClassifier(max_depth=1), n_estimators=200, algorithm="SAMME.R", learning_rate=0.5, random_state=42 ) ada_clf.fit(X_train, y_train) y_hat = ada_clf.predict(X_test) print(y_hat[0:10]) print(y_test.values[0:10])
#오차 행렬 확인 ada_matrix = metrics.confusion_matrix(y_test, y_hat) print(ada_matrix) #정확도 계산 print((ada_matrix[0, 0] + ada_matrix[1,1]) / np.sum(ada_matrix)) ada_report = metrics.classification_report(y_test, y_hat) print(ada_report)
%%time #주피터 노트북에서 시간 측정할 때 사용 ## Gradient Boosting from sklearn.ensemble import GradientBoostingClassifier gbm_clf = GradientBoostingClassifier(random_state=42) gbm_clf.fit(X_train, y_train) y_hat = gbm_clf.predict(X_test) print(y_hat[0:10]) print(y_test.values[0:10])
%%time
#하이퍼 파라미터 튜닝 - 시간이 있을 때는 여러 값을 설정
from sklearn.model_selection import GridSearchCV
#실제로는 4가지
params = {
'n_estimators':[100, 500],
'learning_rate': [0.05, 0.1]
}
grid_cv = GridSearchCV(gbm_clf, param_grid=params, cv=2, verbose=1)
grid_cv.fit(X_train, y_train)
print("최적의 파라미터:", grid_cv.best_params_)
print("최적의 정확도:", grid_cv.best_score_)
#튜닝의 결과로 예측
gbm_pred = grid_cv.best_estimator_.predict(X_test)
gbm_report = metrics.classification_report(y_test, gbm_pred)
print(gbm_report)
warm_start=True
를 설정하면, 일정 횟쉬 동안 성능이 좋아지지 않으면 조기 종료가 가능함conda install -c anaconda py-xgboost