第7章 集成方法 ensemble method

集成方法: ensemble method(元算法: meta algorithm) 概述
概念:是對(duì)其他算法進(jìn)行組合的一種形式。
通俗來說: 當(dāng)做重要決定時(shí),大家可能都會(huì)考慮吸取多個(gè)專家而不只是一個(gè)人的意見。
機(jī)器學(xué)習(xí)處理問題時(shí)又何嘗不是如此? 這就是集成方法背后的思想。-
集成方法:
- 投票選舉(bagging: 自舉匯聚法 bootstrap aggregating): 是基于數(shù)據(jù)隨機(jī)重抽樣分類器構(gòu)造的方法
- 再學(xué)習(xí)(boosting): 是基于所有分類器的加權(quán)求和的方法
集成方法 場(chǎng)景
目前 bagging 方法最流行的版本是: 隨機(jī)森林(random forest)
選男友:美女選擇擇偶對(duì)象的時(shí)候,會(huì)問幾個(gè)閨蜜的建議,最后選擇一個(gè)綜合得分最高的一個(gè)作為男朋友
目前 boosting 方法最流行的版本是: AdaBoost
追女友:3個(gè)帥哥追同一個(gè)美女,第1個(gè)帥哥失敗->(傳授經(jīng)驗(yàn):姓名、家庭情況) 第2個(gè)帥哥失敗->(傳授經(jīng)驗(yàn):興趣愛好、性格特點(diǎn)) 第3個(gè)帥哥成功
bagging 和 boosting 區(qū)別是什么?
- bagging 是一種與 boosting 很類似的技術(shù), 所使用的多個(gè)分類器的類型(數(shù)據(jù)量和特征量)都是一致的。
- bagging 是由不同的分類器(1.數(shù)據(jù)隨機(jī)化 2.特征隨機(jī)化)經(jīng)過訓(xùn)練,綜合得出的出現(xiàn)最多分類結(jié)果;boosting 是通過調(diào)整已有分類器錯(cuò)分的那些數(shù)據(jù)來獲得新的分類器,得出目前最優(yōu)的結(jié)果。
- bagging 中的分類器權(quán)重是相等的;而 boosting 中的分類器加權(quán)求和,所以權(quán)重并不相等,每個(gè)權(quán)重代表的是其對(duì)應(yīng)分類器在上一輪迭代中的成功度。
隨機(jī)森林
隨機(jī)森林 概述
- 隨機(jī)森林指的是利用多棵樹對(duì)樣本進(jìn)行訓(xùn)練并預(yù)測(cè)的一種分類器。
- 決策樹相當(dāng)于一個(gè)大師,通過自己在數(shù)據(jù)集中學(xué)到的知識(shí)用于新數(shù)據(jù)的分類。但是俗話說得好,一個(gè)諸葛亮,玩不過三個(gè)臭皮匠。隨機(jī)森林就是希望構(gòu)建多個(gè)臭皮匠,希望最終的分類效果能夠超過單個(gè)大師的一種算法。
隨機(jī)森林 原理
那隨機(jī)森林具體如何構(gòu)建呢?
有兩個(gè)方面:
- 數(shù)據(jù)的隨機(jī)性化
- 待選特征的隨機(jī)化
使得隨機(jī)森林中的決策樹都能夠彼此不同,提升系統(tǒng)的多樣性,從而提升分類性能。
數(shù)據(jù)的隨機(jī)化:使得隨機(jī)森林中的決策樹更普遍化一點(diǎn),適合更多的場(chǎng)景。
(有放回的準(zhǔn)確率在:70% 以上, 無放回的準(zhǔn)確率在:60% 以上)
- 采取有放回的抽樣方式 構(gòu)造子數(shù)據(jù)集,保證不同子集之間的數(shù)量級(jí)一樣(不同子集/同一子集 之間的元素可以重復(fù))
- 利用子數(shù)據(jù)集來構(gòu)建子決策樹,將這個(gè)數(shù)據(jù)放到每個(gè)子決策樹中,每個(gè)子決策樹輸出一個(gè)結(jié)果。
- 然后統(tǒng)計(jì)子決策樹的投票結(jié)果,得到最終的分類 就是 隨機(jī)森林的輸出結(jié)果。
- 如下圖,假設(shè)隨機(jī)森林中有3棵子決策樹,2棵子樹的分類結(jié)果是A類,1棵子樹的分類結(jié)果是B類,那么隨機(jī)森林的分類結(jié)果就是A類。

待選特征的隨機(jī)化
- 子樹從所有的待選特征中隨機(jī)選取一定的特征。
- 在選取的特征中選取最優(yōu)的特征。
下圖中,藍(lán)色的方塊代表所有可以被選擇的特征,也就是目前的待選特征;黃色的方塊是分裂特征。
左邊是一棵決策樹的特征選取過程,通過在待選特征中選取最優(yōu)的分裂特征(別忘了前文提到的ID3算法,C4.5算法,CART算法等等),完成分裂。
右邊是一個(gè)隨機(jī)森林中的子樹的特征選取過程。

隨機(jī)森林 開發(fā)流程
收集數(shù)據(jù):任何方法
準(zhǔn)備數(shù)據(jù):轉(zhuǎn)換樣本集
分析數(shù)據(jù):任何方法
訓(xùn)練算法:通過數(shù)據(jù)隨機(jī)化和特征隨機(jī)化,進(jìn)行多實(shí)例的分類評(píng)估
測(cè)試算法:計(jì)算錯(cuò)誤率
使用算法:輸入樣本數(shù)據(jù),然后運(yùn)行 隨機(jī)森林 算法判斷輸入數(shù)據(jù)分類屬于哪個(gè)分類,最后對(duì)計(jì)算出的分類執(zhí)行后續(xù)處理
隨機(jī)森林 算法特點(diǎn)
優(yōu)點(diǎn):幾乎不需要輸入準(zhǔn)備、可實(shí)現(xiàn)隱式特征選擇、訓(xùn)練速度非??臁⑵渌P秃茈y超越、很難建立一個(gè)糟糕的隨機(jī)森林模型、大量?jī)?yōu)秀、免費(fèi)以及開源的實(shí)現(xiàn)。
缺點(diǎn):劣勢(shì)在于模型大小、是個(gè)很難去解釋的黑盒子。
適用數(shù)據(jù)范圍:數(shù)值型和標(biāo)稱型
項(xiàng)目案例: 聲納信號(hào)分類
項(xiàng)目概述
這是 Gorman 和 Sejnowski 在研究使用神經(jīng)網(wǎng)絡(luò)的聲納信號(hào)分類中使用的數(shù)據(jù)集。任務(wù)是訓(xùn)練一個(gè)模型來區(qū)分聲納信號(hào)。
開發(fā)流程
收集數(shù)據(jù):提供的文本文件
準(zhǔn)備數(shù)據(jù):轉(zhuǎn)換樣本集
分析數(shù)據(jù):手工檢查數(shù)據(jù)
訓(xùn)練算法:在數(shù)據(jù)上,利用 random_forest() 函數(shù)進(jìn)行優(yōu)化評(píng)估,返回模型的綜合分類結(jié)果
測(cè)試算法:在采用自定義 n_folds 份隨機(jī)重抽樣 進(jìn)行測(cè)試評(píng)估,得出綜合的預(yù)測(cè)評(píng)分
使用算法:若你感興趣可以構(gòu)建完整的應(yīng)用程序,從案例進(jìn)行封裝,也可以參考我們的代碼
收集數(shù)據(jù):提供的文本文件
樣本數(shù)據(jù):sonar-all-data.txt
0.02,0.0371,0.0428,0.0207,0.0954,0.0986,0.1539,0.1601,0.3109,0.2111,0.1609,0.1582,0.2238,0.0645,0.066,0.2273,0.31,0.2999,0.5078,0.4797,0.5783,0.5071,0.4328,0.555,0.6711,0.6415,0.7104,0.808,0.6791,0.3857,0.1307,0.2604,0.5121,0.7547,0.8537,0.8507,0.6692,0.6097,0.4943,0.2744,0.051,0.2834,0.2825,0.4256,0.2641,0.1386,0.1051,0.1343,0.0383,0.0324,0.0232,0.0027,0.0065,0.0159,0.0072,0.0167,0.018,0.0084,0.009,0.0032,R
0.0453,0.0523,0.0843,0.0689,0.1183,0.2583,0.2156,0.3481,0.3337,0.2872,0.4918,0.6552,0.6919,0.7797,0.7464,0.9444,1,0.8874,0.8024,0.7818,0.5212,0.4052,0.3957,0.3914,0.325,0.32,0.3271,0.2767,0.4423,0.2028,0.3788,0.2947,0.1984,0.2341,0.1306,0.4182,0.3835,0.1057,0.184,0.197,0.1674,0.0583,0.1401,0.1628,0.0621,0.0203,0.053,0.0742,0.0409,0.0061,0.0125,0.0084,0.0089,0.0048,0.0094,0.0191,0.014,0.0049,0.0052,0.0044,R
0.0262,0.0582,0.1099,0.1083,0.0974,0.228,0.2431,0.3771,0.5598,0.6194,0.6333,0.706,0.5544,0.532,0.6479,0.6931,0.6759,0.7551,0.8929,0.8619,0.7974,0.6737,0.4293,0.3648,0.5331,0.2413,0.507,0.8533,0.6036,0.8514,0.8512,0.5045,0.1862,0.2709,0.4232,0.3043,0.6116,0.6756,0.5375,0.4719,0.4647,0.2587,0.2129,0.2222,0.2111,0.0176,0.1348,0.0744,0.013,0.0106,0.0033,0.0232,0.0166,0.0095,0.018,0.0244,0.0316,0.0164,0.0095,0.0078,R
準(zhǔn)備數(shù)據(jù):轉(zhuǎn)換樣本集
# 導(dǎo)入csv文件
def loadDataSet(filename):
dataset = []
with open(filename, 'r') as fr:
for line in fr.readlines():
if not line:
continue
lineArr = []
for featrue in line.split(','):
# strip()返回移除字符串頭尾指定的字符生成的新字符串
str_f = featrue.strip()
if str_f.isdigit(): # 判斷是否是數(shù)字
# 將數(shù)據(jù)集的第column列轉(zhuǎn)換成float形式
lineArr.append(float(str_f))
else:
# 添加分類標(biāo)簽
lineArr.append(str_f)
dataset.append(lineArr)
return dataset
分析數(shù)據(jù):手工檢查數(shù)據(jù)
訓(xùn)練算法:在數(shù)據(jù)上,利用 random_forest() 函數(shù)進(jìn)行優(yōu)化評(píng)估,返回模型的綜合分類結(jié)果
- 樣本數(shù)據(jù)隨機(jī)無放回抽樣-用于交叉驗(yàn)證
def cross_validation_split(dataset, n_folds):
"""cross_validation_split(將數(shù)據(jù)集進(jìn)行抽重抽樣 n_folds 份,數(shù)據(jù)可以重復(fù)重復(fù)抽取)
Args:
dataset 原始數(shù)據(jù)集
n_folds 數(shù)據(jù)集dataset分成n_flods份
Returns:
dataset_split list集合,存放的是:將數(shù)據(jù)集進(jìn)行抽重抽樣 n_folds 份,數(shù)據(jù)可以重復(fù)重復(fù)抽取
"""
dataset_split = list()
dataset_copy = list(dataset) # 復(fù)制一份 dataset,防止 dataset 的內(nèi)容改變
fold_size = len(dataset) / n_folds
for i in range(n_folds):
fold = list() # 每次循環(huán) fold 清零,防止重復(fù)導(dǎo)入 dataset_split
while len(fold) < fold_size: # 這里不能用 if,if 只是在第一次判斷時(shí)起作用,while 執(zhí)行循環(huán),直到條件不成立
# 有放回的隨機(jī)采樣,有一些樣本被重復(fù)采樣,從而在訓(xùn)練集中多次出現(xiàn),有的則從未在訓(xùn)練集中出現(xiàn),此則自助采樣法。從而保證每棵決策樹訓(xùn)練集的差異性
index = randrange(len(dataset_copy))
# 將對(duì)應(yīng)索引 index 的內(nèi)容從 dataset_copy 中導(dǎo)出,并將該內(nèi)容從 dataset_copy 中刪除。
# pop() 函數(shù)用于移除列表中的一個(gè)元素(默認(rèn)最后一個(gè)元素),并且返回該元素的值。
fold.append(dataset_copy.pop(index)) # 無放回的方式
# fold.append(dataset_copy[index]) # 有放回的方式
dataset_split.append(fold)
# 由dataset分割出的n_folds個(gè)數(shù)據(jù)構(gòu)成的列表,為了用于交叉驗(yàn)證
return dataset_split
- 訓(xùn)練數(shù)據(jù)集隨機(jī)化
# Create a random subsample from the dataset with replacement
def subsample(dataset, ratio): # 創(chuàng)建數(shù)據(jù)集的隨機(jī)子樣本
"""random_forest(評(píng)估算法性能,返回模型得分)
Args:
dataset 訓(xùn)練數(shù)據(jù)集
ratio 訓(xùn)練數(shù)據(jù)集的樣本比例
Returns:
sample 隨機(jī)抽樣的訓(xùn)練樣本
"""
sample = list()
# 訓(xùn)練樣本的按比例抽樣。
# round() 方法返回浮點(diǎn)數(shù)x的四舍五入值。
n_sample = round(len(dataset) * ratio)
while len(sample) < n_sample:
# 有放回的隨機(jī)采樣,有一些樣本被重復(fù)采樣,從而在訓(xùn)練集中多次出現(xiàn),有的則從未在訓(xùn)練集中出現(xiàn),此則自助采樣法。從而保證每棵決策樹訓(xùn)練集的差異性
index = randrange(len(dataset))
sample.append(dataset[index])
return sample
- 特征隨機(jī)化
# 找出分割數(shù)據(jù)集的最優(yōu)特征,得到最優(yōu)的特征 index,特征值 row[index],以及分割完的數(shù)據(jù) groups(left, right)
def get_split(dataset, n_features):
class_values = list(set(row[-1] for row in dataset)) # class_values =[0, 1]
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) # 往 features 添加 n_features 個(gè)特征( n_feature 等于特征數(shù)的根號(hào)),特征索引從 dataset 中隨機(jī)取
if index not in features:
features.append(index)
for index in features: # 在 n_features 個(gè)特征中選出最優(yōu)的特征索引,并沒有遍歷所有特征,從而保證了每課決策樹的差異性
for row in dataset:
groups = test_split(index, row[index], dataset) # groups=(left, right), row[index] 遍歷每一行 index 索引下的特征值作為分類值 value, 找出最優(yōu)的分類特征和特征值
gini = gini_index(groups, class_values)
# 左右兩邊的數(shù)量越一樣,說明數(shù)據(jù)區(qū)分度不高,gini系數(shù)越大
if gini < b_score:
b_index, b_value, b_score, b_groups = index, row[index], gini, groups # 最后得到最優(yōu)的分類特征 b_index,分類特征值 b_value,分類結(jié)果 b_groups。b_value 為分錯(cuò)的代價(jià)成本
# print b_score
return {'index': b_index, 'value': b_value, 'groups': b_groups}
- 隨機(jī)森林
# Random Forest Algorithm
def random_forest(train, test, max_depth, min_size, sample_size, n_trees, n_features):
"""random_forest(評(píng)估算法性能,返回模型得分)
Args:
train 訓(xùn)練數(shù)據(jù)集
test 測(cè)試數(shù)據(jù)集
max_depth 決策樹深度不能太深,不然容易導(dǎo)致過擬合
min_size 葉子節(jié)點(diǎn)的大小
sample_size 訓(xùn)練數(shù)據(jù)集的樣本比例
n_trees 決策樹的個(gè)數(shù)
n_features 選取的特征的個(gè)數(shù)
Returns:
predictions 每一行的預(yù)測(cè)結(jié)果,bagging 預(yù)測(cè)最后的分類結(jié)果
"""
trees = list()
# n_trees 表示決策樹的數(shù)量
for i in range(n_trees):
# 隨機(jī)抽樣的訓(xùn)練樣本, 隨機(jī)采樣保證了每棵決策樹訓(xùn)練集的差異性
sample = subsample(train, sample_size)
# 創(chuàng)建一個(gè)決策樹
tree = build_tree(sample, max_depth, min_size, n_features)
trees.append(tree)
# 每一行的預(yù)測(cè)結(jié)果,bagging 預(yù)測(cè)最后的分類結(jié)果
predictions = [bagging_predict(trees, row) for row in test]
return predictions
測(cè)試算法:在采用自定義 n_folds 份隨機(jī)重抽樣 進(jìn)行測(cè)試評(píng)估,得出綜合的預(yù)測(cè)評(píng)分。
- 計(jì)算隨機(jī)森林的預(yù)測(cè)結(jié)果的正確率
# 評(píng)估算法性能,返回模型得分
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
"""evaluate_algorithm(評(píng)估算法性能,返回模型得分)
Args:
dataset 原始數(shù)據(jù)集
algorithm 使用的算法
n_folds 數(shù)據(jù)的份數(shù)
*args 其他的參數(shù)
Returns:
scores 模型得分
"""
# 將數(shù)據(jù)集進(jìn)行隨機(jī)抽樣,分成 n_folds 份,數(shù)據(jù)無重復(fù)的抽取
folds = cross_validation_split(dataset, n_folds)
scores = list()
# 每次循環(huán)從 folds 從取出一個(gè) fold 作為測(cè)試集,其余作為訓(xùn)練集,遍歷整個(gè) folds ,實(shí)現(xiàn)交叉驗(yàn)證
for fold in folds:
train_set = list(folds)
train_set.remove(fold)
# 將多個(gè) fold 列表組合成一個(gè) train_set 列表, 類似 union all
"""
In [20]: l1=[[1, 2, 'a'], [11, 22, 'b']]
In [21]: l2=[[3, 4, 'c'], [33, 44, 'd']]
In [22]: l=[]
In [23]: l.append(l1)
In [24]: l.append(l2)
In [25]: l
Out[25]: [[[1, 2, 'a'], [11, 22, 'b']], [[3, 4, 'c'], [33, 44, 'd']]]
In [26]: sum(l, [])
Out[26]: [[1, 2, 'a'], [11, 22, 'b'], [3, 4, 'c'], [33, 44, 'd']]
"""
train_set = sum(train_set, [])
test_set = list()
# fold 表示從原始數(shù)據(jù)集 dataset 提取出來的測(cè)試集
for row in fold:
row_copy = list(row)
row_copy[-1] = None
test_set.append(row_copy)
predicted = algorithm(train_set, test_set, *args)
actual = [row[-1] for row in fold]
# 計(jì)算隨機(jī)森林的預(yù)測(cè)結(jié)果的正確率
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)
return scores
使用算法:若你感興趣可以構(gòu)建完整的應(yīng)用程序,從案例進(jìn)行封裝,也可以參考我們的代碼
完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/7.RandomForest/randomForest.py
AdaBoost
AdaBoost (adaptive boosting: 自適應(yīng) boosting) 概述
能否使用弱分類器和多個(gè)實(shí)例來構(gòu)建一個(gè)強(qiáng)分類器? 這是一個(gè)非常有趣的理論問題。
AdaBoost 原理
AdaBoost 工作原理

AdaBoost 開發(fā)流程
收集數(shù)據(jù):可以使用任意方法
準(zhǔn)備數(shù)據(jù):依賴于所使用的弱分類器類型,本章使用的是單層決策樹,這種分類器可以處理任何數(shù)據(jù)類型。
當(dāng)然也可以使用任意分類器作為弱分類器,第2章到第6章中的任一分類器都可以充當(dāng)弱分類器。
作為弱分類器,簡(jiǎn)單分類器的效果更好。
分析數(shù)據(jù):可以使用任意方法。
訓(xùn)練算法:AdaBoost 的大部分時(shí)間都用在訓(xùn)練上,分類器將多次在同一數(shù)據(jù)集上訓(xùn)練弱分類器。
測(cè)試算法:計(jì)算分類的錯(cuò)誤率。
使用算法:通SVM一樣,AdaBoost 預(yù)測(cè)兩個(gè)類別中的一個(gè)。如果想把它應(yīng)用到多個(gè)類別的場(chǎng)景,那么就要像多類 SVM 中的做法一樣對(duì) AdaBoost 進(jìn)行修改。
AdaBoost 算法特點(diǎn)
* 優(yōu)點(diǎn):泛化(由具體的、個(gè)別的擴(kuò)大為一般的)錯(cuò)誤率低,易編碼,可以應(yīng)用在大部分分類器上,無參數(shù)調(diào)節(jié)。
* 缺點(diǎn):對(duì)離群點(diǎn)敏感。
* 適用數(shù)據(jù)類型:數(shù)值型和標(biāo)稱型數(shù)據(jù)。
項(xiàng)目案例: 馬疝病的預(yù)測(cè)
項(xiàng)目流程圖

基于單層決策樹構(gòu)建弱分類器
- 單層決策樹(decision stump, 也稱決策樹樁)是一種簡(jiǎn)單的決策樹。
項(xiàng)目概述
預(yù)測(cè)患有疝氣病的馬的存活問題,這里的數(shù)據(jù)包括368個(gè)樣本和28個(gè)特征,疝氣病是描述馬胃腸痛的術(shù)語,然而,這種病并不一定源自馬的胃腸問題,其他問題也可能引發(fā)疝氣病,該數(shù)據(jù)集中包含了醫(yī)院檢測(cè)馬疝氣病的一些指標(biāo),有的指標(biāo)比較主觀,有的指標(biāo)難以測(cè)量,例如馬的疼痛級(jí)別。另外,除了部分指標(biāo)主觀和難以測(cè)量之外,該數(shù)據(jù)還存在一個(gè)問題,數(shù)據(jù)集中有30%的值是缺失的。
開發(fā)流程
收集數(shù)據(jù):提供的文本文件
準(zhǔn)備數(shù)據(jù):確保類別標(biāo)簽是+1和-1,而非1和0
分析數(shù)據(jù):統(tǒng)計(jì)分析
訓(xùn)練算法:在數(shù)據(jù)上,利用 adaBoostTrainDS() 函數(shù)訓(xùn)練出一系列的分類器
測(cè)試算法:我們擁有兩個(gè)數(shù)據(jù)集。在不采用隨機(jī)抽樣的方法下,我們就會(huì)對(duì) AdaBoost 和 Logistic 回歸的結(jié)果進(jìn)行完全對(duì)等的比較
使用算法:觀察該例子上的錯(cuò)誤率。不過,也可以構(gòu)建一個(gè) Web 網(wǎng)站,讓馴馬師輸入馬的癥狀然后預(yù)測(cè)馬是否會(huì)死去
收集數(shù)據(jù):提供的文本文件
訓(xùn)練數(shù)據(jù):horseColicTraining.txt
測(cè)試數(shù)據(jù):horseColicTest.txt
2.000000 1.000000 38.500000 66.000000 28.000000 3.000000 3.000000 0.000000 2.000000 5.000000 4.000000 4.000000 0.000000 0.000000 0.000000 3.000000 5.000000 45.000000 8.400000 0.000000 0.000000 -1.000000
1.000000 1.000000 39.200000 88.000000 20.000000 0.000000 0.000000 4.000000 1.000000 3.000000 4.000000 2.000000 0.000000 0.000000 0.000000 4.000000 2.000000 50.000000 85.000000 2.000000 2.000000 -1.000000
2.000000 1.000000 38.300000 40.000000 24.000000 1.000000 1.000000 3.000000 1.000000 3.000000 3.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 33.000000 6.700000 0.000000 0.000000 1.000000
準(zhǔn)備數(shù)據(jù):確保類別標(biāo)簽是+1和-1,而非1和0
def loadDataSet(fileName):
# 獲取 feature 的數(shù)量, 便于獲取
numFeat = len(open(fileName).readline().split('\t'))
dataArr = []
labelArr = []
fr = open(fileName)
for line in fr.readlines():
lineArr = []
curLine = line.strip().split('\t')
for i in range(numFeat-1):
lineArr.append(float(curLine[i]))
dataArr.append(lineArr)
labelArr.append(float(curLine[-1]))
return dataArr, labelArr
分析數(shù)據(jù):統(tǒng)計(jì)分析
過擬合(overfitting, 也稱為過學(xué)習(xí))
- 發(fā)現(xiàn)測(cè)試錯(cuò)誤率在達(dá)到一個(gè)最小值之后有開始上升,這種現(xiàn)象稱為過擬合。

- 通俗來說:就是把一些噪音數(shù)據(jù)也擬合進(jìn)去的,如下圖。

訓(xùn)練算法:在數(shù)據(jù)上,利用 adaBoostTrainDS() 函數(shù)訓(xùn)練出一系列的分類器
def adaBoostTrainDS(dataArr, labelArr, numIt=40):
"""adaBoostTrainDS(adaBoost訓(xùn)練過程放大)
Args:
dataArr 特征標(biāo)簽集合
labelArr 分類標(biāo)簽集合
numIt 實(shí)例數(shù)
Returns:
weakClassArr 弱分類器的集合
aggClassEst 預(yù)測(cè)的分類結(jié)果值
"""
weakClassArr = []
m = shape(dataArr)[0]
# 初始化 D,設(shè)置每個(gè)樣本的權(quán)重值,平均分為m份
D = mat(ones((m, 1))/m)
aggClassEst = mat(zeros((m, 1)))
for i in range(numIt):
# 得到?jīng)Q策樹的模型
bestStump, error, classEst = buildStump(dataArr, labelArr, D)
# alpha目的主要是計(jì)算每一個(gè)分類器實(shí)例的權(quán)重(組合就是分類結(jié)果)
# 計(jì)算每個(gè)分類器的alpha權(quán)重值
alpha = float(0.5*log((1.0-error)/max(error, 1e-16)))
bestStump['alpha'] = alpha
# store Stump Params in Array
weakClassArr.append(bestStump)
print "alpha=%s, classEst=%s, bestStump=%s, error=%s " % (alpha, classEst.T, bestStump, error)
# 分類正確:乘積為1,不會(huì)影響結(jié)果,-1主要是下面求e的-alpha次方
# 分類錯(cuò)誤:乘積為 -1,結(jié)果會(huì)受影響,所以也乘以 -1
expon = multiply(-1*alpha*mat(labelArr).T, classEst)
print '(-1取反)預(yù)測(cè)值expon=', expon.T
# 計(jì)算e的expon次方,然后計(jì)算得到一個(gè)綜合的概率的值
# 結(jié)果發(fā)現(xiàn): 判斷錯(cuò)誤的樣本,D對(duì)于的樣本權(quán)重值會(huì)變大。
D = multiply(D, exp(expon))
D = D/D.sum()
# 預(yù)測(cè)的分類結(jié)果值,在上一輪結(jié)果的基礎(chǔ)上,進(jìn)行加和操作
print '當(dāng)前的分類結(jié)果:', alpha*classEst.T
aggClassEst += alpha*classEst
print "疊加后的分類結(jié)果aggClassEst: ", aggClassEst.T
# sign 判斷正為1, 0為0, 負(fù)為-1,通過最終加和的權(quán)重值,判斷符號(hào)。
# 結(jié)果為:錯(cuò)誤的樣本標(biāo)簽集合,因?yàn)槭?!=,那么結(jié)果就是0 正, 1 負(fù)
aggErrors = multiply(sign(aggClassEst) != mat(labelArr).T, ones((m, 1)))
errorRate = aggErrors.sum()/m
# print "total error=%s " % (errorRate)
if errorRate == 0.0:
break
return weakClassArr, aggClassEst
發(fā)現(xiàn):
alpha (模型權(quán)重)目的主要是計(jì)算每一個(gè)分類器實(shí)例的權(quán)重(加和就是分類結(jié)果)
分類的權(quán)重值:最大的值= alpha 的加和,最小值=-最大值
D (樣本權(quán)重)的目的是為了計(jì)算錯(cuò)誤概率: weightedError = D.T*errArr,求最佳分類器
樣本的權(quán)重值:如果一個(gè)值誤判的幾率越小,那么 D 的樣本權(quán)重越小

