元算法
元算法(meta-algorithm)是對其他算法進行組合的一種方式。(或稱集成方法,ensemble method)
集成方法的不同形式:
- 不同算法的集成
- 同一算法在不同設置下的集成
- 數據集不同部分分配給不同分類器之後的集成
- 基於同一種分類器在多個不同實例下的集成
bagging:基於數據隨機重抽樣的分類器構建方法
bagging也稱自舉匯聚法(bootstrap aggregating)。
核心思想:假設訓練集有個樣本,從中隨機抽取次,每次有放回的獲取個樣本,用某個單獨的算法對個數據集(每個數據集有個樣本)進行訓練,這樣就可以獲得個分類器,最後通過投票來獲取最後的結果。
隨機森林(Random Forest,RF)是bagging方法的一種,其基於決策樹,不僅對數據隨機化抽取,也對特徵隨機化抽取。
1. 數據的隨機化:利用bootstrap方法有放回地隨機抽取個新的樣本集。
2. 特徵隨機化:個特徵,每棵樹隨機選擇個特徵劃分數據集。
boosting
boosting方法是先在原數據集上訓練出一個分類器,然後將前一個分類器沒能完美分類的數據樣本重新賦權重(weight),用新的權重數據樣本再訓練出一個分類器,以此循環,最終的分類結果由加權投票決定。
- boosting和bagging均使用單個學習算法。
- boosting是串行算法(必須依賴上一個分類器),bagging是並行算法(可以同時進行);
- boosting的分類器權重不同,bagging相同。
boosting:AdaBoost
AdaBoost是boosting最流行的一個版本。
AdaBoost的基礎理論:使用弱分類器和多個實例構建一個強分類器,弱意味着分類器的性能比隨機猜測的要略好,但不會好太多,而強分類器的錯誤率要低很多。
AdaBoost的算法流程:
- 給每個訓練樣本賦權重,這些權重構成向量(初始權重相等,如1000個數據,那每個數據樣本初始權重爲1/1000)。
- 在該數據上訓練一個弱分類器並計算錯誤率和該分類器的權重值(基於每個弱分類器的錯誤率進行計算)。
- 基於該值重新計算權重(分錯的樣本權重變大,分對的權重變小)。
- 循環2,3步,在完成給定的迭代次數或錯誤閾值時,停止循環。
- 最終的分類結果由加權投票決定。
錯誤率:
值的計算:
AdaBoost算法示意圖(來源機器學習是實戰):
計算出值後,可以對權重向量進行更新,以使得那些正確分類的樣本的權重降低而分錯樣本的權重增大。
樣本正確分類,其權重修改爲:
樣本被錯誤分類,其權重修改爲:
基於單層決策樹構建弱分類器
加載數據:
import numpy as np
import matplotlib.pyplot as plt
def read_data():
data = np.array([[1, 2.1], [2, 1.1], [1.3, 1], [1, 1], [2, 1]])
label = [1, 1, -1, -1, 1]
return data,label
if __name__ =="__main__":
data,label = read_data()
x =data[:,0]
y =data[:,1]
# print(x)
plt.scatter(x,y,c=label)
plt.show()```
構建單層決策樹:
```python
import numpy as np
def stump_classify(x, dim, thresh_val, thresh_ineq):
'''
通過閾值比較對數據進行分類。
所有在閾值一邊的數據會分到類別-1,而另一邊的數據會被分類到+1。
通過數組過濾實現。
'''
retArray = np.ones((x.shape[0], 1))
if thresh_ineq == 'lt':
retArray[x[:, dim] <= thresh_val] = -1
else:
retArray[x[:, dim] > thresh_val] = -1
return retArray
def build_stump(x, y, D):
'''
:param x: 輸入數據
:param y: 輸入數據的標籤
:param D: 權重向量
:return:
'''
x_mat = np.matrix(x) # 轉換成矩陣形式
y_mat = np.matrix(y).T
m, n = x.shape
num_steps = 10
best_stump = {}
best_class_est = np.matrix(np.zeros((m, 1)))
min_err = np.inf
for i in range(n): # 遍歷所有特徵
row_min = x_mat[:, i].min()
row_max = x_mat[:, i].max()
step_size = (row_max - row_min) / num_steps
for j in range(-1, num_steps + 1):
for eq in ['lt', 'gt']:
thresh_val = row_min + j * step_size
pre_val = stump_classify(x, i, thresh_val, eq)
err_arr = np.matrix(np.ones((m, 1)))
err_arr[pre_val == y_mat] = 0
weight_err = D.T * err_arr
print("split: dim %d, thresh %.2f, thresh ineqal: %s, "
"the weighted error is %.3f"
% (i, thresh_val, eq, weight_err))
if weight_err < min_err:
min_err = weight_err
best_class_est = pre_val.copy()
best_stump['dim'] = i
best_stump['thresh'] = thresh_val
best_stump['ineq'] = eq
return best_stump, min_err, best_class_est
分類實現代碼:
import numpy as np
from stump import *
def adaboost_trian(x, y, num_it=40):
week_class_arr = []
m = x.shape[0]
D = np.matrix(np.ones((m, 1)) / m) # 初始化權重向量D
agg_class_est = np.matrix(np.zeros((m, 1)))
for i in range(num_it):
best_stump, err, class_est = build_stump(x, y, D)
print('D: ', D.T)
alpha = 0.5 * np.log((1 - err) // max(err, 1e-16)) # 計算alpha值
best_stump['alpha'] = alpha
week_class_arr.append(best_stump)
print('class_est: ', class_est.T)
expon = np.multiply(np.matrix(-1 * alpha * y).T, class_est)
D = np.multiply(D, np.exp(expon))
D = D / np.sum(D)
agg_class_est += np.multiply(alpha, class_est)
print('agg_class_est: ', agg_class_est.T)
agg_err = np.multiply(np.sign(agg_class_est) != np.matrix(y).T, np.ones((m, 1)))
err_rate = np.sum(agg_err) / m
print('total error: ', err_rate, '\n')
if err_rate == 0:
break
return week_class_arr
def adaClassify(test, classifierArr):
dataMatrix = np.matrix(test) # do stuff similar to last aggClassEst in adaBoostTrainDS
m = dataMatrix.shape[0]
aggClassEst = np.matrix(np.zeros((m, 1)))
for i in range(len(classifierArr)):
classEst = stump_classify(dataMatrix, classifierArr[i]['dim'],
classifierArr[i]['thresh'],
classifierArr[i]['ineq']) # call stump classify
aggClassEst += np.multiply(classifierArr[i]['alpha'], classEst)
print(aggClassEst)
return np.sign(aggClassEst)
測試代碼:
from adaboost import adaboost_trian,adaClassify
from load_data import read_data
if __name__ =='__main__':
data,label = read_data()
classifier_array = adaboost_trian(data,label,9)
# print(classifier_array)
re = adaClassify([[5,5],[0,0]],classifier_array)
print(re)```