其他章节答案请参考我的汇总统计学习方法答案汇总,都是自己写的。
因为训练数据实例的维度比书中的例子8.1的实例的维度大,也就是特征的数目比较多,因而需要进行特征选择。我在这里根据数据集里面数据的权重进行特征选择的,如果按照原始数据进行原则,那么除了强制排除已经选择的特征,否则每次构造决策树桩,都只能选择相同的特征进行构造决策树桩,这显然是不合理的。
直接上代码:
import numpy as np
def choose_character_by_data_weight(X,Y,w):
'''
该方法使用数据的每次迭代的权重来选择特征,如果不使用数据的权重的话,每次计算出的特征都是相同的,将无法构造分类树桩
Parameters
----------
X : numpy array
训练数据.
Y : numpy array
数据标签.
w : numpy array
数据的权重.
Returns
-------
最佳的特征.
'''
s = np.shape(X)
char_nums = s[1] ## 特征的个数
## 下面开始计算H(D)
class_ = list(set(Y)) ## 类别集合
H_D = -sum([sum(np.where(Y == c, w, 0.0)) * np.log(sum(np.where(Y == c, w, 0.0))) for c in class_])
## 下面开始计算信息增益比
info_rate = []
for i in range(char_nums):
H_D_i = 0.0
char_i = list(set(X[:, i]))
for ch_i in char_i:
w1 = sum(np.where(X[:, i] == ch_i, w, 0.0))
for c in class_:
w2 = sum(np.where((X[:,i] == ch_i) * (Y == c), w, 0.0)) / w1
if w2 != 0.0:
H_D_i -= w1 * w2 * np.log(w2)
## 下面开始计算特征i的条件经验熵
H_i_D = -sum([sum(np.where(X[:, i] == ch, w, 0.0)) * np.log(sum(np.where(X[:, i] == ch, w, 0.0))) for ch in char_i])
info_rate.append((H_D - H_D_i) / H_i_D)
# print('2 is :', info_rate)
return info_rate.index(max(info_rate))
def create_Tree(X,Y,w):
#首先选择特征
char = choose_character_by_data_weight(X,Y,w) ## 根据权重选择特征
char_val = list(set(X[:, char])) ## 特征的取值
char_val = sorted(char_val)
## 下面开始确定选择特征char的取值才能是误差率最小
best_tree = None
best_loss = 2 ** 15
for i in range(len(char_val) - 1):## 只要循环特征char取值少一个就行啦
tree_i = [] # 使用一个列表表示一个二叉树桩,第0个元素是选择哪个特征来进行分类,第一个元素是决策元素,第二个元素表示当小于时的类别,第三个是大于时的类别
loss_i = 0
ch = (char_val[i] + char_val[i + 1]) / 2 #在已经排序好的特征取值中,取两个相邻特征的中间值就可以了,将其分为两类
# 下面根据数据权重计算损失并且确定决策树桩
Y1 = Y[X[:, char] < ch]
Y2 = Y[X[:, char] > ch]
W1 = w[X[:, char] < ch]
W2 = w[X[:, char] > ch]
n1 = list(set(Y1))
n2 = list(set(Y2))
tree_i.append(char)
tree_i.append(ch)
if len(n1) == 1:
## 此时说明只有一个类别,无需计算每个类别的损失,此时在这个子集上的分类误差是0
tree_i.append(Y1[0])
loss_i += 0
else:
## 此时说明Y1有两个类别,因为权重不是均衡的,不能按照数量的多少进行划分类别
loss_1 = sum(np.where(Y1 != 1, W1, 0)) ## 类别1的损失
loss_2 = sum(np.where(Y1 != -1, W1, 0)) ## 类别-1的损失
if loss_1 >= loss_2:
#此时说明应该取值为-1
tree_i.append(-1)
loss_i += loss_2
else:
tree_i.append(1)
loss_i += loss_1
if len(n2) == 1:
## 此时说明只有一个类别,无需计算每个类别的损失,此时在这个子集上的分类误差是0
tree_i.append(Y2[0])
loss_i += 0
else:
## 此时说明Y1有两个类别,因为权重不是均衡的,不能按照数量的多少进行划分类别
loss_1 = sum(np.where(Y2 != 1, W2, 0)) ## 类别1的损失
loss_2 = sum(np.where(Y2 != -1, W2, 0)) ## 类别-1的损失
if loss_1 >= loss_2:
#此时说明应该取值为-1
tree_i.append(-1)
loss_i += loss_2
else:
tree_i.append(1)
loss_i += loss_1
if loss_i < best_loss:
best_loss = loss_i
best_tree = tree_i
return best_tree, best_loss
def boost(X,Y):
init_w = np.array([0.1] * len(Y)) ## 初始的权重分类,使用原始数据训练一个决策树
all_tree = [] ## 用来存储生成的决策树
all_alpha = [] ## 存储每颗决策树的系数
while True:
tree_i, loss_i = create_Tree(X,Y,init_w) ## 生成一个决策树
alpha = 0.5 * np.log((1-loss_i) / loss_i)
all_tree.append(tree_i)
all_alpha.append(alpha)
## 下面开始计算已经得到决策树是否可以让训练的准确率足够高,这里使用完全正确分类来衡量是否跳出循环
acc = 0
for i in range(len(Y)):
x_i = X[i,:]
f = 0
y_true = Y[i]
for t in range(len(all_alpha)):
a_t = all_alpha[t]
tree_ = all_tree[t]
char = tree_[0]
seg = tree_[1]
label_1 = tree_[2]
label_2 = tree_[3]
if x_i[char] < seg:
f += a_t * label_1
else:
f += a_t * label_2
acc += int(np.sign(f) == y_true)
if (acc / len(Y)) == 1:
return all_tree, all_alpha
## 下面开始更新数据的权重
for i in range(len(Y)):
x_i = X[i,:]
y_true = Y[i]
char = tree_i[0]
seg = tree_i[1]
label1 = tree_i[2]
label2 = tree_i[3]
if x_i[char] < seg:
G = label1
else:
G = label2
init_w[i] = init_w[i] * np.exp(- alpha * y_true * G)
init_w = init_w / sum(init_w)
if __name__ == '__main__':
X = np.array([[0,1,3],
[0,3,1],
[1,2,2],
[1,1,3],
[1,2,3],
[0,1,2],
[1,1,2],
[1,1,1],
[1,3,1],
[0,2,1]])
Y = np.array([-1,-1,-1,-1,-1,-1,1,1,-1,-1])
tree, alpha = boost(X,Y)
学习策略:
由目标函数函数可以看到,支持向量机的学习策略是结构风险极小化
算法有最大间隔方法、对偶算法、软间隔算法,emm,貌似对偶算法和软间隔算法是有相交关系的。
学习策略:经验风险极小化
学习算法:提升树算法等
学习策略:经验风险极小化
算法:极大似然估计法