數據挖掘--模型參數調優


模型評估

使用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.貝葉斯調參:

  在搜索空間過大的時候,網格搜索的速度實在不太能讓人接受,貝葉斯調參相對於網格搜索的優勢如下

  • 貝葉斯調參采用高斯過程,會考慮到之前的參數信息,不斷地更新先驗;網格搜索則不會考慮先驗信息。
  • 貝葉斯調參迭代次數少,速度快;網格搜索會遍歷所有的可能的參數組合,所以速度慢,參數多時易導致維度爆炸
  • 貝葉斯調參針對非凸問題依然穩健;網格搜索針對非凸問題易得到局部最優。
  糾結原理的話可以看一看這篇文章( https://www.cnblogs.com/marsggbo/p/9866764.html). 核心的想法是利用已有的先驗知識去找到是目標函數達到全局最優的參數.代碼如下:
  
# 貝葉斯調參

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 有貝葉斯調參代碼更加詳細的一個介紹

 

 

 

 

附錄:

常用模型的鏈接一個記錄回頭整理一下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM