特征工程是機器學習當中很重要的部分,可以幫助我們設計、創建新特征,以便模型從中提取重要相關性。本文將記錄並持續更新相關特征工程的工具包介紹,包括自動模型選擇和超參數調優等各方面。
· Featuretools
Featuretools 是一個開源的Python 庫,用於自動化特征工程。自動特征工程能夠縮減時間成本,構建更優秀的預測模型,生成更有意義的特征,還能防止數據泄漏(data leakage)。
目標任務:從數據表格集中獲取所有的數據信息並整合到一張表中,再創建特征。
解決方案:采用深度特征合成方法(DFS),通過調用一個函數來構建數千個特征。
# Deep feature synthesis feature_matrix, features = ft.dfs(entityset=es, target_entity='clients', agg_primitives = agg_primitives, trans_primitives = trans_primitives)
其中ft 代表導入的 featuretools 庫。
經測試,自動生成特征在數量和效率上均比手動特征工程性能提高很多。
此外,Featuretools還有以下優勢:
· 構建特征時自動地考慮時間
· 可調用RF模型自動獲取特征重要性
詳細內容請見:
· 隨機森林超參數優化- RandomSearch和GridSearch
rf中的超參數主要為森林中的決策樹的數量(n_estimators) 以及每個樹在分割節點時考慮的特征的數量(max_features)。 並且超參數優化的標准程序是通過交叉驗證來解決過度擬合問題。
1)Random Search with Cross Validation
通常,對於最佳超參數的范圍比較模糊,因此縮小搜索范圍的最佳方法是為每個超參數評估各種值。使用Scikit-Learn的RandomizedSearchCV方法,我們可以定義超參數范圍的網格,並從網格中隨機抽樣,使用每個值組合執行K-Fold CV。
Step 1: 執行前,先獲取目前模型的參數
rf = RandomForestRegressor(random_state = 42) from pprint import pprint # Look at parameters used by our current forest print('Parameters currently in use:\n') pprint(rf.get_params())
Step 2:為了使用RandomizedSearchCV,我們首先需要創建一個參數網格在擬合過程中進行采樣:
from sklearn.model_selection import RandomizedSearchCV
# Number of trees in random forest
n_estimators = [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)]
# Number of features to consider at every split
max_features = ['auto', 'sqrt']
# Maximum number of levels in tree
max_depth = [int(x) for x in np.linspace(10, 110, num = 11)]
max_depth.append(None)
# Minimum number of samples required to split a node
min_samples_split = [2, 5, 10]
# Minimum number of samples required at each leaf node
min_samples_leaf = [1, 2, 4]
# Method of selecting samples for training each tree
bootstrap = [True, False]
# Create the random grid
random_grid = {'n_estimators': n_estimators,
'max_features': max_features,
'max_depth': max_depth,
'min_samples_split': min_samples_split,
'min_samples_leaf': min_samples_leaf,
'bootstrap': bootstrap}
pprint(random_grid)
Step 3:訓練
# 使用隨機網格搜索最佳超參數 # 首先創建要調優的基本模型 rf = RandomForestRegressor() # 隨機搜索參數,使用3倍交叉驗證 # 采用100種不同的組合進行搜索,並使用所有可用的核心 rf_random = RandomizedSearchCV(estimator = rf, param_distributions = random_grid, n_iter = 100, cv = 3, verbose=2, random_state=42, n_jobs = -1) # Fit模型 rf_random.fit(train_features, train_labels)
Step 4:得到最佳參數
rf_random.best_params_
Step 5:將優化后的參數進行訓練和比較驗證。
2) GridSearch
隨機搜索允許我們縮小每個超參數的范圍。現在我們知道在哪里集中搜索,我們可以明確指定要嘗試的每個設置組合。GridSearchCV可以評估我們定義的所有組合。
Step 1:要使用網格搜索,我們根據隨機搜索提供的最佳值創建另一個網格
from sklearn.model_selection import GridSearchCV # Create the parameter grid based on the results of random search param_grid = { 'bootstrap': [True], 'max_depth': [80, 90, 100, 110], 'max_features': [2, 3], 'min_samples_leaf': [3, 4, 5], 'min_samples_split': [8, 10, 12], 'n_estimators': [100, 200, 300, 1000] } # Create a based model rf = RandomForestRegressor() # Instantiate the grid search model grid_search = GridSearchCV(estimator = rf, param_grid = param_grid, cv = 3, n_jobs = -1, verbose = 2)
Step 2: Fit模型並重新訓練和比較驗證
grid_search.fit(train_features, train_labels) grid_search.best_params_ best_grid = grid_search.best_estimator_ grid_accuracy = evaluate(best_grid, test_features, test_labels)
當性能的小幅下降表明我們已經達到了超參數調整的收益遞減。
本部分代碼請見:
詳細內容請見:https://towardsdatascience.com/hyperparameter-tuning-the-random-forest-in-python-using-scikit-learn-28d2aa77dd74
· Hyperopt自動化超參數調優- 貝葉斯優化
網格搜索和隨機搜索則對ml模型超參數的優化能取得不錯的效果,但是需要大量運行時間去評估搜索空間中並不太可能找到最優點的區域。因此越來越多的的超參數調優過程都是通過自動化的方法完成的,它們旨在使用帶有策略的啟發式搜索(informed search)在更短的時間內找到最優超參數。
貝葉斯優化是一種基於模型的用於尋找函數最小值的方法。近段時間以來,貝葉斯優化開始被用於機器學習超參數調優,結果表明,該方法在測試集上的表現更加優異,並且需要的迭代次數小於隨機搜索。
Python 環境下有一些貝葉斯優化程序庫,它們目標函數的代理算法有所區別。本部分主要介紹「Hyperopt」庫,它使用樹形 Parzen 評估器(TPE,
https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf)作為搜索算法,其他的 Python 庫還包含「Spearmint」(高斯過程代理)和「SMAC」(隨即森林回歸)。
貝葉斯優化問題有四個組成部分:
1)目標函數:我們想要最小化的對象,這里指帶超參數的機器學習模型的驗證誤差
2)域空間:待搜索的超參數值
3)優化算法:構造代理模型和選擇接下來要評估的超參數值的方法
4)結果的歷史數據:存儲下來的目標函數評估結果,包含超參數和驗證損失
通過以上四個步驟,我們可以對任意實值函數進行優化(找到最小值)。
詳解:
1)目標函數
模型訓練目的是最小化目標函數,所以輸出為需要最小化的實值——交叉驗證損失。Hyperopt 將目標函數作為黑盒處理,因為這個庫只關心輸入和輸出是什么。為了找到使損失最小的輸入值
偽代碼:
def objective(hyperparameters): """Returns validation score from hyperparameters""" model = Classifier(hyperparameters) validation_loss = cross_validation(model, training_data) return validation_loss
實際GBM完整的目標函數
import lightgbm as lgb from hyperopt import STATUS_OK N_FOLDS = 10 # Create the dataset train_set = lgb.Dataset(train_features, train_labels) def objective(params, n_folds = N_FOLDS): """Objective function for Gradient Boosting Machine Hyperparameter Tuning""" # Perform n_fold cross validation with hyperparameters # Use early stopping and evalute based on ROC AUC cv_results = lgb.cv(params, train_set, nfold = n_folds, num_boost_round = 10000, early_stopping_rounds = 100, metrics = 'auc', seed = 50) #此部分為核心代碼, # Extract the best score best_score = max(cv_results['auc-mean']) # Loss must be minimized loss = 1 - best_score # Dictionary with information for evaluation return {'loss': loss, 'params': params, 'status': STATUS_OK}
2)域空間
貝葉斯優化中,域空間對每個超參數來說是一個概率分布而不是離散的值。因為很難確定不同數據集之間的最佳模型設定區間,此處主要采用貝葉斯算法進行推理。
此外,模型中有些參數是不需要調優的。以GBM為例,除了n_estimator之外,還有10個左右的參數需要調整。因此我們采用不同的分布來定義每個參數的域空間
from hyperopt import hp # Define the search space space = { 'class_weight': hp.choice('class_weight', [None, 'balanced']), 'boosting_type': hp.choice('boosting_type', [{'boosting_type': 'gbdt', 'subsample': hp.uniform('gdbt_subsample', 0.5, 1)}, {'boosting_type': 'dart', 'subsample': hp.uniform('dart_subsample', 0.5, 1)}, {'boosting_type': 'goss'}]), 'num_leaves': hp.quniform('num_leaves', 30, 150, 1), 'learning_rate': hp.loguniform('learning_rate', np.log(0.01), np.log(0.2)), 'subsample_for_bin': hp.quniform('subsample_for_bin', 20000, 300000, 20000), 'min_child_samples': hp.quniform('min_child_samples', 20, 500, 5), 'reg_alpha': hp.uniform('reg_alpha', 0.0, 1.0), 'reg_lambda': hp.uniform('reg_lambda', 0.0, 1.0), 'colsample_bytree': hp.uniform('colsample_by_tree', 0.6, 1.0) }
不同分布名稱含義:
choice:類別變量
quniform:離散均勻分布(在整數空間上均勻分布)
uniform:連續均勻分布(在浮點數空間上均勻分布)
loguniform:連續對數均勻分布(在浮點數空間中的對數尺度上均勻分布)
定義與空間后,可以選擇一個樣本來查看典型樣本形式
# Sample from the full space example = sample(space) # Dictionary get method with default subsample = example['boosting_type'].get('subsample', 1.0) # Assign top-level keys example['boosting_type'] = example['boosting_type']['boosting_type'] example['subsample'] = subsample example
3)優化算法
盡管從概念上來說,這是貝葉斯優化最難的一部分,但在 Hyperopt 中創建優化算法只需一行代碼。使用樹形 Parzen 評估器(Tree Parzen Estimation,以下簡稱 TPE)的代碼如下:
from hyperopt import tpe # Algorithm tpe_algorithm = tpe.suggest
4)結果歷史數據
想知道背后的發展進程,可以使用「Trials」對象,它將存儲基本的訓練信息,還可以使用目標函數返回的字典(包含損失「loss」和參數「params」)
from hyperopt import Trials # Trials object to track progress bayes_trials = Trials()
或者通過csv記錄迭代過程
5)優化算法
from hyperopt import fmin MAX_EVALS = 500 # Optimize best = fmin(fn = objective, space = space, algo = tpe.suggest, max_evals = MAX_EVALS, trials = bayes_trials)
此部分代碼請見:
詳細內容參考:
持續更新...