第7章 集成方法 ensemble method
集成方法: ensemble method(元算法: meta algorithm) 概述
概念:是對其他算法進行組合的一種形式。
通俗來說: 當做重要決定時,大家可能都會考慮吸取多個專家而不只是一個人的意見。
機器學習處理問題時又何嘗不是如此? 這就是集成方法背后的思想。-
集成方法:
- 投票選舉(bagging: 自舉匯聚法 bootstrap aggregating): 是基于數(shù)據(jù)隨機重抽樣分類器構(gòu)造的方法
- 再學習(boosting): 是基于所有分類器的加權(quán)求和的方法
集成方法 場景
目前 bagging 方法最流行的版本是: 隨機森林(random forest)
選男友:美女選擇擇偶對象的時候,會問幾個閨蜜的建議,最后選擇一個綜合得分最高的一個作為男朋友
目前 boosting 方法最流行的版本是: AdaBoost
追女友:3個帥哥追同一個美女,第1個帥哥失敗->(傳授經(jīng)驗:姓名、家庭情況) 第2個帥哥失敗->(傳授經(jīng)驗:興趣愛好、性格特點) 第3個帥哥成功
bagging 和 boosting 區(qū)別是什么?
- bagging 是一種與 boosting 很類似的技術, 所使用的多個分類器的類型(數(shù)據(jù)量和特征量)都是一致的。
- bagging 是由不同的分類器(1.數(shù)據(jù)隨機化 2.特征隨機化)經(jīng)過訓練,綜合得出的出現(xiàn)最多分類結(jié)果;boosting 是通過調(diào)整已有分類器錯分的那些數(shù)據(jù)來獲得新的分類器,得出目前最優(yōu)的結(jié)果。
- bagging 中的分類器權(quán)重是相等的;而 boosting 中的分類器加權(quán)求和,所以權(quán)重并不相等,每個權(quán)重代表的是其對應分類器在上一輪迭代中的成功度。
隨機森林
隨機森林 概述
- 隨機森林指的是利用多棵樹對樣本進行訓練并預測的一種分類器。
- 決策樹相當于一個大師,通過自己在數(shù)據(jù)集中學到的知識用于新數(shù)據(jù)的分類。但是俗話說得好,一個諸葛亮,玩不過三個臭皮匠。隨機森林就是希望構(gòu)建多個臭皮匠,希望最終的分類效果能夠超過單個大師的一種算法。
隨機森林 原理
那隨機森林具體如何構(gòu)建呢?
有兩個方面:
- 數(shù)據(jù)的隨機性化
- 待選特征的隨機化
使得隨機森林中的決策樹都能夠彼此不同,提升系統(tǒng)的多樣性,從而提升分類性能。
數(shù)據(jù)的隨機化:使得隨機森林中的決策樹更普遍化一點,適合更多的場景。
(有放回的準確率在:70% 以上, 無放回的準確率在:60% 以上)
- 采取有放回的抽樣方式 構(gòu)造子數(shù)據(jù)集,保證不同子集之間的數(shù)量級一樣(不同子集/同一子集 之間的元素可以重復)
- 利用子數(shù)據(jù)集來構(gòu)建子決策樹,將這個數(shù)據(jù)放到每個子決策樹中,每個子決策樹輸出一個結(jié)果。
- 然后統(tǒng)計子決策樹的投票結(jié)果,得到最終的分類 就是 隨機森林的輸出結(jié)果。
- 如下圖,假設隨機森林中有3棵子決策樹,2棵子樹的分類結(jié)果是A類,1棵子樹的分類結(jié)果是B類,那么隨機森林的分類結(jié)果就是A類。
待選特征的隨機化
- 子樹從所有的待選特征中隨機選取一定的特征。
- 在選取的特征中選取最優(yōu)的特征。
下圖中,藍色的方塊代表所有可以被選擇的特征,也就是目前的待選特征;黃色的方塊是分裂特征。
左邊是一棵決策樹的特征選取過程,通過在待選特征中選取最優(yōu)的分裂特征(別忘了前文提到的ID3算法,C4.5算法,CART算法等等),完成分裂。
右邊是一個隨機森林中的子樹的特征選取過程。
隨機森林 開發(fā)流程
收集數(shù)據(jù):任何方法
準備數(shù)據(jù):轉(zhuǎn)換樣本集
分析數(shù)據(jù):任何方法
訓練算法:通過數(shù)據(jù)隨機化和特征隨機化,進行多實例的分類評估
測試算法:計算錯誤率
使用算法:輸入樣本數(shù)據(jù),然后運行 隨機森林 算法判斷輸入數(shù)據(jù)分類屬于哪個分類,最后對計算出的分類執(zhí)行后續(xù)處理
隨機森林 算法特點
優(yōu)點:幾乎不需要輸入準備、可實現(xiàn)隱式特征選擇、訓練速度非??臁⑵渌P秃茈y超越、很難建立一個糟糕的隨機森林模型、大量優(yōu)秀、免費以及開源的實現(xiàn)。
缺點:劣勢在于模型大小、是個很難去解釋的黑盒子。
適用數(shù)據(jù)范圍:數(shù)值型和標稱型
項目案例: 聲納信號分類
項目概述
這是 Gorman 和 Sejnowski 在研究使用神經(jīng)網(wǎng)絡的聲納信號分類中使用的數(shù)據(jù)集。任務是訓練一個模型來區(qū)分聲納信號。
開發(fā)流程
收集數(shù)據(jù):提供的文本文件
準備數(shù)據(jù):轉(zhuǎn)換樣本集
分析數(shù)據(jù):手工檢查數(shù)據(jù)
訓練算法:在數(shù)據(jù)上,利用 random_forest() 函數(shù)進行優(yōu)化評估,返回模型的綜合分類結(jié)果
測試算法:在采用自定義 n_folds 份隨機重抽樣 進行測試評估,得出綜合的預測評分
使用算法:若你感興趣可以構(gòu)建完整的應用程序,從案例進行封裝,也可以參考我們的代碼
收集數(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
準備數(shù)據(jù):轉(zhuǎn)換樣本集
# 導入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:
# 添加分類標簽
lineArr.append(str_f)
dataset.append(lineArr)
return dataset
分析數(shù)據(jù):手工檢查數(shù)據(jù)
訓練算法:在數(shù)據(jù)上,利用 random_forest() 函數(shù)進行優(yōu)化評估,返回模型的綜合分類結(jié)果
- 樣本數(shù)據(jù)隨機無放回抽樣-用于交叉驗證
def cross_validation_split(dataset, n_folds):
"""cross_validation_split(將數(shù)據(jù)集進行抽重抽樣 n_folds 份,數(shù)據(jù)可以重復重復抽取)
Args:
dataset 原始數(shù)據(jù)集
n_folds 數(shù)據(jù)集dataset分成n_flods份
Returns:
dataset_split list集合,存放的是:將數(shù)據(jù)集進行抽重抽樣 n_folds 份,數(shù)據(jù)可以重復重復抽取
"""
dataset_split = list()
dataset_copy = list(dataset) # 復制一份 dataset,防止 dataset 的內(nèi)容改變
fold_size = len(dataset) / n_folds
for i in range(n_folds):
fold = list() # 每次循環(huán) fold 清零,防止重復導入 dataset_split
while len(fold) < fold_size: # 這里不能用 if,if 只是在第一次判斷時起作用,while 執(zhí)行循環(huán),直到條件不成立
# 有放回的隨機采樣,有一些樣本被重復采樣,從而在訓練集中多次出現(xiàn),有的則從未在訓練集中出現(xiàn),此則自助采樣法。從而保證每棵決策樹訓練集的差異性
index = randrange(len(dataset_copy))
# 將對應索引 index 的內(nèi)容從 dataset_copy 中導出,并將該內(nèi)容從 dataset_copy 中刪除。
# pop() 函數(shù)用于移除列表中的一個元素(默認最后一個元素),并且返回該元素的值。
fold.append(dataset_copy.pop(index)) # 無放回的方式
# fold.append(dataset_copy[index]) # 有放回的方式
dataset_split.append(fold)
# 由dataset分割出的n_folds個數(shù)據(jù)構(gòu)成的列表,為了用于交叉驗證
return dataset_split
- 訓練數(shù)據(jù)集隨機化
# Create a random subsample from the dataset with replacement
def subsample(dataset, ratio): # 創(chuàng)建數(shù)據(jù)集的隨機子樣本
"""random_forest(評估算法性能,返回模型得分)
Args:
dataset 訓練數(shù)據(jù)集
ratio 訓練數(shù)據(jù)集的樣本比例
Returns:
sample 隨機抽樣的訓練樣本
"""
sample = list()
# 訓練樣本的按比例抽樣。
# round() 方法返回浮點數(shù)x的四舍五入值。
n_sample = round(len(dataset) * ratio)
while len(sample) < n_sample:
# 有放回的隨機采樣,有一些樣本被重復采樣,從而在訓練集中多次出現(xiàn),有的則從未在訓練集中出現(xiàn),此則自助采樣法。從而保證每棵決策樹訓練集的差異性
index = randrange(len(dataset))
sample.append(dataset[index])
return sample
- 特征隨機化
# 找出分割數(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 個特征( n_feature 等于特征數(shù)的根號),特征索引從 dataset 中隨機取
if index not in features:
features.append(index)
for index in features: # 在 n_features 個特征中選出最優(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 為分錯的代價成本
# print b_score
return {'index': b_index, 'value': b_value, 'groups': b_groups}
- 隨機森林
# Random Forest Algorithm
def random_forest(train, test, max_depth, min_size, sample_size, n_trees, n_features):
"""random_forest(評估算法性能,返回模型得分)
Args:
train 訓練數(shù)據(jù)集
test 測試數(shù)據(jù)集
max_depth 決策樹深度不能太深,不然容易導致過擬合
min_size 葉子節(jié)點的大小
sample_size 訓練數(shù)據(jù)集的樣本比例
n_trees 決策樹的個數(shù)
n_features 選取的特征的個數(shù)
Returns:
predictions 每一行的預測結(jié)果,bagging 預測最后的分類結(jié)果
"""
trees = list()
# n_trees 表示決策樹的數(shù)量
for i in range(n_trees):
# 隨機抽樣的訓練樣本, 隨機采樣保證了每棵決策樹訓練集的差異性
sample = subsample(train, sample_size)
# 創(chuàng)建一個決策樹
tree = build_tree(sample, max_depth, min_size, n_features)
trees.append(tree)
# 每一行的預測結(jié)果,bagging 預測最后的分類結(jié)果
predictions = [bagging_predict(trees, row) for row in test]
return predictions
測試算法:在采用自定義 n_folds 份隨機重抽樣 進行測試評估,得出綜合的預測評分。
- 計算隨機森林的預測結(jié)果的正確率
# 評估算法性能,返回模型得分
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
"""evaluate_algorithm(評估算法性能,返回模型得分)
Args:
dataset 原始數(shù)據(jù)集
algorithm 使用的算法
n_folds 數(shù)據(jù)的份數(shù)
*args 其他的參數(shù)
Returns:
scores 模型得分
"""
# 將數(shù)據(jù)集進行隨機抽樣,分成 n_folds 份,數(shù)據(jù)無重復的抽取
folds = cross_validation_split(dataset, n_folds)
scores = list()
# 每次循環(huán)從 folds 從取出一個 fold 作為測試集,其余作為訓練集,遍歷整個 folds ,實現(xiàn)交叉驗證
for fold in folds:
train_set = list(folds)
train_set.remove(fold)
# 將多個 fold 列表組合成一個 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 提取出來的測試集
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]
# 計算隨機森林的預測結(jié)果的正確率
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)
return scores
使用算法:若你感興趣可以構(gòu)建完整的應用程序,從案例進行封裝,也可以參考我們的代碼
完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/7.RandomForest/randomForest.py
AdaBoost
AdaBoost (adaptive boosting: 自適應 boosting) 概述
能否使用弱分類器和多個實例來構(gòu)建一個強分類器? 這是一個非常有趣的理論問題。
AdaBoost 原理
AdaBoost 工作原理
AdaBoost 開發(fā)流程
收集數(shù)據(jù):可以使用任意方法
準備數(shù)據(jù):依賴于所使用的弱分類器類型,本章使用的是單層決策樹,這種分類器可以處理任何數(shù)據(jù)類型。
當然也可以使用任意分類器作為弱分類器,第2章到第6章中的任一分類器都可以充當弱分類器。
作為弱分類器,簡單分類器的效果更好。
分析數(shù)據(jù):可以使用任意方法。
訓練算法:AdaBoost 的大部分時間都用在訓練上,分類器將多次在同一數(shù)據(jù)集上訓練弱分類器。
測試算法:計算分類的錯誤率。
使用算法:通SVM一樣,AdaBoost 預測兩個類別中的一個。如果想把它應用到多個類別的場景,那么就要像多類 SVM 中的做法一樣對 AdaBoost 進行修改。
AdaBoost 算法特點
* 優(yōu)點:泛化(由具體的、個別的擴大為一般的)錯誤率低,易編碼,可以應用在大部分分類器上,無參數(shù)調(diào)節(jié)。
* 缺點:對離群點敏感。
* 適用數(shù)據(jù)類型:數(shù)值型和標稱型數(shù)據(jù)。
項目案例: 馬疝病的預測
項目流程圖
基于單層決策樹構(gòu)建弱分類器
- 單層決策樹(decision stump, 也稱決策樹樁)是一種簡單的決策樹。
項目概述
預測患有疝氣病的馬的存活問題,這里的數(shù)據(jù)包括368個樣本和28個特征,疝氣病是描述馬胃腸痛的術語,然而,這種病并不一定源自馬的胃腸問題,其他問題也可能引發(fā)疝氣病,該數(shù)據(jù)集中包含了醫(yī)院檢測馬疝氣病的一些指標,有的指標比較主觀,有的指標難以測量,例如馬的疼痛級別。另外,除了部分指標主觀和難以測量之外,該數(shù)據(jù)還存在一個問題,數(shù)據(jù)集中有30%的值是缺失的。
開發(fā)流程
收集數(shù)據(jù):提供的文本文件
準備數(shù)據(jù):確保類別標簽是+1和-1,而非1和0
分析數(shù)據(jù):統(tǒng)計分析
訓練算法:在數(shù)據(jù)上,利用 adaBoostTrainDS() 函數(shù)訓練出一系列的分類器
測試算法:我們擁有兩個數(shù)據(jù)集。在不采用隨機抽樣的方法下,我們就會對 AdaBoost 和 Logistic 回歸的結(jié)果進行完全對等的比較
使用算法:觀察該例子上的錯誤率。不過,也可以構(gòu)建一個 Web 網(wǎng)站,讓馴馬師輸入馬的癥狀然后預測馬是否會死去
收集數(shù)據(jù):提供的文本文件
訓練數(shù)據(jù):horseColicTraining.txt
測試數(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
準備數(shù)據(jù):確保類別標簽是+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)計分析
過擬合(overfitting, 也稱為過學習)
- 發(fā)現(xiàn)測試錯誤率在達到一個最小值之后有開始上升,這種現(xiàn)象稱為過擬合。
- 通俗來說:就是把一些噪音數(shù)據(jù)也擬合進去的,如下圖。
訓練算法:在數(shù)據(jù)上,利用 adaBoostTrainDS() 函數(shù)訓練出一系列的分類器
def adaBoostTrainDS(dataArr, labelArr, numIt=40):
"""adaBoostTrainDS(adaBoost訓練過程放大)
Args:
dataArr 特征標簽集合
labelArr 分類標簽集合
numIt 實例數(shù)
Returns:
weakClassArr 弱分類器的集合
aggClassEst 預測的分類結(jié)果值
"""
weakClassArr = []
m = shape(dataArr)[0]
# 初始化 D,設置每個樣本的權(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目的主要是計算每一個分類器實例的權(quán)重(組合就是分類結(jié)果)
# 計算每個分類器的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,不會影響結(jié)果,-1主要是下面求e的-alpha次方
# 分類錯誤:乘積為 -1,結(jié)果會受影響,所以也乘以 -1
expon = multiply(-1*alpha*mat(labelArr).T, classEst)
print '(-1取反)預測值expon=', expon.T
# 計算e的expon次方,然后計算得到一個綜合的概率的值
# 結(jié)果發(fā)現(xiàn): 判斷錯誤的樣本,D對于的樣本權(quán)重值會變大。
D = multiply(D, exp(expon))
D = D/D.sum()
# 預測的分類結(jié)果值,在上一輪結(jié)果的基礎上,進行加和操作
print '當前的分類結(jié)果:', alpha*classEst.T
aggClassEst += alpha*classEst
print "疊加后的分類結(jié)果aggClassEst: ", aggClassEst.T
# sign 判斷正為1, 0為0, 負為-1,通過最終加和的權(quán)重值,判斷符號。
# 結(jié)果為:錯誤的樣本標簽集合,因為是 !=,那么結(jié)果就是0 正, 1 負
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)重)目的主要是計算每一個分類器實例的權(quán)重(加和就是分類結(jié)果)
分類的權(quán)重值:最大的值= alpha 的加和,最小值=-最大值
D (樣本權(quán)重)的目的是為了計算錯誤概率: weightedError = D.T*errArr,求最佳分類器
樣本的權(quán)重值:如果一個值誤判的幾率越小,那么 D 的樣本權(quán)重越小
測試算法:我們擁有兩個數(shù)據(jù)集。在不采用隨機抽樣的方法下,我們就會對 AdaBoost 和 Logistic 回歸的結(jié)果進行完全對等的比較。
def adaClassify(datToClass, classifierArr):
"""adaClassify(ada分類測試)
Args:
datToClass 多個待分類的樣例
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) 多個分類器
for i in range(len(classifierArr)):
# 前提: 我們已經(jīng)知道了最佳的分類器的實例
# 通過分類器來核算每一次的分類結(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)
使用算法:觀察該例子上的錯誤率。不過,也可以構(gòu)建一個 Web 網(wǎng)站,讓馴馬師輸入馬的癥狀然后預測馬是否會死去。
# 馬疝病數(shù)據(jù)集
# 訓練集合
dataArr, labelArr = loadDataSet("input/7.AdaBoost/horseColicTraining2.txt")
weakClassArr, aggClassEst = adaBoostTrainDS(dataArr, labelArr, 40)
print weakClassArr, '\n-----\n', aggClassEst.T
# 計算ROC下面的AUC的面積大小
plotROC(aggClassEst.T, labelArr)
# 測試集合
dataArrTest, labelArrTest = loadDataSet("input/7.AdaBoost/horseColicTest2.txt")
m = shape(dataArrTest)[0]
predicting10 = adaClassify(dataArrTest, weakClassArr)
errArr = mat(ones((m, 1)))
# 測試:計算總樣本數(shù),錯誤樣本數(shù),錯誤率
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
要點補充
非均衡現(xiàn)象:
在分類器訓練時,正例數(shù)目和反例數(shù)目不相等(相差很大)
- 判斷馬是否能繼續(xù)生存(不可誤殺)
- 過濾垃圾郵件(不可漏判)
- 不能放過傳染病的人
- 不能隨便認為別人犯罪
ROC 評估方法
- ROC 曲線: 最佳的分類器應該盡可能地處于左上角
- 對不同的 ROC 曲線進行比較的一個指標是曲線下的面積(Area Unser the Curve, AUC).
- AUC 給出的是分類器的平均性能值,當然它并不能完全代替對整條曲線的觀察。
- 一個完美分類器的 AUC 為1,而隨機猜測的 AUC 則為0.5。
代價函數(shù)
- 基于代價函數(shù)的分類器決策控制:
TP*(-5)+FN*1+FP*50+TN*0
抽樣
- 欠抽樣(undersampling)或者過抽樣(oversampling)
- 欠抽樣: 意味著刪除樣例
- 過抽樣: 意味著復制樣例(重復使用)
- 作者:片刻
- GitHub地址: https://github.com/apachecn/MachineLearning
- 版權(quán)聲明:歡迎轉(zhuǎn)載學習 => 請標注信息來源于 ApacheCN