python使用hyperopt工具進(jìn)行自動調(diào)參

學(xué)習(xí)原因:

通過學(xué)習(xí)“魔鏡杯”風(fēng)控大賽金獎獲得者的代碼,發(fā)現(xiàn)在模型建立完畢之后八千,可以使用hyperopt包進(jìn)行自動化參數(shù)調(diào)優(yōu)吗讶。而不需要人工不停輸入?yún)?shù)進(jìn)行判斷燎猛,尤其在參數(shù)組合較多的情況下,很好用照皆。

參數(shù)調(diào)優(yōu)常用的工具包:

常用的調(diào)參方式有 grid search 和 random search 重绷,grid search 是全空間掃描,所以比較慢膜毁,random search 雖然快昭卓,但可能錯失空間上的一些重要的點(diǎn),精度不夠瘟滨,于是候醒,貝葉斯優(yōu)化出現(xiàn)了。

hyperopt是一種通過貝葉斯優(yōu)化(貝葉斯優(yōu)化簡介)來調(diào)整參數(shù)的工具杂瘸,對于像XGBoost這種參數(shù)比較多的算法倒淫,可以用它來獲取比較好的參數(shù)值。

使用方法

fmin應(yīng)該是最重要的一個方法了败玉,下面要介紹的都是在fmin中可以設(shè)置的參數(shù)昌简。全文是通過對fmin參數(shù)的介紹和使用來進(jìn)行搜索模型的最優(yōu)化參數(shù)的。
Hyheropt四個重要的因素:指定需要最小化的函數(shù)绒怨,搜索的空間纯赎,采樣的數(shù)據(jù)集(trails database)(可選),搜索的算法(可選)南蹂。
先來一個簡單的例子犬金,然后根據(jù)這個列子進(jìn)行講解和擴(kuò)展

from hyperopt import hp, fmin, rand, tpe, space_eval
space = [hp.uniform(’x’, 0, 1), hp.normal(’y’, 0, 1)]
def q (args) :
    x, y = args
    return x ?? 2 + y ?? 2
best = fmin(q, space, algo=rand.suggest,max_evals=100)
print space_eval(space, best)

以上面的函數(shù)為例,fmin尋找最佳匹配的 space 六剥,使 fn 的函數(shù)返回值最小晚顷,采用了 tpe.suggest (tree of Parzen estimators) 的算法,反復(fù)嘗試100次疗疟,最終得到的結(jié)果類似于 {'x': 0.000269455723739237}

最小化目標(biāo)函數(shù)

首先该默,定義一個目標(biāo)函數(shù),接受一個變量,計算后返回一個函數(shù)的損失值,比如要最小化函數(shù)q(x,y) = x2 + y2策彤。注意栓袖,一定是loss內(nèi)涵的min函數(shù),不要是score那種的max函數(shù)

搜索空間

定義一個參數(shù)空間店诗,比如x在0-1區(qū)間內(nèi)取值裹刮,y是實(shí)數(shù),所以在上面的代碼中為
hp.uniform(label,start,end)

搜索空間表現(xiàn)形式

搜索空間可以含有l(wèi)ist和dictionary.

from hyperopt import hp
list_space = [
hp.uniform(’a’, 0, 1),
hp.loguniform(’b’, 0, 1)]
tuple_space = (
hp.uniform(’a’, 0, 1),
hp.loguniform(’b’, 0, 1))
dict_space = {
’a’: hp.uniform(’a’, 0, 1),
’b’: hp.loguniform(’b’, 0, 1)}

使用sample函數(shù)從參數(shù)空間內(nèi)采樣:

from hyperopt.pyll.stochasti import sample
print sample(list_space)
# => [0.13, .235]
print sample(nested_space)
# => [[{’case’: 1, ’a’, 0.12‘}, {’case’: 2, ’b’: 2.3}],
# ’extra_literal_string’,
# 3]

可選參數(shù)

  • hp.choice 可以返回list中的值庞瘸,還可以構(gòu)成tuple.options捧弃,用于組成條件參數(shù)
num_leaves=hp.choice('num_leaves',range(10,100,10))
  • hp.pchoice(label,p_options)以一定的概率返回一個p_options的一個選項。這個選項使得函數(shù)在搜索過程中對每個選項的可能性不均勻。
  • hp.uniform(label,low,high)參數(shù)在low和high之間均勻分布违霞。
  • hp.quniform(label,low,high,q),參數(shù)的取值round(uniform(low,high)/q)*q嘴办,適用于那些離散的取值。
  • hp.loguniform(label,low,high) 返回根據(jù) exp(uniform(low买鸽,high)) 繪制的值涧郊,以便返回值的對數(shù)是均勻分布的。
    優(yōu)化時癞谒,該變量被限制在[exp(low)底燎,exp(high)]區(qū)間內(nèi)。
  • hp.randint(label,upper) 返回一個在[0,upper)前閉后開的區(qū)間內(nèi)的隨機(jī)整數(shù)弹砚。
  • hp.normal(label, mu, sigma) where mu and sigma are the mean and standard deviation σ , respectively. 正態(tài)分布双仍,返回值范圍沒法限制。
  • hp.qnormal(label, mu, sigma, q)
  • hp.lognormal(label, mu, sigma)
  • hp.qlognormal(label, mu, sigma, q)

注意事項

  • 如果需要枚舉從[1, 100]桌吃,那么用choice朱沃,而不應(yīng)該用quniform hp.randint(label, upper) 返回從[0, upper)的隨機(jī)整數(shù),一般用作隨機(jī)數(shù)的種子值茅诱。
  • hp.quniform(label, low, high) where low and high are the lower and upper bounds on the range. 但只取整數(shù)(round)的float形式逗物,返回可能是 1.0 這樣的數(shù)值,如果模型參數(shù)類型有Interger的限制瑟俭,需要顯式做一個 int()的轉(zhuǎn)換翎卓。
  • hp.loguniform(label, low, high) 返回的值在 [elow,ehigh] 之間,屬于log uniform分布摆寄,取值偏聚集于前部失暴,概率上類似于拋物線

一個比較復(fù)雜的搜索空間

 from hyperopt import hp
    space = hp.choice('classifier_type', [
        {
        'type': 'naive_bayes',
        },
        {
        'type': 'svm',
        'C': hp.lognormal('svm_C', 0, 1),
        'kernel': hp.choice('svm_kernel', [
            {'ktype': 'linear'},
            {'ktype': 'RBF', 'width': hp.lognormal('svm_rbf_width', 0, 1)},
            ]),
        },
        {
        'type': 'dtree',
        'criterion': hp.choice('dtree_criterion', ['gini', 'entropy']),
        'max_depth': hp.choice('dtree_max_depth',
            [None, hp.qlognormal('dtree_max_depth_int', 3, 1, 1)]),
        'min_samples_split': hp.qlognormal('dtree_min_samples_split', 2, 1, 1),
        },
        ])

搜索算法

algo指定搜索算法,目前支持以下算法:
①隨機(jī)搜索(hyperopt.rand.suggest)
②模擬退火(hyperopt.anneal.suggest)
③TPE算法(hyperopt.tpe.suggest微饥,算法全稱為Tree-structured Parzen Estimator Approach)

其他有用的參數(shù)和方法

Trials

Trials只是用來記錄每次eval的時候逗扒,具體使用了什么參數(shù)以及相關(guān)的返回值。這時候欠橘,fn的返回值變?yōu)閐ict矩肩,除了loss,還有一個status肃续。Trials對象將數(shù)據(jù)存儲為一個BSON對象黍檩,可以利用MongoDB做分布式運(yùn)算。

from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
 
fspace = {
    'x': hp.uniform('x', -5, 5)
}
 
def f(params):
    x = params['x']
    val = x**2
    return {'loss': val, 'status': STATUS_OK}
 
trials = Trials()
best = fmin(fn=f, space=fspace, algo=tpe.suggest, max_evals=50, trials=trials)
 
print('best:', best)
 
print('trials:')
for trial in trials.trials[:2]:
    print(trial)

對于STATUS_OK的返回痹升,會統(tǒng)計它的loss值建炫,而對于STATUS_FAIL的返回,則會忽略疼蛾。

可以通過這里面的值,把一些變量與loss的點(diǎn)繪圖艺配,來看匹配度察郁⊙苌鳎或者tid與變量繪圖,看它搜索的位置收斂(非數(shù)學(xué)意義上的收斂)情況皮钠。
trials有這幾種:

  • trials.trials - a list of dictionaries representing everything about the search
  • trials.results - a list of dictionaries returned by ‘objective’ during the search
  • trials.losses() - a list of losses (float for each ‘ok’ trial) trials.statuses() - a list of status strings

通過交叉驗(yàn)證的方式確定最佳的參數(shù)

cross_val_score
對衡量的estimator稳捆,它默認(rèn)返回的是一個array,包含K folder情況下的各次的評分麦轰,一般采用mean()乔夯。 需要確定這個estimator默認(rèn)的 scoring 是什么,它的值是越大越匹配還是越小越匹配款侵。如果自己指定了scoring末荐,一定要確定這個scoring值的意義,切記切記新锈! 而如果用戶不指定甲脏,一般對于Classification類的estimator,使用accuracy妹笆,它是越大越好块请,那么,hyperopt里面的loss的值就應(yīng)該是對這個值取負(fù)數(shù)拳缠,因?yàn)閔yperopt通過loss最小取找最佳匹配墩新。 可以把feature的normalize或者scale作為一個choice,然后看看是否更合適窟坐。如果更合適海渊,best里面就會顯示 normalize 為1。

from sklearn.datasets import load_iris
from sklearn import datasets
from sklearn.preprocessing import normalize, scale
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
 
 
iris = load_iris()
X = iris.data
y = iris.target
 
def hyperopt_train_test(params):
    X_ = X[:]
 
    # 因?yàn)橄旅娴膬蓚€參數(shù)都不屬于KNeighborsClassifier支持的參數(shù)狸涌,故使用后直接刪除
    if 'normalize' in params:
        if params['normalize'] == 1:
            X_ = normalize(X_)
            del params['normalize']
 
    if 'scale' in params:
        if params['scale'] == 1:
            X_ = scale(X_)
            del params['scale']
 
    clf = KNeighborsClassifier(**params)
    return cross_val_score(clf, X_, y).mean()
 
space4knn = {
    'n_neighbors': hp.choice('n_neighbors', range(1,50)),
    'scale': hp.choice('scale', [0, 1]),  # 必須是choice切省,不要用quniform
    'normalize': hp.choice('normalize', [0, 1])
}
 
def f(params):
    acc = hyperopt_train_test(params)
    return {'loss': -acc, 'status': STATUS_OK} #注意這里的負(fù)號
 
trials = Trials()
best = fmin(f, space4knn, algo=tpe.suggest, max_evals=100, trials=trials)
print best

參考的網(wǎng)頁們:

hyperopt的gitlab主頁
hyperopt的中文翻譯文檔主頁
調(diào)參神器:Hyperopt
Hyperopt的使用注意點(diǎn)
python機(jī)器學(xué)習(xí)模型選擇&調(diào)參工具Hyperopt-sklearn(1)——綜述&分類問題
Hyperopt中文文檔:FMin

使用sklearn的數(shù)據(jù)進(jìn)行一次測試

#coding:utf-8
from hyperopt import fmin, tpe, hp, rand
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn import svm
from sklearn import datasets

# SVM的三個超參數(shù):C為懲罰因子,kernel為核函數(shù)類型帕胆,gamma為核函數(shù)的額外參數(shù)(對于不同類型的核函數(shù)有不同的含義)
# 有別于傳統(tǒng)的網(wǎng)格搜索(GridSearch)朝捆,這里只需要給出最優(yōu)參數(shù)的概率分布即可,而不需要按照步長把具體的值給一個個枚舉出來
parameter_space_svc ={
    # loguniform表示該參數(shù)取對數(shù)后符合均勻分布
    'C':hp.loguniform("C", np.log(1), np.log(100)),
    'kernel':hp.choice('kernel',['rbf','poly']),
    'gamma': hp.loguniform("gamma", np.log(0.001), np.log(0.1)),
}

# 鳶尾花卉數(shù)據(jù)集懒豹,是一類多重變量分析的數(shù)據(jù)集
# 通過花萼長度芙盘,花萼寬度,花瓣長度脸秽,花瓣寬度4個屬性預(yù)測鳶尾花卉屬于(Setosa儒老,Versicolour,Virginica)三個種類中的哪一類
iris = datasets.load_digits()

#--------------------劃分訓(xùn)練集和測試集--------------------
train_data = iris.data[0:1300]
train_target = iris.target[0:1300]
test_data = iris.data[1300:-1]
test_target = iris.target[1300:-1]
#-----------------------------------------------------------

# 計數(shù)器记餐,每一次參數(shù)組合的枚舉都會使它加1
count = 0

def function(args):
    print(args)

    # **可以把dict轉(zhuǎn)換為關(guān)鍵字參數(shù)驮樊,可以大大簡化復(fù)雜的函數(shù)調(diào)用
    clf = svm.SVC(**args)

    # 訓(xùn)練模型
    clf.fit(train_data,train_target)

    # 預(yù)測測試集
    prediction = clf.predict(test_data)

    global count
    count = count + 1
    score = accuracy_score(test_target,prediction)
    print("第%s次,測試集正確率為:" % str(count),score)

    # 由于hyperopt僅提供fmin接口,因此如果要求最大值囚衔,則需要取相反數(shù)
    return -score

# algo指定搜索算法挖腰,目前支持以下算法:
# ①隨機(jī)搜索(hyperopt.rand.suggest)
# ②模擬退火(hyperopt.anneal.suggest)
# ③TPE算法(hyperopt.tpe.suggest,算法全稱為Tree-structured Parzen Estimator Approach)
# max_evals指定枚舉次數(shù)上限练湿,即使第max_evals次枚舉仍未能確定全局最優(yōu)解猴仑,也要結(jié)束搜索,返回目前搜索到的最優(yōu)解
best = fmin(function, parameter_space_svc, algo=tpe.suggest, max_evals=100)

# best["kernel"]返回的是數(shù)組下標(biāo)肥哎,因此需要把它還原回來
kernel_list = ['rbf','poly']
best["kernel"] = kernel_list[best["kernel"]]

print("最佳參數(shù)為:",best)

clf = svm.SVC(**best)
print(clf)

輸出結(jié)果如下:

{'gamma': 0.0010051585652497248, 'kernel': 'poly', 'C': 29.551164584073586}
第1次辽俗,測試集正確率為: 0.959677419355
{'gamma': 0.006498482991283678, 'kernel': 'rbf', 'C': 6.626826808981864}
第2次,測試集正確率為: 0.834677419355
{'gamma': 0.008192671915044216, 'kernel': 'poly', 'C': 34.48947180442318}
第3次篡诽,測試集正確率為: 0.959677419355
{'gamma': 0.001359874432712413, 'kernel': 'rbf', 'C': 1.6402360233244775}
第98次崖飘,測試集正確率為: 0.971774193548
{'gamma': 0.0029328466160223813, 'kernel': 'poly', 'C': 1.6328276445108112}
第99次,測試集正確率為: 0.959677419355
{'gamma': 0.0015786919481979775, 'kernel': 'rbf', 'C': 4.669133703622153}
第100次霞捡,測試集正確率為: 0.969758064516
最佳參數(shù)為: {'gamma': 0.00101162002595069, 'kernel': 'rbf', 'C': 21.12514792460218}
SVC(C=21.12514792460218, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape=None, degree=3, gamma=0.00101162002595069,
  kernel='rbf', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坐漏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子碧信,更是在濱河造成了極大的恐慌赊琳,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砰碴,死亡現(xiàn)場離奇詭異躏筏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)呈枉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門趁尼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人猖辫,你說我怎么就攤上這事酥泞。” “怎么了啃憎?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵芝囤,是天一觀的道長。 經(jīng)常有香客問我辛萍,道長悯姊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任贩毕,我火速辦了婚禮悯许,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辉阶。我一直安慰自己先壕,他們只是感情好瘩扼,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著启上,像睡著了一般邢隧。 火紅的嫁衣襯著肌膚如雪店印。 梳的紋絲不亂的頭發(fā)上冈在,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音按摘,去河邊找鬼包券。 笑死,一個胖子當(dāng)著我的面吹牛炫贤,可吹牛的內(nèi)容都是我干的溅固。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼兰珍,長吁一口氣:“原來是場噩夢啊……” “哼侍郭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掠河,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亮元,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后唠摹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爆捞,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年勾拉,在試婚紗的時候發(fā)現(xiàn)自己被綠了煮甥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡藕赞,死狀恐怖成肘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斧蜕,我是刑警寧澤双霍,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站惩激,受9級特大地震影響店煞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜风钻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一顷蟀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骡技,春花似錦鸣个、人聲如沸羞反。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昼窗。三九已至,卻和暖如春涛舍,著一層夾襖步出監(jiān)牢的瞬間澄惊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工富雅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掸驱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓没佑,卻偏偏與公主長得像毕贼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛤奢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359