機器學習十大經典算法之隨機森林

2020-12-13 人工智慧cv

隨機森林簡介

隨機森林是機器學習一種常用的方法。它是以決策樹為基礎,用隨機的方式排列建立的,森林裡每個決策樹之間都是沒有關聯的。 在得到森林之後,當有一個新的輸入樣本進入的時候,就讓森林中的每一棵決策樹分別進行一下判斷,看看這個樣本應該屬於哪一類(對於分類算法),然後看看哪一類被選擇最多,就預測這個樣本為那一類。隨機森林可以用來進行無監督學習聚類和異常點檢測。決策樹(decision tree)是一個樹結構(可以是二叉樹或非二叉樹)。其每個非葉節點表示一個特徵屬性上的測試,每個分支代表這個特徵屬性在某個值域上的輸出,而每個葉節點存放一個類別。使用決策樹進行決策的過程就是從根節點開始,測試待分類項中相應的特徵屬性,並按照其值選擇輸出分支,直到到達葉子節點,將葉子節點存放的類別作為決策結果。詳情請前往先前的推送。

算法流程

隨機森林裡每棵樹按照如下規則生成:

1、如果訓練集大小為N,對於每棵樹而言,隨機且有放回地從訓練集中的抽取N個訓練樣本,作為該樹的訓練集;PS:從這裡我們可以知道:每棵樹的訓練集都是不同的,而且裡面包含重複的訓練樣本。

2、如果每個樣本的特徵維度為M,指定一個常數m<<M,隨機地從M個特徵中選取m個特徵子集,每次樹進行分裂時,從這m個屬性中採用某種策略(比如說信息增益)來選擇1個屬性作為該節點的分裂屬性。3、每棵樹都盡最大程度的生長,並且沒有剪枝過程。4、 按照步驟1~3建立大量的決策樹,這樣就構成了隨機森林了。一開始我們提到的隨機森林中的「隨機」就是指的這裡的兩個隨機性。兩個隨機性的引入對隨機森林的分類性能至關重要。由於它們的引入,使得隨機森林不容易陷入過擬合,並且具有很好得抗噪能力(比如:對預設值不敏感)

隨機森林優點

它能夠處理很高維度(feature很多)的數據,並且不用做特徵選擇(因為特徵子集是隨機選擇的)。在創建隨機森林的時候,對generlization error使用的是無偏估計,模型泛化能力強。訓練速度快,容易做成並行化方法(訓練時樹與樹之間是相互獨立的)。在訓練過程中,能夠檢測到feature間的互相影響。對於不平衡的數據集來說,它可以平衡誤差。隨機森林(Random Forest,簡稱RF)主要應用於

回歸和分類

,且擁有廣泛的應用前景,從市場營銷到醫療保健保險,既可以用來做市場營銷模擬的建模,統計客戶來源,保留和流失,也可用來預測疾病的風險和病患者的易感性。最近幾年的國內外大賽,包括2013年百度校園電影推薦系統大賽、2014年阿里巴巴天池大數據競賽以及Kaggle數據科學競賽,參賽者對隨機森林的使用佔有相當高的比例。而且隨機森林在運算量沒有顯著提高的情況下精度得到了很大的改善。

代碼實現

隨機森林實現分類算法

import pandas as pdimport numpy as npimport randomimport mathimport collectionsfrom sklearn.externals.joblib import Parallel, delayedclass Tree(object):"""定義一棵決策樹"""def __init__(self): self.split_feature = None self.split_value = None self.leaf_value = None self.tree_left = None self.tree_right = None def calc_predict_value(self, dataset):"""通過遞歸決策樹找到樣本所屬葉子節點"""if self.leaf_value is not None:return self.leaf_valueelif dataset[self.split_feature] <= self.split_value:return self.tree_left.calc_predict_value(dataset)else:return self.tree_right.calc_predict_value(dataset) def describe_tree(self):"""以json形式列印決策樹,方便查看樹結構"""if not self.tree_left and not self.tree_right: leaf_info = "{leaf_value:" + str(self.leaf_value) + "}"return leaf_info left_info = self.tree_left.describe_tree() right_info = self.tree_right.describe_tree() tree_structure = "{split_feature:" + str(self.split_feature) + \",split_value:" + str(self.split_value) + \",left_tree:" + left_info + \",right_tree:" + right_info + "}"return tree_structureclass RandomForestClassifier(object): def __init__(self, n_estimators=10, max_depth=-1, min_samples_split=2, min_samples_leaf=1, min_split_gain=0.0, colsample_bytree=None, subsample=0.8, random_state=None):""" 隨機森林參數 ---------- n_estimators: 樹數量 max_depth: 樹深度,-1表示不限制深度 min_samples_split: 節點分裂所需的最小樣本數量,小於該值節點終止分裂 min_samples_leaf: 葉子節點最少樣本數量,小於該值葉子被合併 min_split_gain: 分裂所需的最小增益,小於該值節點終止分裂 colsample_bytree: 列採樣設置,可取[sqrt、log2]。sqrt表示隨機選擇sqrt(n_features)個特徵, log2表示隨機選擇log(n_features)個特徵,設置為其他則不進行列採樣 subsample: 行採樣比例 random_state: 隨機種子,設置之後每次生成的n_estimators個樣本集不會變,確保實驗可重複 """ self.n_estimators = n_estimators self.max_depth = max_depth if max_depth != -1 elsefloat('inf') self.min_samples_split = min_samples_split self.min_samples_leaf = min_samples_leaf self.min_split_gain = min_split_gain self.colsample_bytree = colsample_bytree self.subsample = subsample self.random_state = random_state self.trees = None self.feature_importances_ = dict() def fit(self, dataset, targets):"""模型訓練入口""" assert targets.unique().__len__() == 2, "There must be two class for targets!" targets = targets.to_frame(name='label')if self.random_state: random.seed(self.random_state) random_state_stages = random.sample(range(self.n_estimators), self.n_estimators)# 兩種列採樣方式if self.colsample_bytree == "sqrt": self.colsample_bytree = int(len(dataset.columns) ** 0.5)elif self.colsample_bytree == "log2": self.colsample_bytree = int(math.log(len(dataset.columns)))else: self.colsample_bytree = len(dataset.columns)# 並行建立多棵決策樹 self.trees = Parallel(n_jobs=-1, verbose=0, backend="threading")( delayed(self._parallel_build_trees)(dataset, targets, random_state)for random_state in random_state_stages) def _parallel_build_trees(self, dataset, targets, random_state):"""bootstrap有放回抽樣生成訓練樣本集,建立決策樹""" subcol_index = random.sample(dataset.columns.tolist(), self.colsample_bytree) dataset_stage = dataset.sample(n=int(self.subsample * len(dataset)), replace=True, random_state=random_state).reset_index(drop=True) dataset_stage = dataset_stage.loc[:, subcol_index] targets_stage = targets.sample(n=int(self.subsample * len(dataset)), replace=True, random_state=random_state).reset_index(drop=True) tree = self._build_single_tree(dataset_stage, targets_stage, depth=0)print(tree.describe_tree())return tree def _build_single_tree(self, dataset, targets, depth):"""遞歸建立決策樹"""# 如果該節點的類別全都一樣/樣本小於分裂所需最小樣本數量,則選取出現次數最多的類別。終止分裂if len(targets['label'].unique()) <= 1 or dataset.__len__() <= self.min_samples_split: tree = Tree() tree.leaf_value = self.calc_leaf_value(targets['label'])return treeif depth < self.max_depth: best_split_feature, best_split_value, best_split_gain = self.choose_best_feature(dataset, targets) left_dataset, right_dataset, left_targets, right_targets = \ self.split_dataset(dataset, targets, best_split_feature, best_split_value) tree = Tree()# 如果父節點分裂後,左葉子節點/右葉子節點樣本小於設置的葉子節點最小樣本數量,則該父節點終止分裂if left_dataset.__len__() <= self.min_samples_leaf or \ right_dataset.__len__() <= self.min_samples_leaf or \ best_split_gain <= self.min_split_gain: tree.leaf_value = self.calc_leaf_value(targets['label'])return treeelse:# 如果分裂的時候用到該特徵,則該特徵的importance加1 self.feature_importances_[best_split_feature] = \ self.feature_importances_.get(best_split_feature, 0) + 1 tree.split_feature = best_split_feature tree.split_value = best_split_value tree.tree_left = self._build_single_tree(left_dataset, left_targets, depth+1) tree.tree_right = self._build_single_tree(right_dataset, right_targets, depth+1)return tree# 如果樹的深度超過預設值,則終止分裂else: tree = Tree() tree.leaf_value = self.calc_leaf_value(targets['label'])return tree def choose_best_feature(self, dataset, targets):"""尋找最好的數據集劃分方式,找到最優分裂特徵、分裂閾值、分裂增益""" best_split_gain = 1 best_split_feature = None best_split_value = Nonefor feature in dataset.columns:if dataset[feature].unique().__len__() <= 100: unique_values = sorted(dataset[feature].unique().tolist())# 如果該維度特徵取值太多,則選擇100個百分位值作為待選分裂閾值else: unique_values = np.unique([np.percentile(dataset[feature], x)for x in np.linspace(0, 100, 100)])# 對可能的分裂閾值求分裂增益,選取增益最大的閾值for split_value in unique_values: left_targets = targets[dataset[feature] <= split_value] right_targets = targets[dataset[feature] > split_value] split_gain = self.calc_gini(left_targets['label'], right_targets['label'])if split_gain < best_split_gain: best_split_feature = feature best_split_value = split_value best_split_gain = split_gainreturn best_split_feature, best_split_value, best_split_gain @staticmethod def calc_leaf_value(targets):"""選擇樣本中出現次數最多的類別作為葉子節點取值""" label_counts = collections.Counter(targets) major_label = max(zip(label_counts.values(), label_counts.keys()))return major_label[1] @staticmethod def calc_gini(left_targets, right_targets):"""分類樹採用基尼指數作為指標來選擇最優分裂點""" split_gain = 0for targets in [left_targets, right_targets]: gini = 1# 統計每個類別有多少樣本,然後計算gini label_counts = collections.Counter(targets)for key in label_counts: prob = label_counts[key] * 1.0 / len(targets) gini -= prob ** 2 split_gain += len(targets) * 1.0 / (len(left_targets) + len(right_targets)) * ginireturn split_gain @staticmethod def split_dataset(dataset, targets, split_feature, split_value):"""根據特徵和閾值將樣本劃分成左右兩份,左邊小於等於閾值,右邊大於閾值""" left_dataset = dataset[dataset[split_feature] <= split_value] left_targets = targets[dataset[split_feature] <= split_value] right_dataset = dataset[dataset[split_feature] > split_value] right_targets = targets[dataset[split_feature] > split_value]return left_dataset, right_dataset, left_targets, right_targets def predict(self, dataset):"""輸入樣本,預測所屬類別""" res = []for _, row in dataset.iterrows(): pred_list = []# 統計每棵樹的預測結果,選取出現次數最多的結果作為最終類別for tree in self.trees: pred_list.append(tree.calc_predict_value(row)) pred_label_counts = collections.Counter(pred_list) pred_label = max(zip(pred_label_counts.values(), pred_label_counts.keys())) res.append(pred_label[1])return np.array(res)if __name__ == '__main__': df = pd.read_csv("source/wine.txt") df = df[df['label'].isin([1, 2])].sample(frac=1, random_state=66).reset_index(drop=True) clf = RandomForestClassifier(n_estimators=5, max_depth=5, min_samples_split=6, min_samples_leaf=2, min_split_gain=0.0, colsample_bytree="sqrt", subsample=0.8, random_state=66) train_count = int(0.7 * len(df)) feature_list = ["Alcohol", "Malic acid", "Ash", "Alcalinity of ash", "Magnesium", "Total phenols", "Flavanoids", "Nonflavanoid phenols", "Proanthocyanins", "Color intensity", "Hue", "OD280/OD315 of diluted wines", "Proline"] clf.fit(df.loc[:train_count, feature_list], df.loc[:train_count, 'label']) from sklearn import metricsprint(metrics.accuracy_score(df.loc[:train_count, 'label'], clf.predict(df.loc[:train_count, feature_list])))print(metrics.accuracy_score(df.loc[train_count:, 'label'], clf.predict(df.loc[train_count:, feature_list])))

現在實現隨機森林基本上都是可以直接調用

sklearn

裡面的API。

from sklearn.ensemble import RandomForestClassifier

參考資料

[1]

https://blog.csdn.net/yangyin007/article/details/82385967

[2]

https://zhuanlan.zhihu.com/p/22097796

[3]

https://github.com/zhaoxingfeng/RandomForest/blob/master/RandomForestClassification.py

相關焦點

  • 用Python實現隨機森林算法
    除了仍然根據從訓練數據樣本建立複合模型之外,隨機森林對用做構建樹(tree)的數據特徵做了一定限制,使得生成的決策樹之間沒有關聯,從而提升算法效果。本文章旨在探討如何用 Python 實現隨機森林算法。
  • 「機器學習」機器學習算法優缺點對比(匯總篇)
    主要回顧下幾個常用算法的適應場景及其優缺點!機器學習算法太多了,分類、回歸、聚類、推薦、圖像識別領域等等,要想找到一個合適算法真的不容易,所以在實際應用中,我們一般都是採用啟發式學習方式來實驗。另一個缺點就是容易出現過擬合,但這也就是諸如隨機森林RF(或提升樹boosted tree)之類的集成方法的切入點。另外,隨機森林經常是很多分類問題的贏家(通常比支持向量機好上那麼一丁點),它訓練快速並且可調,同時你無須擔心要像支持向量機那樣調一大堆參數,所以在以前都一直很受歡迎。
  • 深入了解4大熱門機器學習算法
    但其實,真正了解機器學習的人還是少數,大多數人屬於以下兩個陣營:· 不懂機器學習算法;· 知道算法是如何工作的,但不知道為什麼會工作。因此,本文試圖闡述算法的工作流程和內容,盡力直觀地解釋其中的工作原理,希望能讓你對此有豁然開朗之感。
  • 實戰:用Python實現隨機森林
    因為有Scikit-Learn這樣的庫,現在用Python實現任何機器學習算法都非常容易。實際上,我們現在不需要任何潛在的知識來了解模型如何工作。雖然不需要了解所有細節,但了解模型如何訓練和預測對工作仍有幫助。比如:如果性能不如預期,我們可以診斷模型或當我們想要說服其他人使用我們的模型時,我們可以向他們解釋模型如何做出決策的。
  • 不囉嗦,上代碼——機器學習經典實例
    當然也是在Google、StackOverflow、GitHub網站上找不到答案之後,無可奈何之舉。編程書把看著複雜的知識寫得更複雜,雖然大多篇幅不輸「飛雪連天射白鹿,笑書神俠倚碧鴛」等經典,且綱舉目張、圖文並茂,甚至有作者愛引經據典,卻極少有令人拍案的驚奇之處。為什麼同樣是文以載道,編程書卻不能像武俠小說一樣簡單具體,反而顯得了無生趣,令人望而卻步?
  • 從決策樹到隨機森林:樹型算法的原理與實現
    本文由機器之心編輯,「機器之心」專注生產人工智慧專業性內容,適合開發者和從業者閱讀參考。點擊右上角即刻關注。基於樹(Tree based)的學習算法在數據科學競賽中是相當常見的。這些算法給預測模型賦予了準確性、穩定性以及易解釋性。和線性模型不同,它們對非線性關係也能進行很好的映射。
  • 機器學習十大經典算法之AdaBoost
    Boosting是一族算法,其主要目標為將弱學習器「提升」為強學習器,大部分Boosting算法都是根據前一個學習器的訓練效果對樣本分布進行調整,再根據新的樣本分布訓練下一個學習器,如此迭代M次,最後將一系列弱學習器組合成一個強學習器。而這些Boosting算法的不同點則主要體現在每輪樣本分布的調整方式上。
  • 算法應用|機器學習python應用,簡單機器學習項目實踐
    這個項目是針對鳶尾花(Iris Flower)進行分類的一個項目,數據集是含鳶尾花的三個亞屬的分類信息,通過機器學習算法生成一個模型,自動分類新數據到這三個亞屬的某一個中。5 數據處理一般在機器學習的項目中,數據清洗、數據處理就佔去了整個項目的80%的工作量,所以這是機器學習項目中非常重要的一個環節,但在本項目中,iris的數據已經是非常完善的,不需要再進行過多的數據處理過程。如此我們只需要簡單處理一下原數據,使其更適合在某些有特殊要求的算法上使用。
  • 大盤點:隨機森林的優缺點以及如何用Python解釋
    隨機森林隨機森林是一種靈活的、便於使用的機器學習算法,即使沒有超參數調整,大多數情況下也會帶來好的結果。它可以用來進行分類和回歸任務。通過本文,你將會學習到隨機森林算法是如何解決分類和回歸問題的。為了理解什麼是隨機森林算法,首先要熟悉決策樹。決策樹往往會產生過擬合問題,尤其會發生在存在整組數據的決策樹上。有時決策樹仿佛變得只會記憶數據了。
  • 選擇Spark機器學習API的四大機器學習算法,你掌握了多少?
    Oliver翻譯 丨 雨言編輯註:本文簡要介紹了四種經典的機器學習算法。本文將簡要介紹Spark機器學習庫(Spark MLlib’s APIs)的各種機器學習算法,主要包括:統計算法、分類算法、聚類算法和協同過濾算法,以及各種算法的應用。你不是一個數據科學家。
  • 威斯康辛大學《機器學習導論》2020秋季課程完結,課件、視頻資源已...
    機器之心報導編輯:蛋醬對於機器學習領域的初學者來說,這會是很好的入門課程。目前,課程的筆記、PPT 和視頻正在陸續發布中。,監督學習、無監督學習和強化學習1.4 符號:介紹了將在本課程中使用的機器學習形式和符號1.5 ML 應用:走向機器學習程序的主要步驟,以及機器學習組件的分類1.6 ML 動力:關於學習機器學習的不同觀點和動力L02:最近鄰算法2.1 最近鄰算法:介紹最近鄰算法
  • Python機器學習的迷你課程(14天教學)
    有許多不同的度量標準可以用來評估機器學習算法在數據集上的技能。抽查數據集上的一些非線性算法(如KNN、SVM和CART)。在數據集上對一些複雜的集成算法進行抽樣檢查(例如隨機森林和隨機梯度提升)。例如,下面的代碼片段對波士頓房價數據集上的k近鄰算法進行抽樣檢查。
  • 微分方程VS機器學習,實例講解二者異同
    經驗或數據驅動型建模,特別是機器學習,能夠讓數據來學習系統的結構,這個過程就叫做「擬合」。機器學習對於人類不確定如何將信號從噪聲中分離出來的複雜系統格外有效,只需要訓練一種聰明的算法,讓它來代替你做繁瑣的事情。
  • 優化算法系列之模擬退火算法(1)
    模擬退火算法是所謂三大非經典算法之一,它脫胎於自然界的物理過程,與優化問題相結合。在百度百科上對於模擬退火算法的定義是:模擬退火算法來源於固體退火原理,是一種基於概率的算法,將固體加溫至充分高,再讓其徐徐冷卻,加溫時,固體內部粒子隨溫升變為無序狀,內能增大,而徐徐冷卻時粒子漸趨有序,在每個溫度都達到平衡態,最後在常溫時達到基態,內能減為最小。
  • 進化決策樹:當機器學習從生物學中汲取靈感時
    這種鳥的喙部細長,使之在潛入水中捕食時能夠少濺水花。因此,通過模仿這種鳥的形象重新設計列車,工程師不僅解決了最初的問題,而且還將列車的耗電量減少了15%,速度提高了10%。圖1-日本的高速鐵路,新幹線,來源生物學知識也可以成為機器學習中靈感的來源。
  • 李飛飛推薦:一篇文章幫你糾正十個機器學習誤區
    ----李飛飛在柯潔和阿爾法狗大戰熱忱之時,李飛飛在推特推薦了一篇文章說明機器學習的十大誤區,並說:機器快速,準確但有點「笨」,而人緩慢,不精準卻充滿創造力!  然而機器學習現在已然登上了頭版頭條,成為了被熱烈討論的話題!機器學習算法可以駕駛車輛,可以翻譯演講,贏得危險邊緣遊戲(哥倫比亞廣播公司益智問答遊戲節目)!我們不由自主會問:「他們到底能做什麼不能做到什麼?他們會是隱私、工作甚至是人類消失的開始呢?」
  • 使用Scikit-learn 理解隨機森林
    翻譯 | 汪鵬 校對 | 餘杭 整理 | 餘杭在我以前的一篇文章中,我討論了隨機森林如何變成一個「白箱子」,這樣每次預測就能被分解為各項特徵的貢獻和,即預測=偏差+特徵 1 貢獻+ ... +特徵 n 貢獻。
  • 常用數據挖掘算法簡介
    基於深度置信網絡(DBN)提出非監督貪心逐層訓練算法,為解決深層結構相關的優化難題帶來希望,隨後提出多層自動編碼器深層結構。此外Lecun等人提出的卷積神經網絡是第一個真正多層結構學習算法,它利用空間相對關係減少參數數目以提高訓練性能。深度學習涉及相當廣泛的機器學習技術和結構,根據這些結構和技術應用的方式,可以將其分成如下三類:a) 生成性深度結構。
  • 吐血整理:43種機器學習開源數據集(附地址/調用方法)
    導讀:學習機器學習是一個不斷探索和實驗的過程,因此,本文將主要介紹常見的開源數據集,便於讀者學習和實驗各種機器學習算法。  作者:張春強 張和平 唐振 來源:大數據DT(ID:hzdashuju)
  • 可用於水下形成清晰圖像的機器學習算法,高度還原拍照顏色與亮度
    打開APP 可用於水下形成清晰圖像的機器學習算法,高度還原拍照顏色與亮度 大萌、夏雅薇 發表於 2020-01-17 13:50:22