快速比較多種機(jī)器學(xué)習(xí)模型實(shí)例
介紹
當(dāng)從事機(jī)器學(xué)習(xí)項(xiàng)目時(shí),所有數(shù)據(jù)科學(xué)家都必須面對(duì)的一個(gè)問(wèn)題是:哪種機(jī)器學(xué)習(xí)模型架構(gòu)比較適合我的數(shù)據(jù)呢?
不幸的是,對(duì)于哪種模型比較好,還沒(méi)有明確的答案。當(dāng)面對(duì)這種不確定性的時(shí)候,常用的方法是:實(shí)驗(yàn)!
在本文中,我將向您展示如何快速測(cè)試數(shù)據(jù)集上的多個(gè)模型,以找到可能提供優(yōu)質(zhì)性能的機(jī)器學(xué)習(xí)模型,從而使您能夠?qū)⒕性谀P偷奈⒄{(diào)和優(yōu)化上。
機(jī)器學(xué)習(xí)數(shù)據(jù)集
在開(kāi)始實(shí)驗(yàn)之前,我們需要一個(gè)數(shù)據(jù)集。我將假設(shè)我們的問(wèn)題是有監(jiān)督的二元分類(lèi)任務(wù)。讓我們從sklearn加載乳腺癌數(shù)據(jù)集開(kāi)始。
- from sklearn.datasets import load_breast_cancer
- X, y = data = load_breast_cancer(return_X_y=True)
接下來(lái),我們需要將數(shù)據(jù)拆分為訓(xùn)練集和測(cè)試集。拆分比例為75/25。
- from sklearn.model_selection import train_test_split
- X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=8675309)
Python編碼
我們將在此數(shù)據(jù)集上快速測(cè)試6種不同模型的擬合度。
- 邏輯回歸
- 隨機(jī)森林
- K最近鄰居
- 支持向量機(jī)
- 高斯樸素貝葉斯
- XGBoost
為了更準(zhǔn)確地表示每個(gè)模型的擬合度,實(shí)際上是需要調(diào)整默認(rèn)參數(shù)的,但是,本文出于演示目的,我將使用每個(gè)模型的默認(rèn)參數(shù),這樣可以使總體思路更加清晰。
- from sklearn.linear_model import LogisticRegression
- from sklearn.neighbors import KNeighborsClassifier
- from sklearn.svm import SVC
- from sklearn.ensemble import RandomForestClassifier
- from sklearn.naive_bayes import GaussianNB
- from xgboost import XGBClassifier
- from sklearn import model_selection
- from sklearn.utils import class_weight
- from sklearn.metrics import classification_report
- from sklearn.metrics import confusion_matrix
- import numpy as np
- import pandas as pd
- def run_exps(X_train: pd.DataFrame , y_train: pd.DataFrame, X_test: pd.DataFrame, y_test: pd.DataFrame) -> pd.DataFrame:
- '''
- Lightweight script to test many models and find winners
- :param X_train: training split
- :param y_train: training target vector
- :param X_test: test split
- :param y_test: test target vector
- :return: DataFrame of predictions
- '''
- dfs = []
- models = [
- ('LogReg', LogisticRegression()),
- ('RF', RandomForestClassifier()),
- ('KNN', KNeighborsClassifier()),
- ('SVM', SVC()),
- ('GNB', GaussianNB()),
- ('XGB', XGBClassifier())
- ]
- results = []
- names = []
- scoring = ['accuracy', 'precision_weighted', 'recall_weighted', 'f1_weighted', 'roc_auc']
- target_names = ['malignant', 'benign']
- for name, model in models:
- kfold = model_selection.KFold(n_splits=5, shuffle=True, random_state=90210)
- cv_results = model_selection.cross_validate(model, X_train, y_train, cv=kfold, scoring=scoring)
- clf = model.fit(X_train, y_train)
- y_pred = clf.predict(X_test)
- print(name)
- print(classification_report(y_test, y_pred, target_names=target_names))
- results.append(cv_results)
- names.append(name)
- this_df = pd.DataFrame(cv_results)
- this_df['model'] = name
- dfs.append(this_df)
- final = pd.concat(dfs, ignore_index=True)
- return final
- final=run_exps(X_train,y_train, X_test, y_test )
- final
在上面的Python代碼中有很多東西需要解釋。首先,我們創(chuàng)建一個(gè)變量dfs,該變量用來(lái)保存通過(guò)對(duì)訓(xùn)練集上應(yīng)用5-fold交叉驗(yàn)證創(chuàng)建的數(shù)據(jù)集。
接下來(lái),models保存在元組列表中,其中包含要測(cè)試的每個(gè)分類(lèi)器的名稱(chēng)和類(lèi)。在此之后,我們循環(huán)遍歷這個(gè)列表并運(yùn)行5-fold交叉驗(yàn)證。每次運(yùn)行的結(jié)果都記錄在我們附加到dfs列表的pandas dataframe中。必須注意,這里指標(biāo)是兩個(gè)類(lèi)的加權(quán)平均指標(biāo)。
測(cè)試集上的分類(lèi)報(bào)告如下:

評(píng)估結(jié)果
我們將分析從run_exps()腳本返回的final(dataframe)中的數(shù)據(jù)。
為了更好地估計(jì)每個(gè)模型的指標(biāo)分布,我在30個(gè)樣本上運(yùn)行了empirical bootstrapping。此外,我將關(guān)注兩個(gè)指標(biāo):性能指標(biāo)和擬合時(shí)間指標(biāo)。下面的Python代碼塊實(shí)現(xiàn)了這一點(diǎn)。
- bootstraps = []
- for model in list(set(final.model.values)):
- model_df = final.loc[final.model == model]
- bootstrap = model_df.sample(n=30, replace=True)
- bootstraps.append(bootstrap)
- bootstrap_df = pd.concat(bootstraps, ignore_index=True)
- results_long = pd.melt(bootstrap_df,id_vars=['model'],var_name='metrics', value_name='values')
- time_metrics = ['fit_time','score_time'] # fit time metrics
- ## PERFORMANCE METRICS
- results_long_nofit = results_long.loc[~results_long['metrics'].isin(time_metrics)] # get df without fit data
- results_long_nofit = results_long_nofit.sort_values(by='values')
- ## TIME METRICS
- results_long_fit = results_long.loc[results_long['metrics'].isin(time_metrics)] # df with fit data
- results_long_fit = results_long_fit.sort_values(by='values')
首先,讓我們繪制來(lái)自5-fold交叉驗(yàn)證的性能指標(biāo)。
- import matplotlib.pyplot as plt
- import seaborn as sns
- plt.figure(figsize=(20, 12))
- sns.set(font_scale=2.5)
- g = sns.boxplot(x="model", y="values", hue="metrics", data=results_long_nofit, palette="Set3")
- plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
- plt.title('Comparison of Model by Classification Metric')
- #plt.savefig('./benchmark_models_performance.png',dpi=300)
- plt.show()

很明顯,支持向量機(jī)在所有指標(biāo)上對(duì)我們的數(shù)據(jù)的擬合度都很差,而集成決策樹(shù)模型(Random Forest和XGBoost)對(duì)數(shù)據(jù)的擬合非常好。
訓(xùn)練時(shí)間怎么樣呢?
- plt.figure(figsize=(20, 12))
- sns.set(font_scale=2.5)
- g = sns.boxplot(x="model", y="values", hue="metrics", data=results_long_fit, palette="Set3")
- plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
- plt.title('Comparison of Model by Fit and Score Time')
- plt.show()

隨機(jī)森林雖然相對(duì)于KNN、GNB和LogReg來(lái)說(shuō)比較慢,但其性能僅次于KNN。如果我繼續(xù)細(xì)化模型,我可能會(huì)將大部分精力集中在隨機(jī)森林上,因?yàn)樗男阅軒缀跖cXGBoost相同(它們的95%置信區(qū)間可能重疊),但訓(xùn)練速度幾乎快了4倍!
如果您希望對(duì)這些模型進(jìn)行更多的分析(例如,計(jì)算每個(gè)度量標(biāo)準(zhǔn)的置信區(qū)間),您將需要訪問(wèn)每個(gè)度量標(biāo)準(zhǔn)的均值和標(biāo)準(zhǔn)差。
- metrics = list(set(results_long_nofit.metrics.values))
- bootstrap_df.groupby(['model'])[metrics].agg([np.std, np.mean])

- time_metrics = list(set(results_long_fit.metrics.values))
- bootstrap_df.groupby(['model'])[time_metrics].agg([np.std, np.mean])

結(jié)論
上述分析只考慮了平均精度、召回率等。在實(shí)際問(wèn)題中,您不太可能關(guān)心類(lèi)之間的平均精度,相反,您可能會(huì)特別關(guān)注某個(gè)類(lèi)的精度!此外,必須調(diào)整每個(gè)機(jī)器學(xué)習(xí)模型的超參數(shù),以真正評(píng)估它們與數(shù)據(jù)的擬合程度。