模型評估
使用metric函數來進行評分
sklearn.metrics里面提供了一些函數來幫助我們進行評分。其中里面以_score結尾的函數的返回值越大,模型的性能越好。而以_error或_loss結尾的函數,返回值越小,表示模型性能越好。從命名上來看,這一點不難理解。
metrics里面的很多函數名不直接傳入scoring后面,因為有一些函數需要傳入特定的參數才能夠使用。比如在使用fbeta_score的時候需要傳入bata參數等。 在這個時候,我們的做法是把函數名和參數封裝一下,封裝成為一個新的函數,然后傳入scoring后面。封裝的方法是使用metrics的make_scorer方法。
from sklearn.metrics import make_scorer, fbeta_score #我們用make_scorer封裝了fbeta_score,它需要傳入一個參數 ftwo_score = make_scorer(fbeta_score, beta=2) from sklearn.model_selection import GridSearchCV from sklearn.svm import LinearSVC grid = GridSearchCV(LinearSVC(), param_grid={‘C‘:[1, 10]}, scoring=ftwo_score)
使用metrics的make_score方法,我們可以制定出我們自己的方法,這個方法需要滿足下面一些條件:
- 需要傳入一個我們自定義的函數的名稱
- 需說明greater_is_better的值是True還是False。 當值為正的時候,返回的是score的值,值越高性能越好。當為False的時候,返回的為score的負值,值越低越好。
- 是否是針對分類問題的。 傳入needs_threshold=True來說明是針對分類問題的,默認情況為False。
- 其余的參數。如在f1_score中的bata,labels。
import numpy as np from sklearn.metrics import make_scorer def my_custom_loss_func(ground_truth, predictions): diff = np.abs(ground_truth - predictions).max() return np.log(1 + diff) loss = make_scorer(my_custom_loss_func, greater_is_better=False) score = make_scorer(my_custom_loss_func, greater_is_better=True) ground_truth = [[1], [1]] predictions = [0, 1] from sklearn.dummy import DummyClassifier clf = DummyClassifier(strategy=‘most_frequent‘, random_state=0) clf = clf.fit(ground_truth, predictions) #這段代碼的原理是這樣的,我們的clf使用ground_truth 和predictions進行訓練 #使用clf.predict(ground_truth) 進行預測以后的結果為[0,0], #my_custom_loss_func(np.array([0,0], np.array[0,1]) 最后得到log(2) = 0.69314 print(score(clf, ground_truth, predictions)) print(loss(clf, ground_truth, predictions))
我們還可以實現我們自己的評分對象.為了實現更高的自由度,我們可以不使用上述的make_scorer方法,完全定制出來我們自己的評分對象,這需要遵循兩點
- 能夠調用(estimater, X, y)參數,estimater是我們的模型,X為數據集, y為X數據集的真實結果。
- 需要返回一個分數作為評分的結果。該分數能夠從某個方面反映出我們模型的好壞。
模型調參
1.貪心調參
采用貪心算法選取局部最優的思想,每次選擇一個參數(其他參數為默認或者為已經調至最優的參數)調至最優。代碼如下:
## LGB的參數集合: objective = ['regression', 'regression_l1', 'mape', 'huber', 'fair'] num_leaves = [3,5,10,15,20,40, 55] max_depth = [3,5,10,15,20,40, 55] bagging_fraction = [] feature_fraction = [] drop_rate = [] # 貪心調參 每一輪針對某個特征找到最優的值, # key-參數名字 value為對應的參數值 best_obj = dict() for obj in objective: model = LGBMRegressor(objective=obj) score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))) best_obj[obj] = score best_leaves = dict() for leaves in num_leaves: model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=leaves) score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))) best_leaves[leaves] = score best_depth = dict() for depth in max_depth: model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=min(best_leaves.items(), key=lambda x:x[1])[0], max_depth=depth) score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))) best_depth[depth] = score sns.lineplot(x=['0_initial','1_turning_obj','2_turning_leaves','3_turning_depth'], y=[0.143 ,min(best_obj.values()), min(best_leaves.values()), min(best_depth.values())])
2.網格調參(Grid Search)
Sklearn-GridSearchCV:一種調參的方法,當你算法模型效果不是很好時,可以通過該方法來調整參數,通過循環遍歷,嘗試每一種參數組合,返回最好的得分值的參數組合。由於遍歷的組合較多,在算力條件一般的情況下,適用於小數據集。代碼如下:
# grid search 網格搜索調參 遍歷所有給定的值進行調參 適用於小數據集 # 原來的數據集分割為訓練集和測試集之后,其中測試集起到的作用有兩個,一個是用來調整參數,一個是用來評價模型的好壞,這樣會導致評分值會比實際效果要好。(因為我們將測試集送到了模型里面去測試模型的好壞,而我們目的是要將訓練模型應用在沒使用過的數據上。) from sklearn.model_selection import GridSearchCV parameters = {'objective': objective , 'num_leaves': num_leaves, 'max_depth': max_depth} model = LGBMRegressor() # 交叉驗證~ clf = GridSearchCV(model, parameters, cv=5) clf = clf.fit(train_X, train_y) clf.best_params_
3.貝葉斯調參:
在搜索空間過大的時候,網格搜索的速度實在不太能讓人接受,貝葉斯調參相對於網格搜索的優勢如下
- 貝葉斯調參采用高斯過程,會考慮到之前的參數信息,不斷地更新先驗;網格搜索則不會考慮先驗信息。
- 貝葉斯調參迭代次數少,速度快;網格搜索會遍歷所有的可能的參數組合,所以速度慢,參數多時易導致維度爆炸
- 貝葉斯調參針對非凸問題依然穩健;網格搜索針對非凸問題易得到局部最優。
# 貝葉斯調參 from bayes_opt import BayesianOptimization from sklearn.metrics import mean_absolute_error, make_scorer # 用 make_scorer封裝metrics中的評分函數供scoring使用 def rf_cv(num_leaves, max_depth, subsample, min_child_samples): val = cross_val_score( LGBMRegressor(objective = 'regression_l1', num_leaves=int(num_leaves), max_depth=int(max_depth), subsample = subsample, min_child_samples = int(min_child_samples) ), X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error) ).mean() return 1 - val # 核心三個部分 目標函數的設計:rf_cv,域空間的設定(參數范圍),最優化search rf_bo = BayesianOptimization( rf_cv, { 'num_leaves': (2, 100), 'max_depth': (2, 100), 'subsample': (0.1, 1), 'min_child_samples' : (2, 100) } ) rf_bo.maximize() # 輸出最優參數組合 print(rf_bo.max)
https://github.com/fmfn/BayesianOptimization 有貝葉斯調參代碼更加詳細的一個介紹
附錄:
常用模型的鏈接一個記錄回頭整理一下: