集成方法:產生改進機器學習結果的優雅技術

已發表: 2022-03-11

集成方法是創建多個模型然後將它們組合以產生改進結果的技術。 集成方法通常會產生比單個模型更準確的解決方案。 在許多機器學習競賽中都是這種情況,獲勝的解決方案使用了集成方法。 在流行的 Netflix 競賽中,獲勝者使用集成方法來實現強大的協同過濾算法。 另一個例子是 KDD 2009,獲勝者也使用了集成方法。 您還可以在 Kaggle 比賽中找到使用這些方法的獲勝者,例如這裡是對 CrowdFlower 比賽獲勝者的採訪。

在繼續閱讀本文之前,了解一些術語非常重要。 在整篇文章中,我使用術語“模型”來描述使用數據訓練的算法的輸出。 然後使用該模型進行預測。 該算法可以是任何機器學習算法,例如邏輯回歸、決策樹等。這些模型在用作集成方法的輸入時,稱為“基礎模型”。

在這篇博文中,我將介紹用於分類的集成方法,並描述一些廣為人知的集成方法:投票、堆疊、裝袋和提升。

基於投票和平均的集成方法

投票和平均是兩種最簡單的集成方法。 它們都易於理解和實施。 投票用於分類,平均用於回歸。

基於投票和平均的集成方法

在這兩種方法中,第一步是使用一些訓練數據集創建多個分類/回歸模型。 每個基本模型可以使用相同訓練數據集和相同算法的不同拆分,或使用具有不同算法的相同數據集,或任何其他方法來創建。 以下 Python 式偽代碼顯示了使用不同算法的相同訓練數據集。

 train = load_csv("train.csv") target = train["target"] train = train.drop("target") test = load_csv("test.csv") algorithms = [logistic_regression, decision_tree_classification, ...] #for classification algorithms = [linear_regression, decision_tree_regressor, ...] #for regression predictions = matrix(row_length=len(target), column_length=len(algorithms)) for i,algorithm in enumerate(algorithms): predictions[,i] = algorithm.fit(train, target).predict(test)

根據上面的偽代碼,我們為每個模型創建了預測並將它們保存在一個稱為預測的矩陣中,其中每一列都包含來自一個模型的預測。

多數投票

每個模型對每個測試實例進行預測(投票),最終輸出預測是獲得一半以上投票的預測。 如果沒有一個預測得到超過一半的選票,我們可以說集成方法無法對這個實例做出穩定的預測。 儘管這是一種廣泛使用的技術,但您可以嘗試將投票最多的預測(即使不到一半的投票)作為最終預測。 在某些文章中,您可能會看到這種方法被稱為“複數投票”。

加權投票

與多數投票不同,每個模型都擁有相同的權利,我們可以增加一個或多個模型的重要性。 在加權投票中,您多次計算更好模型的預測。 找到一組合理的權重取決於您。

簡單平均

在簡單平均方法中,對於測試數據集的每個實例,計算平均預測值。 這種方法通常會減少過擬合併創建更平滑的回歸模型。 以下偽代碼顯示了這種簡單的平均方法:

 final_predictions = [] for row_number in len(predictions): final_predictions.append( mean(prediction[row_number, ]) )

加權平均

加權平均是簡單平均的略微修改版本,其中每個模型的預測乘以權重,然後計算它們的平均值。 以下偽代碼代碼顯示了加權平均:

 weights = [..., ..., ...] #length is equal to len(algorithms) final_predictions = [] for row_number in len(predictions): final_predictions.append( mean(prediction[row_number, ]*weights) )

堆疊多個機器學習模型

堆疊,也稱為堆疊泛化,是一種集成方法,其中模型使用另一種機器學習算法進行組合。 基本思想是用訓練數據集訓練機器學習算法,然後用這些模型生成一個新的數據集。 然後這個新數據集被用作組合機器學習算法的輸入。

堆棧過程的偽代碼總結如下:

 base_algorithms = [logistic_regression, decision_tree_classification, ...] #for classification stacking_train_dataset = matrix(row_length=len(target), column_length=len(algorithms)) stacking_test_dataset = matrix(row_length=len(test), column_length=len(algorithms)) for i,base_algorithm in enumerate(base_algorithms): stacking_train_dataset[,i] = base_algorithm.fit(train, target).predict(train) stacking_test_dataset[,i] = base_algorithm.predict(test) final_predictions = combiner_algorithm.fit(stacking_train_dataset, target).predict(stacking_test_dataset)

正如您在上面的偽代碼中看到的,組合器算法的訓練數據集是使用基本算法的輸出生成的。 在偽代碼中,使用訓練數據集生成基本算法,然後再次使用相同的數據集進行預測。 但正如我們所知,在現實世界中,我們不會使用相同的訓練數據集進行預測,因此為了克服這個問題,您可能會看到一些堆疊的實現,其中訓練數據集被拆分。 下面你可以看到一個偽代碼,其中訓練數據集在訓練基本算法之前被分割:

 base_algorithms = [logistic_regression, decision_tree_classification, ...] #for classification stacking_train_dataset = matrix(row_length=len(target), column_length=len(algorithms)) stacking_test_dataset = matrix(row_length=len(test), column_length=len(algorithms)) for i,base_algorithm in enumerate(base_algorithms): for trainix, testix in split(train, k=10): #you may use sklearn.cross_validation.KFold of sklearn library stacking_train_dataset[testcv,i] = base_algorithm.fit(train[trainix], target[trainix]).predict(train[testix]) stacking_test_dataset[,i] = base_algorithm.fit(train).predict(test) final_predictions = combiner_algorithm.fit(stacking_train_dataset, target).predict(stacking_test_dataset)

引導聚合

Bootstrap Aggregating(也稱為“Bagging”)這個名稱總結了該策略的關鍵要素。 在 bagging 算法中,第一步涉及創建多個模型。 這些模型是使用與數據集的隨機子樣本相同的算法生成的,這些子樣本是使用自舉抽樣方法從原始數據集中隨機抽取的。 在 bootstrap 抽樣中,一些原始示例出現了不止一次,並且一些原始示例不存在於示例中。 如果要創建具有 m 個元素的子數據集,則應從原始數據集中隨機選擇一個元素 m 次。 如果目標是生成 n 個數據集,則執行此步驟 n 次。

引導聚合

最後,我們有 n 個數據集,每個數據集中的元素數為 m。 以下 Python 風格的偽代碼顯示引導採樣:

 def bootstrap_sample(original_dataset, m): sub_dataset = [] for i in range(m): sub_dataset.append( random_one_element(original_dataset) ) return sub_dataset

bagging 的第二步是聚合生成的模型。 為此目的使用眾所周知的方法,例如投票和平均。

整個偽代碼如下所示:

 def bagging(n, m, base_algorithm, train_dataset, target, test_dataset): predictions = matrix(row_length=len(target), column_length=n) for i in range(n): sub_dataset = bootstrap_sample(train_dataset, m) predictions[,i] = base_algorithm.fit(original_dataset, target).predict(test_dataset) final_predictions = voting(predictions) # for classification final_predictions = averaging(predictions) # for regression return final_predictions

在 bagging 中,每個子樣本可以相互獨立地生成。 所以生成和訓練可以並行進行。

您還可以在某些算法中找到 bagging 策略的實現。 例如,隨機森林算法使用 bagging 技術,但存在一些差異。 隨機森林使用隨機特徵選擇,其基本算法是決策樹算法。

相關:深度學習教程:從感知器到深度網絡

Boosting:將弱模型轉換為強模型

術語“提升”用於描述能夠將弱模型轉換為強模型的一系列算法。 如果模型的錯誤率很高,則該模型很弱,但性能不是隨機的(導致二元分類的錯誤率為 0.5)。 Boosting 通過使用相同的數據集訓練每個模型,但其中實例的權重會根據上次預測的誤差進行調整,從而逐步構建一個集成。 主要思想是迫使模型專注於困難的實例。 與 bagging 不同,boosting 是一種順序方法,因此您不能在這裡使用並行操作。

boosting算法的一般過程定義如下:

 def adjust_dataset(_train, errors): #create a new dataset by using the hardest instances ix = get_highest_errors_index(train) return concat(_train[ix], random_select(train)) models = [] _train = random_select(train) for i in range(n): #n rounds model = base_algorithm.fit(_train) predictions = model.predict(_train) models.append(model) errors = calculate_error(predictions) _train = adjust_dataset(_train, errors) final_predictions = combine(models, test)

adjust_dataset 函數返回一個包含最難實例的新數據集,然後可用於強制基礎算法從中學習。

Adaboost 是一種廣為人知的算法,它是一種提升方法。 Adaboost 的創始人因其工作獲得了哥德爾獎。 大多數情況下,決策樹算法被首選作為 Adaboost 的基本算法,在 sklearn 庫中,Adaboost 的默認基本算法是決策樹(AdaBoostRegressor 和 AdaBoostClassifier)。 正如我們在上一段中所討論的,同樣的增量方法適用於 Adaboost。 在 AdaBoost 算法的每一步收集的關於每個訓練樣本的“硬度”的信息被輸入到模型中。 “調整數據集”步驟與上述步驟不同​​,“組合模型”步驟是通過使用加權投票計算的。

結論

儘管集成方法可以通過設計複雜的算法並產生高精度的結果來幫助您贏得機器學習競賽,但在可解釋性更重要的行業中,它通常不是首選。 儘管如此,這些方法的有效性是不可否認的,並且它們在適當的應用中的好處是巨大的。 在醫療保健等領域,即使機器學習算法的準確性得到最小程度的改進,也可能是真正有價值的東西。

有關的:
  • 機器學習理論及其應用簡介:帶有示例的可視化教程
  • 機器和信任:如何減輕 AI 偏見