摘要:在本教程中,您將了解如何在中從頭開始實現隨機森林算法。如何將隨機森林算法應用于預測建模問題。如何在中從頭開始實現隨機森林圖片來自,保留部分權利。這被稱為隨機森林算法。如何更新決策樹的創建以適應隨機森林過程。
歡迎大家前往云+社區,獲取更多騰訊海量技術實踐干貨哦~
決策樹可能會受到高度變異的影響,使得結果對所使用的特定測試數據而言變得脆弱。
根據您的測試數據樣本構建多個模型(稱為套袋)可以減少這種差異,但是樹本身是高度相關的。
隨機森林是套袋(方法)的延伸,除了基于多個測試數據樣本構建樹木之外,它還限制了可用于構建樹木的特征,使得樹木間具有差異。這反過來可以提升算法的表現。
在本教程中,您將了解如何在Python中從頭開始實現隨機森林算法。
完成本教程后,您將知道:
套袋決策樹和隨機森林算法的區別。
如何構造更多方差的袋裝決策樹。
如何將隨機森林算法應用于預測建模問題。
讓我們開始吧。
2017年1月更新:將cross_validation_split()中fold_size的計算更改為始終為整數。修復了Python 3的問題。
2017年2月更新:修復了build_tree中的錯誤。
2017年8月更新:修正了基尼計算中的一個錯誤,增加了群組大小(基于邁克爾!)。
如何在Python中從頭開始實現隨機森林 圖片來自 InspireFate Photography,保留部分權利。
描述本節簡要介紹本教程中使用的隨機森林算法和Sonar數據集。
隨機森林算法決策樹涉及從數據集中(利用)貪婪選擇選取最佳分割點過程中的每一步。
如果不精簡(該算法),此算法容易使決策樹出現高方差。這種高方差(結果)可以通過創建包含測試數據集中(多個)不同的實例(問題的不同觀點)的多重樹,接著將實例所有的可能結果結合,這種方法簡稱為bootstrap聚合或套袋。
套袋的局限性在于,它使用相同的貪婪算法來創建每棵樹,這意味著在每棵樹中可能會選擇相同或非常相似的分割點,使得不同的樹非常相似(樹將被關聯)。這反過來又使他們的預測相似,從而縮減了最初尋求的差異。
我們可以通過貪婪算法在創建樹時在每個分割點評估的特征(行)來限制決策樹不同。這被稱為隨機森林算法。
像裝袋一樣,測試數據集的多個樣本在被采集后,接著在每個樣本上訓練不同的樹。不同之處在于在每一點上,拆分是在數據中進行并添加到樹中的,且只考慮固定的屬性子集。
對于分類問題,我們將在本教程中討論的問題的類型——分割中輸入特點數的平方根值對為分割操作考慮的屬性個數的限制。
num_features_for_split = sqrt(total_input_features)
這一小變化的結果是樹之間變得更加不同(不關聯),作為結果會有更加多樣化的預測,這樣的結果往往好于一個多帶帶的樹或者多帶帶套袋得到的結果。
聲納數據集我們將在本教程中使用的數據集是Sonar數據集。
這是一個描述聲納聲音從不同曲面反彈后返回(數據)的數據集。輸入的60個變量是聲吶從不同角度返回的力度值。這是一個二元分類問題,需要一個模型來區分金屬圓柱中的巖石。這里有208個觀察對象。
這是一個很好理解的數據集。所有變量都是連續的且范圍一般是0到1。輸出變量是“Mine”字符串中的“M”和“rock”中的“R”,需要轉換為整數1和0。
通過預測在數據集(“M”或“mines”)中觀測數最多的類,零規則算法可以達到53%的準確度。
您可以在UCI Machine Learning repository了解關于此數據集的更多信息。
下載免費的數據集,并將其放置在工作目錄中,文件名為sonar.all-data.csv。
教程本教程分為2個步驟。
計算分割。
聲納數據集案例研究。
這些步驟為您需要將隨機森林算法應用于自己的預測建模問題奠定了基礎。
1.計算分割在決策樹中,通過利用最低成本找到指定屬性和該屬性的值方法來確定分割點。
對于分類問題,這個成本函數通常是基尼指數,它計算分割點創建的數據組的純度。基尼指數為0是完美純度,其中在兩類分類問題的情況下,將類別值完全分成兩組。
在決策樹中找到最佳分割點涉及到為每個輸入的變量評估訓練數據集中每個值的成本。
對于裝袋和隨機森林,這個程序是在測試數據集的樣本上執行的,并且是可替換的。更換取樣意味著同一行(數據)會不止一次的被選擇并將其添加到取樣中。
我們可以優化隨機森林的這個程序。我們可以創建一個輸入屬性樣本來考慮,而不是在搜索中枚舉輸入屬性的所有值。
這個輸入屬性的樣本可以隨機選擇而不需要替換,這意味著每個輸入屬性在查找具有最低成本的分割點的過程中只被考慮一次。
下面是實現此過程的函數名稱get_split()。它將數據集和固定數量的輸入要素作為輸入參數進行評估,此數據集可能是實際測試數據集的一個樣本。
helper函數test_split()用于通過候選分割點拆分數據集,gini_index()用于根據創建的行組來計算給定拆分的花費。
我們可以看到,通過隨機選擇特征索引并將其添加到列表(稱為特征)來創建特征列表,然后枚舉該特征列表并且將測試數據集中的特定值評估作為分割點。
# Select the best split point for a dataset def get_split(dataset, n_features): class_values = list(set(row[-1] for row in dataset)) b_index, b_value, b_score, b_groups = 999, 999, 999, None features = list() while len(features) < n_features: index = randrange(len(dataset[0])-1) if index not in features: features.append(index) for index in features: for row in dataset: groups = test_split(index, row[index], dataset) gini = gini_index(groups, class_values) if gini < b_score: b_index, b_value, b_score, b_groups = index, row[index], gini, groups return {"index":b_index, "value":b_value, "groups":b_groups}
現在我們知道如何修改決策樹算法以便與隨機森林算法一起使用,我們可以將它與一個bagging實現一起使用,并將其應用于現實生活中的數據集。
2.聲納數據集案例研究在本節中,我們將把隨機森林算法應用到聲納數據集。
該示例假定數據集的CSV副本位于當前工作目錄中,文件名為sonar.all-data.csv。
首先加載數據集,將字符串值轉換為數字,并將輸出列從字符串轉換為0和1的整數值。這可以通過使用幫助器函數load_csv(),str_column_to_float()和str_column_to_int()來加載和預備數據集。
我們將使用k-fold交叉驗證來估計未知數據的學習模型的性能。這意味著我們將構建和評估k個模型,并將性能估計為平均模型誤差。分類準確性將用于評估每個模型。這些工具或是算法在cross_validation_split(),accuracy_metric()和evaluate_algorithm()輔助函數中提供。
我們也將使用適合套袋包括輔助功能分類和回歸樹(CART)算法的實現)test_split(拆分數據集分成組,gini_index()來評估分割點,我們修改get_split()函數中討論在前一步中,to_terminal(),split()和build_tree()用于創建單個決策樹,預測()使用決策樹進行預測,subsample()創建訓練數據集的子采樣,以及bagging_predict()用決策樹列表進行預測。
開發了一個新的函數名稱random_forest(),首先根據訓練數據集的子樣本創建一個決策樹列表,然后使用它們進行預測。
正如我們上面所說的,隨機森林和袋裝決策樹之間的關鍵區別是對樹的創建方式中的一個小的改變,這里是在get_split()函數中。
完整的例子如下所示。
# Random Forest Algorithm on Sonar Dataset from random import seed from random import randrange from csv import reade from math import sqrt # Load a CSV file def load_csv(filename): dataset = list() with open(filename, "r") as file: csv_reader = reader(file) for row in csv_reader: if not row: continue dataset.append(row) return dataset # Convert string column to float def str_column_to_float(dataset, column): for row in dataset: row[column] = float(row[column].strip()) # Convert string column to intege def str_column_to_int(dataset, column): class_values = [row[column] for row in dataset] unique = set(class_values) lookup = dict() for i, value in enumerate(unique): lookup[value] = i for row in dataset: row[column] = lookup[row[column]] return lookup # Split a dataset into k folds def cross_validation_split(dataset, n_folds): dataset_split = list() dataset_copy = list(dataset) fold_size = int(len(dataset) / n_folds) for i in range(n_folds): fold = list() while len(fold) < fold_size: index = randrange(len(dataset_copy)) fold.append(dataset_copy.pop(index)) dataset_split.append(fold) return dataset_split # Calculate accuracy percentage def accuracy_metric(actual, predicted): correct = 0 for i in range(len(actual)): if actual[i] == predicted[i]: correct += 1 return correct / float(len(actual)) * 100.0 # Evaluate an algorithm using a cross validation split def evaluate_algorithm(dataset, algorithm, n_folds, *args): folds = cross_validation_split(dataset, n_folds) scores = list() for fold in folds: train_set = list(folds) train_set.remove(fold) train_set = sum(train_set, []) test_set = list() for row in fold: row_copy = list(row) test_set.append(row_copy) row_copy[-1] = None predicted = algorithm(train_set, test_set, *args) actual = [row[-1] for row in fold] accuracy = accuracy_metric(actual, predicted) scores.append(accuracy) return scores # Split a dataset based on an attribute and an attribute value def test_split(index, value, dataset): left, right = list(), list() for row in dataset: if row[index] < value: left.append(row) else: right.append(row) return left, right # Calculate the Gini index for a split dataset def gini_index(groups, classes): # count all samples at split point n_instances = float(sum([len(group) for group in groups])) # sum weighted Gini index for each group gini = 0.0 for group in groups: size = float(len(group)) # avoid divide by zero if size == 0: continue score = 0.0 # score the group based on the score for each class for class_val in classes: p = [row[-1] for row in group].count(class_val) / size score += p * p # weight the group score by its relative size gini += (1.0 - score) * (size / n_instances) return gini # Select the best split point for a dataset def get_split(dataset, n_features): class_values = list(set(row[-1] for row in dataset)) b_index, b_value, b_score, b_groups = 999, 999, 999, None features = list() while len(features) < n_features: index = randrange(len(dataset[0])-1) if index not in features: features.append(index) for index in features: for row in dataset: groups = test_split(index, row[index], dataset) gini = gini_index(groups, class_values) if gini < b_score: b_index, b_value, b_score, b_groups = index, row[index], gini, groups return {"index":b_index, "value":b_value, "groups":b_groups} # Create a terminal node value def to_terminal(group): outcomes = [row[-1] for row in group] return max(set(outcomes), key=outcomes.count) # Create child splits for a node or make terminal def split(node, max_depth, min_size, n_features, depth): left, right = node["groups"] del(node["groups"]) # check for a no split if not left or not right: node["left"] = node["right"] = to_terminal(left + right) return # check for max depth if depth >= max_depth: node["left"], node["right"] = to_terminal(left), to_terminal(right) return # process left child if len(left) <= min_size: node["left"] = to_terminal(left) else: node["left"] = get_split(left, n_features) split(node["left"], max_depth, min_size, n_features, depth+1) # process right child if len(right) <= min_size: node["right"] = to_terminal(right) else: node["right"] = get_split(right, n_features) split(node["right"], max_depth, min_size, n_features, depth+1) # Build a decision tree def build_tree(train, max_depth, min_size, n_features): root = get_split(train, n_features) split(root, max_depth, min_size, n_features, 1) return root # Make a prediction with a decision tree def predict(node, row): if row[node["index"]] < node["value"]: if isinstance(node["left"], dict): return predict(node["left"], row) else: return node["left"] else: if isinstance(node["right"], dict): return predict(node["right"], row) else: return node["right"] # Create a random subsample from the dataset with replacement def subsample(dataset, ratio): sample = list() n_sample = round(len(dataset) * ratio) while len(sample) < n_sample: index = randrange(len(dataset)) sample.append(dataset[index]) return sample # Make a prediction with a list of bagged trees def bagging_predict(trees, row): predictions = [predict(tree, row) for tree in trees] return max(set(predictions), key=predictions.count) # Random Forest Algorithm def random_forest(train, test, max_depth, min_size, sample_size, n_trees, n_features): trees = list() for i in range(n_trees): sample = subsample(train, sample_size) tree = build_tree(sample, max_depth, min_size, n_features) trees.append(tree) predictions = [bagging_predict(trees, row) for row in test] return(predictions) # Test the random forest algorithm seed(2) # load and prepare data filename = "sonar.all-data.csv" dataset = load_csv(filename) # convert string attributes to integers for i in range(0, len(dataset[0])-1): str_column_to_float(dataset, i) # convert class column to integers str_column_to_int(dataset, len(dataset[0])-1) # evaluate algorithm n_folds = 5 max_depth = 10 min_size = 1 sample_size = 1.0 n_features = int(sqrt(len(dataset[0])-1)) for n_trees in [1, 5, 10]: scores = evaluate_algorithm(dataset, random_forest, n_folds, max_depth, min_size, sample_size, n_trees, n_features) print("Trees: %d" % n_trees) print("Scores: %s" % scores) print("Mean Accuracy: %.3f%%" % (sum(scores)/float(len(scores))))
使用k值5進行交叉驗證,給定每個倍數值為208/5 = 41.6或者在每次迭代中剛好超過40個記錄被計算。
構建深度樹的最大深度為10,每個節點的最小訓練行數為1。訓練數據集樣本的創建大小與原始數據集相同,這是隨機森林算法的默認期望值。
在每個分割點處考慮的特征的數量被設置為sqrt(num_features)或者sqrt(60)= 7.74被保留為7個特征。
對一套有著3種不同數量的樹木(示例)進行評測在此過程中進行比較,結果表明隨著更多樹木的添加,(處理)技能也隨之提升。
運行該示例將打印每個折疊的分數和每個配置的平均分數。
Trees: 1 Scores: [56.09756097560976, 63.41463414634146, 60.97560975609756, 58.536585365853654, 73.17073170731707] Mean Accuracy: 62.439% Trees: 5 Scores: [70.73170731707317, 58.536585365853654, 85.36585365853658, 75.60975609756098, 63.41463414634146] Mean Accuracy: 70.732% Trees: 10 Scores: [82.92682926829268, 75.60975609756098, 97.5609756097561, 80.48780487804879, 68.29268292682927] Mean Accuracy: 80.976%擴展
本節列出了您可能有興趣探索的關于本教程的擴展。
算法優化。發現教程中使用的配置有一些試驗和錯誤,但沒有進行優化。嘗試更多的樹木,不同數量的特征,甚至不同的樹形配置來提高性能。
更多的問題。將該技術應用于其他分類問題,甚至將其應用于回歸,具有新的成本函數和結合樹預測的新方法。
你有沒有嘗試這些擴展? 在下面的評論中分享你的經驗。
評論在本教程中,您了解了如何從頭開始實現隨機森林算法。
具體來說,你了解到:
隨機森林和Bagged決策樹的區別。
如何更新決策樹的創建以適應隨機森林過程。
如何將隨機森林算法應用于現實世界的預測建模問題。
翻譯人:一只懶惰的小白,該成員來自云+社區翻譯社相關閱讀
原文鏈接:https://machinelearningmaster...
原文作者:Jason Brownlee
教程從頭開始在Python中實現k最近鄰居
Python NLTK 自然語言處理入門與例程
淺談用Python計算文本BLEU分數
此文已由作者授權云加社區發布,轉載請注明文章出處
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41422.html
摘要:目前騰訊云提供的云服務器并未提供方面的監控數據,本文旨在通過使用騰訊云的自定義監控服務來自行實現對服務器的使用率的監控。除了命令行工具,也提供了的供開發者使用,本文就基于的用于讀取使用率,并將數據上傳到騰訊云自定義監控對應接口進行監控。 歡迎大家前往云+社區,獲取更多騰訊海量技術實踐干貨哦~ 作者:李想 隨著人工智能以及比特幣的火熱,GPU云服務的使用場景是越來越廣,在很多場景下我們也...
馬上就要開始啦這次共組織15個組隊學習 涵蓋了AI領域從理論知識到動手實踐的內容 按照下面給出的最完備學習路線分類 難度系數分為低、中、高三檔 可以按照需要參加 - 學習路線 - showImg(https://segmentfault.com/img/remote/1460000019082128); showImg(https://segmentfault.com/img/remote/...
摘要:翻譯自昨天收到推送了一篇介紹隨機森林算法的郵件,感覺作為介紹和入門不錯,就順手把它翻譯一下。隨機森林引入的隨機森林算法將自動創建隨機決策樹群。回歸隨機森林也可以用于回歸問題。結語隨機森林相當起來非常容易。 翻譯自:http://blog.yhat.com/posts/python-random-forest.html 昨天收到yhat推送了一篇介紹隨機森林算法的郵件,感覺作為介紹和入門...
閱讀 2045·2021-11-08 13:22
閱讀 2506·2021-09-04 16:40
閱讀 1150·2021-09-03 10:29
閱讀 1715·2019-08-30 15:44
閱讀 2124·2019-08-30 11:13
閱讀 2791·2019-08-29 17:07
閱讀 1967·2019-08-29 14:22
閱讀 1247·2019-08-26 14:00