測(cè)試算法:我們擁有兩個(gè)數(shù)據(jù)集。在不采用隨機(jī)抽樣的方法下,我們就會(huì)對(duì) AdaBoost 和 Logistic 回歸的結(jié)果進(jìn)行完全對(duì)等的比較。
def adaClassify(datToClass, classifierArr):
"""adaClassify(ada分類測(cè)試)
Args:
datToClass 多個(gè)待分類的樣例
classifierArr 弱分類器的集合
Returns:
sign(aggClassEst) 分類結(jié)果
"""
# do stuff similar to last aggClassEst in adaBoostTrainDS
dataMat = mat(datToClass)
m = shape(dataMat)[0]
aggClassEst = mat(zeros((m, 1)))
# 循環(huán) 多個(gè)分類器
for i in range(len(classifierArr)):
# 前提: 我們已經(jīng)知道了最佳的分類器的實(shí)例
# 通過分類器來核算每一次的分類結(jié)果,然后通過alpha*每一次的結(jié)果 得到最后的權(quán)重加和的值。
classEst = stumpClassify(dataMat, classifierArr[i]['dim'], classifierArr[i]['thresh'], classifierArr[i]['ineq'])
aggClassEst += classifierArr[i]['alpha']*classEst
return sign(aggClassEst)
使用算法:觀察該例子上的錯(cuò)誤率。不過,也可以構(gòu)建一個(gè) Web 網(wǎng)站,讓馴馬師輸入馬的癥狀然后預(yù)測(cè)馬是否會(huì)死去。
# 馬疝病數(shù)據(jù)集
# 訓(xùn)練集合
dataArr, labelArr = loadDataSet("input/7.AdaBoost/horseColicTraining2.txt")
weakClassArr, aggClassEst = adaBoostTrainDS(dataArr, labelArr, 40)
print weakClassArr, '\n-----\n', aggClassEst.T
# 計(jì)算ROC下面的AUC的面積大小
plotROC(aggClassEst.T, labelArr)
# 測(cè)試集合
dataArrTest, labelArrTest = loadDataSet("input/7.AdaBoost/horseColicTest2.txt")
m = shape(dataArrTest)[0]
predicting10 = adaClassify(dataArrTest, weakClassArr)
errArr = mat(ones((m, 1)))
# 測(cè)試:計(jì)算總樣本數(shù),錯(cuò)誤樣本數(shù),錯(cuò)誤率
print m, errArr[predicting10 != mat(labelArrTest).T].sum(), errArr[predicting10 != mat(labelArrTest).T].sum()/m
完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/7.AdaBoost/adaboost.py
要點(diǎn)補(bǔ)充
非均衡現(xiàn)象:
在分類器訓(xùn)練時(shí),正例數(shù)目和反例數(shù)目不相等(相差很大)
- 判斷馬是否能繼續(xù)生存(不可誤殺)
- 過濾垃圾郵件(不可漏判)
- 不能放過傳染病的人
- 不能隨便認(rèn)為別人犯罪
ROC 評(píng)估方法
- ROC 曲線: 最佳的分類器應(yīng)該盡可能地處于左上角

- 對(duì)不同的 ROC 曲線進(jìn)行比較的一個(gè)指標(biāo)是曲線下的面積(Area Unser the Curve, AUC).
- AUC 給出的是分類器的平均性能值,當(dāng)然它并不能完全代替對(duì)整條曲線的觀察。
- 一個(gè)完美分類器的 AUC 為1,而隨機(jī)猜測(cè)的 AUC 則為0.5。
代價(jià)函數(shù)
- 基于代價(jià)函數(shù)的分類器決策控制:
TP*(-5)+FN*1+FP*50+TN*0

抽樣
- 欠抽樣(undersampling)或者過抽樣(oversampling)
- 欠抽樣: 意味著刪除樣例
- 過抽樣: 意味著復(fù)制樣例(重復(fù)使用)
- 作者:片刻
- GitHub地址: https://github.com/apachecn/MachineLearning
- 版權(quán)聲明:歡迎轉(zhuǎn)載學(xué)習(xí) => 請(qǐng)標(biāo)注信息來源于 ApacheCN