通俗理解:
集成算法就是以各種形式將多種感知器算法揉搓成一個(gè)打算法析恢,在實(shí)際應(yīng)用中有,揉搓方式一般有:
- Bagging:以隨機(jī)森林為代表。
![]()
- Boosting:Adaboost和Xgboost為代表,
![]()
- stacking:使用不同分類(lèi)器得到的結(jié)果同時(shí)作為第二次訓(xùn)練的輸入
隨機(jī)森林的簡(jiǎn)單介紹
例如:建立三課決策樹(shù),從100個(gè)樣本里有放回的選擇60到80個(gè)樣本店量,分別放入三棵決策樹(shù)中。在決策樹(shù)選擇特征的時(shí)候鞠呈,也是從10里選擇6到8特征融师。然后三棵樹(shù)之間不存在相互影響,并行計(jì)算得到的分?jǐn)?shù)按照上述公式取平均值即可得到最終結(jié)果蚁吝。
特征重要性評(píng)估
例如:一批數(shù)據(jù)有ABCD四個(gè)特征旱爆,若想知道B特征對(duì)整個(gè)評(píng)估標(biāo)準(zhǔn)的重要程度,
- 首先使用這四個(gè)特征進(jìn)行模型訓(xùn)練灭将,得到錯(cuò)誤率error1疼鸟。
- 之后經(jīng)過(guò)某種算法,破壞B特征中屬性值的規(guī)律性庙曙,使B變成B',使用AB’CD進(jìn)行訓(xùn)練得到error2空镜。
- 若error1近似error2,證明B特征沒(méi)什么用捌朴,如果error2>>error1,證明B特征重要吴攒。
- 在確認(rèn)B特征確實(shí)無(wú)用后,在訓(xùn)練模型時(shí)可以去掉B特征砂蔽。
??:在實(shí)際使用中洼怔,并不是樹(shù)越多越好。應(yīng)該具體場(chǎng)景具體分析左驾。
boosting簡(jiǎn)單介紹
假如:
- 有一個(gè)小偷镣隶,他此次真實(shí)偷取了1000塊錢(qián)(真實(shí)的y值)极谊,
- 警察建立了一棵樹(shù),預(yù)測(cè)后他此次能偷取950塊錢(qián)(預(yù)測(cè)目標(biāo)其實(shí)想達(dá)到1000)
- 然后警察計(jì)算出了殘差值R=1000-950=50安岂,然后建立第二棵樹(shù)轻猖,目標(biāo)是結(jié)果要接近殘差值50,結(jié)果得到了30域那。
- 再次計(jì)算與上一次的殘差R=50-30=20,建立第三棵樹(shù)咙边,目標(biāo)是結(jié)果要接近新的殘差值20,結(jié)果得到15次员。
- 目前為止已經(jīng)預(yù)測(cè)到的值為950+30+15=995败许,這個(gè)值看上去已經(jīng)很漂亮了
Adaboost簡(jiǎn)單介紹
假如:
- 有一批數(shù)據(jù),隨機(jī)切分成5份為ABCDE淑蔚,對(duì)應(yīng)5個(gè)分類(lèi)器
- 將每批數(shù)據(jù)分別賦予權(quán)重0.2市殷,在進(jìn)行一次預(yù)測(cè)后,ABDE都預(yù)測(cè)對(duì)了束倍,而C預(yù)測(cè)錯(cuò)了被丧。
- 根據(jù)預(yù)測(cè)結(jié)果,調(diào)整程序绪妹,加大對(duì)錯(cuò)誤數(shù)據(jù)的權(quán)重,減輕預(yù)測(cè)正確的數(shù)據(jù)權(quán)重柿究。如0.1_0.1_0.6_0.1_0.1邮旷。
- 經(jīng)過(guò)新的權(quán)重訓(xùn)練后進(jìn)行預(yù)測(cè),可能會(huì)出現(xiàn)別的數(shù)據(jù)集預(yù)測(cè)錯(cuò)誤的情況蝇摸,那么繼續(xù)調(diào)整相應(yīng)權(quán)重婶肩,以此類(lèi)推。
集成算法工具包推薦:ml-ens
ROC和AUC介紹
簡(jiǎn)單回顧一下混淆矩陣貌夕,橫坐標(biāo)是預(yù)測(cè)值律歼,縱坐標(biāo)是真實(shí)的ylabel。
真\預(yù) | 0 | 1 |
---|---|---|
0 | TN | FP |
1 | FN | TP |
AUC即為圖中陰影面積啡专,如圖可知险毁,面積越大,即AUC值越大们童,證明預(yù)測(cè)效果越好畔况。
??:經(jīng)過(guò)實(shí)踐,我們發(fā)現(xiàn)使用集成算法慧库,在處理數(shù)據(jù)的時(shí)候跷跪,只要你牛逼,可以根據(jù)自己需要調(diào)整到很高的精度和很高的泛化能力齐板,但是計(jì)算量真的不小吵瞻,所以集成算法不適合處理實(shí)時(shí)數(shù)據(jù)葛菇。。
代碼展示
以下橡羞,使用美國(guó)黨派捐贈(zèng)情況表眯停,來(lái)通過(guò)各個(gè)特征預(yù)測(cè)某一次捐贈(zèng)可能屬于哪個(gè)黨派的行為。表結(jié)構(gòu)和部分?jǐn)?shù)據(jù)為:
- 老樣子尉姨,導(dǎo)入數(shù)據(jù)集庵朝,切分?jǐn)?shù)據(jù),同時(shí)將部分?jǐn)?shù)據(jù)離散化又厉,one-hot編碼
SEED = 222
np.random.seed(SEED)
df = pd.read_csv('input.csv')
# 切分?jǐn)?shù)據(jù)集
def get_train_test(test_size=0.95):
y = 1 * (df.cand_pty_affiliation == "REP") # 標(biāo)簽值轉(zhuǎn)變0九府。1值
X = df.drop(["cand_pty_affiliation"], axis=1) #制作X,所以去掉y的那一列
X = pd.get_dummies(X) #屬性值離散化
X.drop(X.columns[X.std() == 0], axis=1, inplace=True) #去掉標(biāo)準(zhǔn)差為0的列(因?yàn)檫@樣的數(shù)據(jù)對(duì)程序沒(méi)卵用)
return train_test_split(X, y, test_size=test_size, random_state=SEED)
print("\nExample data:")
print(df.head())
xtrain, xtest, ytrain, ytest = get_train_test()
- 查看兩個(gè)黨派的具體分布
df.cand_pty_affiliation.value_counts(normalize=True).plot(
kind="bar", title="Share of No. donations")
plt.show()
- 構(gòu)建一棵3層的決策樹(shù)覆致,并計(jì)算出AUC值
#打印出決策樹(shù)的圖片
def print_graph(clf, feature_names):
graph = export_graphviz(
clf,
label="root",
proportion=True,
impurity=False,
out_file=None,
feature_names=feature_names,
class_names={0: "D", 1: "R"},
filled=True,
rounded=True
)
graph = pydotplus.graph_from_dot_data(graph)
img = Image(graph.create_png())
graph.write_png("partycontri.png")
return img
#構(gòu)建深度為3的決策樹(shù)
t2 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
t2.fit(xtrain, ytrain)
p = t2.predict_proba(xtest)[:, 1]
#計(jì)算出AUC
print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.751
#繪制出決策樹(shù)的圖片侄旬,根據(jù)圖中內(nèi)容發(fā)現(xiàn)過(guò)擬合,
print_graph(t2, xtrain.columns)
我們可以發(fā)現(xiàn)煌妈,絕大部分?jǐn)?shù)據(jù)通過(guò)預(yù)測(cè)儡羔,都落入了DEM里,這樣的樹(shù)極有可能出現(xiàn)過(guò)擬合現(xiàn)象璧诵。如果出現(xiàn)這種情況汰蜘,我們可以通過(guò)去掉決策能力最強(qiáng)的Transaction_amt后重新建立第二個(gè)樹(shù)模型,來(lái)看一看接下來(lái)會(huì)發(fā)生怎樣的情況之宿。
#去掉先前最重要特征族操,再看看新決策樹(shù)是否會(huì)有好轉(zhuǎn)
drop = ["transaction_amt"]
xtrain_slim = xtrain.drop(drop, axis=1)
xtest_slim = xtest.drop(drop, axis=1)
t3 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
t3.fit(xtrain_slim, ytrain)
p = t3.predict_proba(xtest_slim)[:, 1]
print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.740
print_graph(t3, xtrain_slim.columns)
- 不好意思打臉了。比被。色难。那么既然是介紹集成算法,不妨我們把兩棵樹(shù)集成起來(lái)等缀,使用bagging思想枷莉,看一下有沒(méi)有好轉(zhuǎn)。
#使用bagging思想尺迂,手動(dòng)求平均分
p1 = t2.predict_proba(xtest)[:, 1]
p2 = t3.predict_proba(xtest_slim)[:, 1]
p = np.mean([p1, p2], axis=0)#計(jì)算平均值
print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.783
我們發(fā)現(xiàn)AUC明顯變高了笤妙。
- 既然是兩棵樹(shù)集成的模型,不如我們直接使用隨機(jī)森林枪狂,因?yàn)閟klearn里有現(xiàn)成的隨機(jī)森林庫(kù)危喉,代碼少,活還好州疾。
'''
max_features:隨機(jī)森林允許單個(gè)決策樹(shù)使用特征的最大數(shù)量辜限。 Python為最大特征數(shù)提供了多個(gè)可選項(xiàng)。 下面是其中的幾個(gè):
Auto/None :簡(jiǎn)單地選取所有特征严蓖,每顆樹(shù)都可以利用他們薄嫡。這種情況下氧急,每顆樹(shù)都沒(méi)有任何的限制。
sqrt :此選項(xiàng)是每顆子樹(shù)可以利用總特征數(shù)的平方根個(gè)毫深。 例如吩坝,如果變量(特征)的總數(shù)是100,所以每顆子樹(shù)只能取其中的10個(gè)哑蔫《で蓿“l(fā)og2”是另一種相似類(lèi)型的選項(xiàng)。
0.2:此選項(xiàng)允許每個(gè)隨機(jī)森林的子樹(shù)可以利用變量(特征)數(shù)的20%闸迷。如果想考察的特征x%的作用嵌纲, 我們可以使用“0.X”的格式
'''
rf = RandomForestClassifier(
n_estimators=10,#搞10棵樹(shù)
max_features=3,
random_state=SEED
)
rf.fit(xtrain, ytrain)
p = rf.predict_proba(xtest)[:, 1]
print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.844
AUC的值明顯比之前又搞出了好多。
- 接下來(lái)開(kāi)始作死腥沽,嘗試用不同分類(lèi)器進(jìn)行集成逮走,得到一個(gè)龐大分類(lèi)器,進(jìn)行預(yù)測(cè)看看效果今阳。一下包含兩個(gè)方法师溅,建立
#構(gòu)建基礎(chǔ)分類(lèi)器(分類(lèi)器大合集)
def get_models():
nb = GaussianNB()
svc = SVC(C=100, probability=True)
knn = KNeighborsClassifier(n_neighbors=3)
lr = LogisticRegression(C=100, random_state=SEED)
nn = MLPClassifier((80, 10), early_stopping=False, random_state=SEED)
gb = GradientBoostingClassifier(n_estimators=100, random_state=SEED)
rf = RandomForestClassifier(n_estimators=10, max_features=3, random_state=SEED)
models = {'svm': svc,
'knn': knn,
'naive bayes': nb,
'mlp-nn': nn,
'random forest': rf,
'gbm': gb,
'logistic': lr,
}
return models
#訓(xùn)練模型
def train_predict(model_list):
P = np.zeros((ytest.shape[0], len(model_list))) # 初始化好結(jié)果集框架
P = pd.DataFrame(P)
print("Fitting models.")
cols = list()
for i, (name, m) in enumerate(model_list.items()):
print("%s..." % name, end=" ", flush=False)
m.fit(xtrain, ytrain)
P.iloc[:, i] = m.predict_proba(xtest)[:, 1]
cols.append(name)
print("done")
P.columns = cols #設(shè)置表頭
print("Done.\n")
return P
#評(píng)估
def score_models(P, y):
print("Scoring models.")
for m in P.columns:
score = roc_auc_score(y, P.loc[:, m]) #P.loc[:, m]含義:取列名為m的列的所有行(即取出名為m的列)
print("%-26s: %.3f" % (m, score))
print("Done.\n")
#開(kāi)始作死
models = get_models()
P = train_predict(models)
score_models(P, ytest)
通過(guò)預(yù)測(cè),我們得到了一下結(jié)果:
Scoring models.
svm : 0.845
knn : 0.779
naive bayes : 0.803
mlp-nn : 0.873
random forest : 0.844
gbm : 0.878
logistic : 0.853
直接取個(gè)平均值盾舌。這里仍然使用的是bagging思想
print("Ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.mean(axis=1)))#bagging一下墓臭,0.884
AUC提升至0.884。
- 另外妖谴,我們可以通過(guò)mlens庫(kù)起便,通過(guò)各算法產(chǎn)生的結(jié)果,反推出各個(gè)算法之間的相關(guān)性:
#使用mlens將集成算法的關(guān)系和計(jì)算結(jié)果可視化
corrmat(P.corr(), inflate=False)
plt.show()
- 同學(xué)們可以看到窖维,之前一直使用AUC進(jìn)行模型評(píng)估,那么以上各個(gè)算法的ROC曲線到底長(zhǎng)啥樣妙痹?集成算法的ROC又長(zhǎng)啥樣铸史?
#繪制roc曲線,y值,預(yù)測(cè)值怯伊,集成值琳轿,標(biāo)簽名列表,集成標(biāo)簽名
def plot_roc_curve(ytest, P_base_learners, P_ensemble, labels, ens_label):
plt.figure(figsize=(10, 8))
plt.plot([0, 1], [0, 1], 'k--') #'‐‐' 破折線
cm = [plt.cm.rainbow(i)
for i in np.linspace(0, 1.0, P_base_learners.shape[1] + 1)] #7個(gè)單獨(dú)算法+1個(gè)集成算法
for i in range(P_base_learners.shape[1]):
p = P_base_learners[:, i]
fpr, tpr, _ = roc_curve(ytest, p)
plt.plot(fpr, tpr, label=labels[i], c=cm[i + 1])
fpr, tpr, _ = roc_curve(ytest, P_ensemble)
plt.plot(fpr, tpr, label=ens_label, c=cm[0])
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve')
plt.legend(frameon=False)
plt.show()
plot_roc_curve(ytest, P.values, P.mean(axis=1), list(P.columns), "ensemble")
- 我們也可以展示出不同算法計(jì)算出的REP(真值)占比
#各個(gè)算法預(yù)測(cè)的共和黨占比
p = P.apply(lambda x: 1*(x >= 0.5).value_counts(normalize=True))
p.index = ["DEM", "REP"]
p.loc["REP", :].sort_values().plot(kind="bar")
plt.axhline(0.25, color="k", linewidth=0.5)
plt.text(0., 0.23, "True share republicans")
plt.show()
通過(guò)圖像耿芹,我們可以看到崭篡,svm和mpl-nn預(yù)測(cè)出的占比和實(shí)際數(shù)據(jù)差太多了,索性干掉他們倆吧秕。操作的話琉闪,這里不做解釋了,刪掉相關(guān)代碼即可砸彬。
- 那么每次都要通過(guò)觀察來(lái)刪掉不好的算法颠毙,太人工了斯入,一點(diǎn)也不智能。那么我們可以使用stacking的方式進(jìn)行操作蛀蜜,在大集合算法拿到的預(yù)測(cè)值刻两,再找一個(gè)裝B的算法進(jìn)行二階段的訓(xùn)練,來(lái)調(diào)整每個(gè)算法的權(quán)重配比滴某。
meta_learner = GradientBoostingClassifier(#第二階段分類(lèi)器
n_estimators=1000,
loss="exponential",
max_features=4,
max_depth=3,
subsample=0.5,
learning_rate=0.005,
random_state=SEED
)
- 當(dāng)?shù)谝浑A段的結(jié)果在第二階段繼續(xù)訓(xùn)練磅摹,已經(jīng)產(chǎn)生了權(quán)重上的傾斜,即嚼過(guò)的飯?jiān)俳酪淮析荩苋菀壮霈F(xiàn)過(guò)擬合户誓,可采用交叉驗(yàn)證的思想。將訓(xùn)練集一分為二椰憋。
1.用交叉訓(xùn)練集訓(xùn)練模型厅克,
2.交叉驗(yàn)證集產(chǎn)生第二階段的輸入即可解決(畢竟交叉驗(yàn)證集沒(méi)有進(jìn)行反向傳播調(diào)整權(quán)重)
#切分交叉訓(xùn)練集和驗(yàn)證集
xtrain_base, xpred_base, ytrain_base, ypred_base = train_test_split(
xtrain, ytrain, test_size=0.5, random_state=SEED)
#訓(xùn)練模型方法
def train_base_learners(base_learners, inp, out, verbose=True):
if verbose: print("Fitting models.")
for i, (name, m) in enumerate(base_learners.items()):
if verbose: print("%s..." % name, end=" ", flush=False)
m.fit(inp, out)
if verbose: print("done")
# 第一階段預(yù)測(cè)出作為第二階段輸入的值
def predict_base_learners(pred_base_learners, inp, verbose=True):
P = np.zeros((inp.shape[0], len(pred_base_learners)))
if verbose: print("Generating base learner predictions.")
for i, (name, m) in enumerate(pred_base_learners.items()):
if verbose: print("%s..." % name, end=" ", flush=False)
p = m.predict_proba(inp)
P[:, i] = p[:, 1]
if verbose: print("done")
return P
#對(duì)stacking模型進(jìn)行訓(xùn)練
def ensemble_predict(base_learners, meta_learner, inp, verbose=True):
P_pred = predict_base_learners(base_learners, inp, verbose=verbose)
return P_pred, meta_learner.predict_proba(P_pred)[:, 1]
#開(kāi)始訓(xùn)練
train_base_learners(base_learners, xtrain_base, ytrain_base)
#交叉預(yù)測(cè),可拿到第二階段的輸入
P_base = predict_base_learners(base_learners, xpred_base)
#在第二階段進(jìn)行各個(gè)算法的權(quán)重訓(xùn)練橙依,即完成對(duì)mata_learner的訓(xùn)練
meta_learner.fit(P_base, ypred_base)
#用測(cè)試集進(jìn)行最終測(cè)試
P_pred, p = ensemble_predict(base_learners, meta_learner, xtest)
print("\nEnsemble ROC-AUC score: %.3f" % roc_auc_score(ytest, p)) #0.880
但我們發(fā)現(xiàn)效果并沒(méi)有好多少证舟,那是因?yàn)槲覀冊(cè)谟?xùn)練階段拿到的數(shù)據(jù)少了一半,效果肯定不好按捌铩女责!那么我們可以采用真正的交叉驗(yàn)證來(lái)解決這種粗暴的拆分方式,具體代碼這里不寫(xiě)了创译,請(qǐng)參考另一篇文章離散型隨機(jī)變量的二分類(lèi)預(yù)測(cè)案例
,里面有關(guān)于交叉驗(yàn)證具體的操作代碼抵知。
- 然而之前推薦的mlens庫(kù)中自帶了集成算法的框架,就和隨機(jī)森林一樣软族,不用我們這樣造輪子了刷喜,里面已經(jīng)寫(xiě)好了并行訓(xùn)練多分類(lèi)器,交叉驗(yàn)證等操作,上代碼:
from mlens.ensemble import SuperLearner
# 集成算法分類(lèi)器
sl = SuperLearner(
folds=10,
random_state=SEED,
verbose=2,
backend="multiprocessing"
)
# 指定各階段的算法
sl.add(list(base_learners.values()), proba=True)
sl.add_meta(meta_learner, proba=True)
# 訓(xùn)練
sl.fit(xtrain, ytrain)
# 評(píng)分
p_sl = sl.predict_proba(xtest)
print("\nSuper Learner ROC-AUC score: %.3f" % roc_auc_score(ytest, p_sl[:, 1]))#0.889
效果不錯(cuò)立砸。
以上內(nèi)容介紹了集成算法的一些思想掖疮,通過(guò)代碼從決策樹(shù),隨機(jī)森林颗祝,stacking等角度實(shí)踐了預(yù)測(cè)方法浊闪,對(duì)于數(shù)據(jù)的預(yù)處理沒(méi)有進(jìn)行過(guò)多操作。
完整代碼:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
import pydotplus
from IPython.display import Image
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.ensemble import RandomForestClassifier
from mlens.visualization import corrmat
from sklearn.metrics import roc_curve
# 指定隨機(jī)種子
SEED = 222
np.random.seed(SEED)
df = pd.read_csv('input.csv')
# 切分?jǐn)?shù)據(jù)集
def get_train_test(test_size=0.95):
y = 1 * (df.cand_pty_affiliation == "REP") # 標(biāo)簽值轉(zhuǎn)變0螺戳。1值
X = df.drop(["cand_pty_affiliation"], axis=1) #制作X搁宾,所以去掉y的那一列
X = pd.get_dummies(X) #屬性值離散化
X.drop(X.columns[X.std() == 0], axis=1, inplace=True) #去掉標(biāo)準(zhǔn)差為0的列(因?yàn)檫@樣的數(shù)據(jù)對(duì)程序沒(méi)卵用)
return train_test_split(X, y, test_size=test_size, random_state=SEED)
print("\nExample data:")
print(df.head())
xtrain, xtest, ytrain, ytest = get_train_test()
# #以占比形式展示兩個(gè)黨派的數(shù)據(jù)分布,normalize=True:以百分比形式展示
# df.cand_pty_affiliation.value_counts(normalize=True).plot(
# kind="bar", title="Share of No. donations")
# plt.show()
# #打印出決策樹(shù)的圖片
# def print_graph(clf, feature_names):
# graph = export_graphviz(
# clf,
# label="root",
# proportion=True,
# impurity=False,
# out_file=None,
# feature_names=feature_names,
# class_names={0: "D", 1: "R"},
# filled=True,
# rounded=True
# )
# graph = pydotplus.graph_from_dot_data(graph)
# img = Image(graph.create_png())
# graph.write_png("partycontri.png")
# return img
#
# #構(gòu)建深度為3的決策樹(shù)
# t2 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
# t2.fit(xtrain, ytrain)
# p = t2.predict_proba(xtest)[:, 1]
#
# #計(jì)算出AUC
# print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.751
# #繪制出決策樹(shù)的圖片,根據(jù)圖中內(nèi)容發(fā)現(xiàn)過(guò)擬合倔幼,
# # print_graph(t2, xtrain.columns)
#
#
# #去掉先前最重要特征盖腿,再看看新決策樹(shù)是否會(huì)有好轉(zhuǎn)
# drop = ["transaction_amt"]
# xtrain_slim = xtrain.drop(drop, axis=1)
# xtest_slim = xtest.drop(drop, axis=1)
# t3 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
# t3.fit(xtrain_slim, ytrain)
# p = t3.predict_proba(xtest_slim)[:, 1]
# print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.740
# print_graph(t3, xtrain_slim.columns)
#
# #開(kāi)始集成部分!
# #使用bagging思想凤藏,手動(dòng)求平均分
# p1 = t2.predict_proba(xtest)[:, 1]
# p2 = t3.predict_proba(xtest_slim)[:, 1]
# p = np.mean([p1, p2], axis=0)#計(jì)算平均值
# print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.783
#使用bagging思想奸忽,使用sklearn提供的決策森林直接玩
# '''
# max_features:隨機(jī)森林允許單個(gè)決策樹(shù)使用特征的最大數(shù)量堕伪。 Python為最大特征數(shù)提供了多個(gè)可選項(xiàng)。 下面是其中的幾個(gè):
# Auto/None :簡(jiǎn)單地選取所有特征栗菜,每顆樹(shù)都可以利用他們欠雌。這種情況下,每顆樹(shù)都沒(méi)有任何的限制疙筹。
# sqrt :此選項(xiàng)是每顆子樹(shù)可以利用總特征數(shù)的平方根個(gè)富俄。 例如,如果變量(特征)的總數(shù)是100而咆,所以每顆子樹(shù)只能取其中的10個(gè)霍比。“l(fā)og2”是另一種相似類(lèi)型的選項(xiàng)暴备。
# 0.2:此選項(xiàng)允許每個(gè)隨機(jī)森林的子樹(shù)可以利用變量(特征)數(shù)的20%悠瞬。如果想考察的特征x%的作用, 我們可以使用“0.X”的格式
# '''
# rf = RandomForestClassifier(
# n_estimators=10,#搞10棵樹(shù)
# max_features=3,
# random_state=SEED
# )
#
# rf.fit(xtrain, ytrain)
# p = rf.predict_proba(xtest)[:, 1]
# print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))
# #====================================================================================================================
#
#
# #使用bagging思想搞一個(gè)多種分類(lèi)器的集成模型
from sklearn.svm import SVC, LinearSVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.kernel_approximation import Nystroem
from sklearn.kernel_approximation import RBFSampler
from sklearn.pipeline import make_pipeline
#構(gòu)建基礎(chǔ)分類(lèi)器(分類(lèi)器大合集)
def get_models():
nb = GaussianNB()
svc = SVC(C=100, probability=True)
knn = KNeighborsClassifier(n_neighbors=3)
lr = LogisticRegression(C=100, random_state=SEED)
nn = MLPClassifier((80, 10), early_stopping=False, random_state=SEED)
gb = GradientBoostingClassifier(n_estimators=100, random_state=SEED)
rf = RandomForestClassifier(n_estimators=10, max_features=3, random_state=SEED)
models = {'svm': svc,
'knn': knn,
'naive bayes': nb,
'mlp-nn': nn,
'random forest': rf,
'gbm': gb,
'logistic': lr,
}
return models
#訓(xùn)練模型
def train_predict(model_list):
P = np.zeros((ytest.shape[0], len(model_list))) # 初始化好結(jié)果集框架
P = pd.DataFrame(P)
print("Fitting models.")
cols = list()
for i, (name, m) in enumerate(model_list.items()):
print("%s..." % name, end=" ", flush=False)
m.fit(xtrain, ytrain)
P.iloc[:, i] = m.predict_proba(xtest)[:, 1]
cols.append(name)
print("done")
P.columns = cols #設(shè)置表頭
print("Done.\n")
return P
#評(píng)估
def score_models(P, y):
print("Scoring models.")
for m in P.columns:
score = roc_auc_score(y, P.loc[:, m]) #P.loc[:, m]含義:取列名為m的列的所有行(即取出名為m的列)
print("%-26s: %.3f" % (m, score))
print("Done.\n")
models = get_models()
P = train_predict(models)
score_models(P, ytest)
#使用mlens將集成算法的關(guān)系和計(jì)算結(jié)果可視化
corrmat(P.corr(), inflate=False)
plt.show()
print("Ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.mean(axis=1)))#bagging一下涯捻,0.884
#繪制roc曲線,y值浅妆,預(yù)測(cè)值,集成值障癌,標(biāo)簽名列表凌外,集成標(biāo)簽名
def plot_roc_curve(ytest, P_base_learners, P_ensemble, labels, ens_label):
plt.figure(figsize=(10, 8))
plt.plot([0, 1], [0, 1], 'k--') #'‐‐' 破折線
cm = [plt.cm.rainbow(i)
for i in np.linspace(0, 1.0, P_base_learners.shape[1] + 1)] #7個(gè)單獨(dú)算法+1個(gè)集成算法
for i in range(P_base_learners.shape[1]):
p = P_base_learners[:, i]
fpr, tpr, _ = roc_curve(ytest, p)
plt.plot(fpr, tpr, label=labels[i], c=cm[i + 1])
fpr, tpr, _ = roc_curve(ytest, P_ensemble)
plt.plot(fpr, tpr, label=ens_label, c=cm[0])
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve')
plt.legend(frameon=False)
plt.show()
plot_roc_curve(ytest, P.values, P.mean(axis=1), list(P.columns), "ensemble")
#各個(gè)算法預(yù)測(cè)的共和黨占比
p = P.apply(lambda x: 1*(x >= 0.5).value_counts(normalize=True))
p.index = ["DEM", "REP"]
p.loc["REP", :].sort_values().plot(kind="bar")
plt.axhline(0.25, color="k", linewidth=0.5)
plt.text(0., 0.23, "True share republicans")
plt.show()
#
# 通過(guò)上一步展示的圖片發(fā)現(xiàn)svm和mlp-nn和真實(shí)的共和黨比例相差太大,那么我們手動(dòng)直接干掉涛浙,
include = [c for c in P.columns if c not in ["mlp-nn"]]
print("Truncated ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.loc[:, include].mean(axis=1)))
#====================================================================================================
#手動(dòng)去找麻煩康辑,可利用stacking的思想,在第二階段訓(xùn)練每個(gè)算法的權(quán)重值
base_learners = get_models()
meta_learner = GradientBoostingClassifier(#第二階段分類(lèi)器
n_estimators=1000,
loss="exponential",
max_features=4,
max_depth=3,
subsample=0.5,
learning_rate=0.005,
random_state=SEED
)
#當(dāng)?shù)谝浑A段的結(jié)果在第二階段繼續(xù)訓(xùn)練轿亮,嚼過(guò)的飯?jiān)俳酪淮未保苋菀壮霈F(xiàn)過(guò)擬合,可采用交叉驗(yàn)證我注,用交叉訓(xùn)練集訓(xùn)練模型惦辛,交叉驗(yàn)證集產(chǎn)生第二階段的輸入即可解決(畢竟交叉驗(yàn)證集沒(méi)有進(jìn)行反向傳播調(diào)整權(quán)重)
#切分交叉訓(xùn)練集和驗(yàn)證集
xtrain_base, xpred_base, ytrain_base, ypred_base = train_test_split(
xtrain, ytrain, test_size=0.5, random_state=SEED)
#訓(xùn)練模型方法
def train_base_learners(base_learners, inp, out, verbose=True):
if verbose: print("Fitting models.")
for i, (name, m) in enumerate(base_learners.items()):
if verbose: print("%s..." % name, end=" ", flush=False)
m.fit(inp, out)
if verbose: print("done")
# 第一階段預(yù)測(cè)出作為第二階段輸入的值
def predict_base_learners(pred_base_learners, inp, verbose=True):
P = np.zeros((inp.shape[0], len(pred_base_learners)))
if verbose: print("Generating base learner predictions.")
for i, (name, m) in enumerate(pred_base_learners.items()):
if verbose: print("%s..." % name, end=" ", flush=False)
p = m.predict_proba(inp)
P[:, i] = p[:, 1]
if verbose: print("done")
return P
#對(duì)stacking模型進(jìn)行訓(xùn)練
def ensemble_predict(base_learners, meta_learner, inp, verbose=True):
P_pred = predict_base_learners(base_learners, inp, verbose=verbose)
return P_pred, meta_learner.predict_proba(P_pred)[:, 1]
#開(kāi)始訓(xùn)練
train_base_learners(base_learners, xtrain_base, ytrain_base)
#交叉預(yù)測(cè),可拿到第二階段的輸入
P_base = predict_base_learners(base_learners, xpred_base)
#在第二階段進(jìn)行各個(gè)算法的權(quán)重訓(xùn)練仓手,即完成對(duì)mata_learner的訓(xùn)練
meta_learner.fit(P_base, ypred_base)
#用測(cè)試集進(jìn)行最終測(cè)試
P_pred, p = ensemble_predict(base_learners, meta_learner, xtest)
print("\nEnsemble ROC-AUC score: %.3f" % roc_auc_score(ytest, p)) #0.880
#由于之前的暴力切分驗(yàn)證集,導(dǎo)致數(shù)據(jù)損失了一半玻淑,可以進(jìn)行真正的交叉驗(yàn)證嗽冒,具體代碼可參考信用卡欺詐
#現(xiàn)在利用現(xiàn)成的集成算法庫(kù)mlens實(shí)現(xiàn)
from mlens.ensemble import SuperLearner
# 集成算法分類(lèi)器
sl = SuperLearner(
folds=10,
random_state=SEED,
verbose=2,
backend="multiprocessing"
)
# 指定各階段的算法
sl.add(list(base_learners.values()), proba=True)
sl.add_meta(meta_learner, proba=True)
# 訓(xùn)練
sl.fit(xtrain, ytrain)
# 評(píng)分
p_sl = sl.predict_proba(xtest)
print("\nSuper Learner ROC-AUC score: %.3f" % roc_auc_score(ytest, p_sl[:, 1]))#0.889