本文根据最近学习机器学习书籍网络文章的情况,特将一些学习思路做了归纳整理,详情如下.如有不当之处,请各位大拿多多指点,在此谢过。
(未添加文章标签,特此补上,2018.1.14记。)
1、概念理解
集成学习方法是指组合多个模型,以获得更好的效果,使集成的模型具有更强的泛化能力。对于多个模型,如何组合这些模型,主要有以下几种不同的方法
集成学习在机器学习算法中具有较高的准去率,不足之处就是模型的训练过程可能比较复杂,效率不是很高。目前接触较多的集成学习主要有2种:基于Boosting的和基于Bagging,前者的代表算法有Adaboost、GBDT、XGBOOST、后者的代表算法主要是随机森林。
2、主要思想
通俗地来说,当一个项目做出重大决定时,当事人可能会考虑吸取多个专家而不是一个专家的意见,同理,机器学习也是一样的做法。
书面语言:集成学习的主要思想是利用一定的手段学习出多个分类器,而且这多个分类器要求是弱分类器,然后将多个分类器进行组合公共预测。核心思想就是如何训练处多个弱分类器以及如何将这些弱分类器进行组合。
3、集成方法
1、投票选举(bagging: 自举汇聚法 bootstrap aggregating)
是基于数据随机重抽样分类器构造的方法。以bagging方法最流行的版本--随机森林(random forest)为例:
一个美女正在选择男友,她让自己的10个闺蜜都给出每个男生的综合评分,最终选择了一个综合评分最高的男生作为自己的男友。
2、再学习(boosting)
是基于所有分类器的加权求和的方法。 以boosting方法最流行的版本--AdaBoost算法为例:
四个帅哥追同一个美女
第一个帅哥失败-->(传授经验:姓名、身高、五官、皮肤、家庭);第二个帅哥失败-->(传授经验: 兴趣爱好、日常习惯、性格特点);第三个帅哥失败-->(传授经验:择偶要求、未来规划、理想生活方式);第四个帅哥成功。
3、bagging和boost的区别
随机森林的构建有两个方面:样本的随机化、待分类特征的随机化。使得随机森林中的决策都彼此不同,增加系统的多样性,以此提升分类的性能。
1、数据(样本)的随机化
使得随机森林中的决策更加普遍化一些,以便适合更多的场景。一般情况下,有放回的准确率在70%以上,无放回的准确率在60%以上。
2、待选特征的随机化
下图中,蓝色的方块代表所有可以被选择的特征,也就是目前的待选特征;黄色的方块是分裂特征。
左边是一棵决策树的特征选取过程,通过在待选特征中选取最优的分裂特征(别忘了前文提到的ID3算法,C4.5算法,CART算法等等),完成分裂。
右边是一个随机森林中的子树的特征选取过程。
3、随机森林开发的流程
4、随机森林算法的特点
1、项目概述
采用 Gorman 和 Sejnowski 在研究使用神经网络的声纳信号分类中使用的数据集(sonar-all-data.txt),目标是使用训练算法得到一个模型以便区分声呐信号。
2、开发流程
3、样本数据集样式
收集数据: 提供的样本数据集
0.0286 0.0453 0.0277 0.0174 0.0384 0.099 0.1201 0.1833 0.2105 0.3039 0.2988 0.425 0.6343 0.8198 1 0.9988 0.9508 0.9025 0.7234 0.5122 0.2074 0.3985 0.589 0.2872 0.2043 0.5782 0.5389 0.375 0.3411 0.5067 0.558 0.4778 0.3299 0.2198 0.1407 0.2856 0.3807 0.4158 0.4054 0.3296 0.2707 0.265 0.0723 0.1238 0.1192 0.1089 0.0623 0.0494 0.0264 0.0081 0.0104 0.0045 0.0014 0.0038 0.0013 0.0089 0.0057 0.0027 0.0051 0.0062 R
0.0317 0.0956 0.1321 0.1408 0.1674 0.171 0.0731 0.1401 0.2083 0.3513 0.1786 0.0658 0.0513 0.3752 0.5419 0.544 0.515 0.4262 0.2024 0.4233 0.7723 0.9735 0.939 0.5559 0.5268 0.6826 0.5713 0.5429 0.2177 0.2149 0.5811 0.6323 0.2965 0.1873 0.2969 0.5163 0.6153 0.4283 0.5479 0.6133 0.5017 0.2377 0.1957 0.1749 0.1304 0.0597 0.1124 0.1047 0.0507 0.0159 0.0195 0.0201 0.0248 0.0131 0.007 0.0138 0.0092 0.0143 0.0036 0.0103 R
0.0519 0.0548 0.0842 0.0319 0.1158 0.0922 0.1027 0.0613 0.1465 0.2838 0.2802 0.3086 0.2657 0.3801 0.5626 0.4376 0.2617 0.1199 0.6676 0.9402 0.7832 0.5352 0.6809 0.9174 0.7613 0.822 0.8872 0.6091 0.2967 0.1103 0.1318 0.0624 0.099 0.4006 0.3666 0.105 0.1915 0.393 0.4288 0.2546 0.1151 0.2196 0.1879 0.1437 0.2146 0.236 0.1125 0.0254 0.0285 0.0178 0.0052 0.0081 0.012 0.0045 0.0121 0.0097 0.0085 0.0047 0.0048 0.0053 R
0.0223 0.0375 0.0484 0.0475 0.0647 0.0591 0.0753 0.0098 0.0684 0.1487 0.1156 0.1654 0.3833 0.3598 0.1713 0.1136 0.0349 0.3796 0.7401 0.9925 0.9802 0.889 0.6712 0.4286 0.3374 0.7366 0.9611 0.7353 0.4856 0.1594 0.3007 0.4096 0.317 0.3305 0.3408 0.2186 0.2463 0.2726 0.168 0.2792 0.2558 0.174 0.2121 0.1099 0.0985 0.1271 0.1459 0.1164 0.0777 0.0439 0.0061 0.0145 0.0128 0.0145 0.0058 0.0049 0.0065 0.0093 0.0059 0.0022 R
0.0164 0.0173 0.0347 0.007 0.0187 0.0671 0.1056 0.0697 0.0962 0.0251 0.0801 0.1056 0.1266 0.089 0.0198 0.1133 0.2826 0.3234 0.3238 0.4333 0.6068 0.7652 0.9203 0.9719 0.9207 0.7545 0.8289 0.8907 0.7309 0.6896 0.5829 0.4935 0.3101 0.0306 0.0244 0.1108 0.1594 0.1371 0.0696 0.0452 0.062 0.1421 0.1597 0.1384 0.0372 0.0688 0.0867 0.0513 0.0092 0.0198 0.0118 0.009 0.0223 0.0179 0.0084 0.0068 0.0032 0.0035 0.0056 0.004 R
0.0039 0.0063 0.0152 0.0336 0.031 0.0284 0.0396 0.0272 0.0323 0.0452 0.0492 0.0996 0.1424 0.1194 0.0628 0.0907 0.1177 0.1429 0.1223 0.1104 0.1847 0.3715 0.4382 0.5707 0.6654 0.7476 0.7654 0.8555 0.972 0.9221 0.7502 0.7209 0.7757 0.6055 0.5021 0.4499 0.3947 0.4281 0.4427 0.3749 0.1972 0.0511 0.0793 0.1269 0.1533 0.069 0.0402 0.0534 0.0228 0.0073 0.0062 0.0062 0.012 0.0052 0.0056 0.0093 0.0042 0.0003 0.0053 0.0036 R
0.0123 0.0309 0.0169 0.0313 0.0358 0.0102 0.0182 0.0579 0.1122 0.0835 0.0548 0.0847 0.2026 0.2557 0.187 0.2032 0.1463 0.2849 0.5824 0.7728 0.7852 0.8515 0.5312 0.3653 0.5973 0.8275 1 0.8673 0.6301 0.4591 0.394 0.2576 0.2817 0.2641 0.2757 0.2698 0.3994 0.4576 0.394 0.2522 0.1782 0.1354 0.0516 0.0337 0.0894 0.0861 0.0872 0.0445 0.0134 0.0217 0.0188 0.0133 0.0265 0.0224 0.0074 0.0118 0.0026 0.0092 0.0009 0.0044 R
0.0079 0.0086 0.0055 0.025 0.0344 0.0546 0.0528 0.0958 0.1009 0.124 0.1097 0.1215 0.1874 0.3383 0.3227 0.2723 0.3943 0.6432 0.7271 0.8673 0.9674 0.9847 0.948 0.8036 0.6833 0.5136 0.309 0.0832 0.4019 0.2344 0.1905 0.1235 0.1717 0.2351 0.2489 0.3649 0.3382 0.1589 0.0989 0.1089 0.1043 0.0839 0.1391 0.0819 0.0678 0.0663 0.1202 0.0692 0.0152 0.0266 0.0174 0.0176 0.0127 0.0088 0.0098 0.0019 0.0059 0.0058 0.0059 0.0032 R
0.009 0.0062 0.0253 0.0489 0.1197 0.1589 0.1392 0.0987 0.0955 0.1895 0.1896 0.2547 0.4073 0.2988 0.2901 0.5326 0.4022 0.1571 0.3024 0.3907 0.3542 0.4438 0.6414 0.4601 0.6009 0.869 0.8345 0.7669 0.5081 0.462 0.538 0.5375 0.3844 0.3601 0.7402 0.7761 0.3858 0.0667 0.3684 0.6114 0.351 0.2312 0.2195 0.3051 0.1937 0.157 0.0479 0.0538 0.0146 0.0068 0.0187 0.0059 0.0095 0.0194 0.008 0.0152 0.0158 0.0053 0.0189 0.0102 R
0.0124 0.0433 0.0604 0.0449 0.0597 0.0355 0.0531 0.0343 0.1052 0.212 0.164 0.1901 0.3026 0.2019 0.0592 0.239 0.3657 0.3809 0.5929 0.6299 0.5801 0.4574 0.4449 0.3691 0.6446 0.894 0.8978 0.498 0.3333 0.235 0.1553 0.3666 0.434 0.3082 0.3024 0.4109 0.5501 0.4129 0.5499 0.5018 0.3132 0.2802 0.2351 0.2298 0.1155 0.0724 0.0621 0.0318 0.045 0.0167 0.0078 0.0083 0.0057 0.0174 0.0188 0.0054 0.0114 0.0196 0.0147 0.0062 R
def loadDataSet(filename):
dataSet = []
with open(filename, 'r') as fs:
for line in fs.readlines():
if not line:
contine
lineArr = []
for feature in line.split(','):
str_f = feature.strip()
if str_f. isdigit():
lineArr.append(float(str_f))
else:
#添加分类标签
lineArr.append(str_f)
dataSet.append(lineArr)
return dataSet
6、 训练算法
在数据集上使用random_forest()函数进行优化评估,返回模型的综合分类结果。
def cross_validation_split(dataset, n_flods):
dataset_split = list()
dataset_copy = list(dataset)
fold_size = len(dataset)/n_folds
for i in range(n_folds):
#每次循环fold清零,防止重复导入dataset_split
fold = list()
while len(fold) < fold_size:
index = randrange(len(dataset_copy))
fold.append(dataset_copy[index])
#foled.append(dataset_copy[index])
dataset_split.append(fold)
return dataset_split
#Create a random subsample ffrom the dataset with replacement.
def subsample(dataset, ratio): # 创建数据集的随机子样本
"""random_forest(评估算法性能,返回模型得分)
Args:
dataset 训练数据集
ratio 训练数据集的样本比例
Returns:
sample 随机抽样的训练样本
"""
sample = list()
# 训练样本的按比例抽样。
# round() 方法返回浮点数x的四舍五入值。
n_sample = round(len(dataset) * ratio)
while len(sample) < n_sample:
index = randrange(len(dataset))
sample.append(dataset[index])
return sample
def get_split(dataset, n_features):
class_values = list(set(row[-1] for row in dataset))
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)
if index not in features:
features.append(index)
for index in features:
for row in dataset:
groups = test_split(index, row[index], dataset)
gini = gini_index(groups, class_values)
if gini < b_score:
b_index, b_value, b_score, b_groups = index, row[index], gini, groups
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):
trees = list()
for i in range(n_trees):
sample = subsample(train, sample_size)#随机抽样的训练样本,随机采样保证每个决策树训练集的差异性。
tree = build_tree(sample,max_depth, min_size, n_features) #创建一个决策树
trees.append(tree)
predictions = [bagging_predict(trees, row) for row in test] #每一行的预测结果,bagging预测最后的分类结果
return predictions
7、测试算法
使用自定义的n_folds份随机重抽样,进行测试评估,得到预测的综合评分情况。那么,显然是计算随机森林预测的结果的正确率情况。
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
#将数据集随机抽样,分成n_folds份,数据无重复抽取
folds = cross_validation_split(dataset, n_folds)
scores = list()
#每次循环从folds中选取一个fold作为训练数据集,遍历整个folds,进行交叉验证。
for fold in folds:
#将多个fold列表组成一个train_set列表
train_set = list(folds)
train_set.remove(fold)
train_set = sum(train_set,[])
test_set = list()
#fold表示从原始数据集中提取出来的测试集
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]
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)
return scores
构建完整的程序,进行测试集数据分类预测。其余代码如下:
from random import seed, randrange, random
#Split a dataset based on an attribute and an attributed value.
def test_split(index, value ,dataset):
left, right = list(), list()
for row in dataset:
if row[index] < value:
left.append(row)
else:
right.append(row)
return left ,right
#Calculate the Gini index for a split dataset
def gini_index(groups, class_values):
gini = 0.0
for class_value in class_values:
for group in groups:
size = len(group)
if size == 0:
continue
proporation = [row[-1] for row in group].count(class_value)/float(size)
gini += (proporation*(1-proporation))
return gini
#Create a terminal node value ,输出group中出现次数较多的标签。
def to_terminal(group):
outcomes = [row[-1] for row in group]
return max(set(outcomes), key = outcomes.count)
#Create child split for a node of make terminal,创建子分类器,递归分类,直到分类结束。
def split(node, max_depth, min_size, n_features, depth):
left, right = node['groups']
# Check for a no split
if not left or right :
node['left'] = node['right'] = to_terminal(left + right)
return
#check for max depth ,max_depth =10 表示递归10次,若分类还没结束,则选数据分类标签较多的作为结果,使分类提前结束,防止过拟合。
if depth >= max_depth:
node['left'] , node['right'] = to_terminal(left), to_terminal(right)
return
# process left child
if len(left) <= min_size:
node['left'] = to_terminal(left)
else:
node['left'] = get_split(left, n_features)
split(node['left'], max_depth, min_size, n_features, detph+1)
#Build a decision tree.
def build_tree(train, max_depth, min_size, n_features):
"""
build_tree(创建一个决策树)
Args:
train--训练数据集; max_depth--决策树深度不能太深,否则会容易导致过拟合;min_size--叶子节点大小; n_features--选取特征的个数
Returns:
root --返回决策树.
"""
#返回最优列和相关信息。
root = get_split(train, n_features)
split(root, max_depth, min_size, n_features, 1)
return root
# Make a prediction with a decision tree.
def predict(node, row):
if row[node['index']] < node['value']:
if isinstance(node['left'], dict):
return predict(node['left'], row)
else:
return node['left']
else:
if isinstance(node['right'], dict):
return predict(node['right'],row)
else:
return node['right']
#Make a decision with a list of bagged trees.
def bagging_predict(trees, row):
"""
bagging_predict(bagging预测)
Args:
trees--决策树集合; row--测试数据集的每一行数据。
Returns:
返回随机森林中决策树结果做大的那个。
"""
# 使用多个决策树对测试集test第row行进行预测,再使用简单投票法判断出该行属于哪一个分类。
predictions = [predict(tree, row) for tree in trees]
return max(set(predictions), key = predictions.count)
#Create a accuracy percentage.
def accuracy_metric(actual, predicted):
#导入实际值和预测值,计算精确度。
correct = 0
for i in range(len(actual)):
if actual[i] == predicted[i]:
correct += 1
return correct/float(len(actual))*100.0
# 加载数据
if __name__ == '__main__':
# 加载数据
dataset = loadDataSet('sonar-all-data.txt')
# print dataset
n_folds = 5 # 分成5份数据,进行交叉验证
max_depth = 20 # 调参(自己修改) #决策树深度不能太深,不然容易导致过拟合
min_size = 1 # 决策树的叶子节点最少的元素数量
sample_size = 1.0 # 做决策树时候的样本的比例
# n_features = int((len(dataset[0])-1))
n_features = 15 # 调参(自己修改) #准确性与多样性之间的权衡
for n_trees in [1, 10, 20]: # 理论上树是越多越好
scores = evaluate_algorithm(dataset, random_forest, n_folds, max_depth, min_size, sample_size, n_trees, n_features)
# 每一次执行本文件时都能产生同一个随机数
seed(1)
print('random=', random())
print('Trees: %d' % n_trees)
print('Scores: %s' % scores)
print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores))))
如下:
random= 0.13436424411240122
Trees: 1
Scores: [50.0, 52.38095238095239, 47.61904761904761, 50.0, 47.61904761904761]
random= 0.13436424411240122
Trees: 10
Scores: [61.904761904761905, 59.523809523809526, 64.28571428571429, 66.66666666666666, 45.23809523809524]
random= 0.13436424411240122
Trees: 20
Scores: [61.904761904761905, 59.523809523809526, 64.28571428571429, 66.66666666666666, 45.23809523809524]
Mean Accuracy: 59.524%
1、adaBoost算法概述
AdaBoot是adaptive boosting(自适应boosting)的缩写,运行机制如下:
训练数据中的每个样本,并赋予一个权重,这些权重共同构成了向量D。起初,这些权重全部被初始化成相等值。首先,在训练数据集上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练中,每个样本的权重会被重新调整,其中第一次分对的样本权重会下降,第一次分错的样本的权重被提高。为了从所有若分类器中得到最终的分类结果,AdaBoost给每个分类器都分配了一个权重值alpha,这些alpha的值是基于每个弱分类器的错误率进行计算的,alpha可以理解为弱分类器中的“话语权”。
2、 AdaBoost工作原理
3、 AdaBoost开发流程
收集数据: 可以使用任意方法。
准备数据: 依赖于所使用的弱分类器类型,本文使用单层决策树,这种分类器可以处理任何数据类型。当然也可以使用任意分类器作为弱分类器。作为弱分类器,简单分类器的效果更好。
分析数据: 可以使用任意方法。
训练算法: AdaBoost大部分时间都用在训练上,分类器将多次在同一数据集上训练弱分类器。
测试算法: 计算分类的错误率。
使用算法: 同SVM一样,AdaBoost预测两个类别中的一个。若想把它应用到多个类别场合,则就要像多类SVM中的做法一样对AdaBoost进行修改。
4、 AdaBoost的相关特性
优点: 泛化错误率低,易编码,可以应用在大部分分类器上,无需调参。
缺点: 对离群点敏感。
适用数据类型: 数值型和标称型数据。
5、 完整AdaBoost算法的实现
伪代码如下:
对每次迭代:
利用buildStump()函数找到最佳的单层决策树
将最佳单层决策树加入到单层决策树组
计算alpha
计算新的权重向量D
更新累计类别估计值
若错误率等于0.0,则退出循环。
6、 过拟合(overfitting,或过学习)
如 上表测试错误率一栏所示,可以发现测试错误率在达到一个最小值之后又开始上升,这类现象称之为“过拟合(overfitting,也称过学习)”。说的直白些,过拟合就是把一些噪声也拟合进去了。如下图所示:
7、 ROC曲线
ROC(receiver operating characteristic)曲线用于度量分类中的非均衡性,最早在二战期间由电气工程师构建雷达系统时使用的。
1、项目概述
预测患有疝气病的马的存活问题,这里的数据包括368个样本和28个特征,疝气病是描述马胃肠痛的术语,然而,这种病并不一定源自马的胃肠问题,其他问题也可能引发疝气病,该数据集中包含了医院检测马疝气病的一些指标,有的指标比较主观,有的指标难以测量,例如马的疼痛级别。另外,除了部分指标主观和难以测量之外,该数据还存在一个问题,数据集中有30%的值是缺失的。
2、项目流程
3、 开发流程
收集数据: 提供的文本文件
准备数据: 确保类别标签为+1和-1,而非1和0.
分析数据: 手工检查数据。
训练算法: 在数据上,使用adaBoostTrainDS()函数训练一系列的分类器。
测试算法: 这里有两个数据集。在不采用随机抽样的情况下,对AdaBoost和Logistic回归的结果进行完全对等的比较。
使用算法: 观察该例子上的错误率。
4、 收集数据--提供的文本文件
训练数据:horseColicTraining.txt和 测试数据:horseColicTest.txt,以训练数据集为例,部分数据如下:
2 1 37.5 48 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 37.6 64 21 1 1 2 1 2 3 1 1 1 0 2 5 40 7 1 0 1
2 1 39.4 110 35 4 3 6 0 0 3 3 0 0 0 0 0 55 8.7 0 0 1
1 1 39.9 72 60 1 1 5 2 5 4 4 3 1 0 4 4 46 6.1 2 0 1
2 1 38.4 48 16 1 0 1 1 1 3 1 2 3 5.5 4 3 49 6.8 0 0 1
1 1 38.6 42 34 2 1 4 0 2 3 1 0 0 0 1 0 48 7.2 0 0 1
1 9 38.3 130 60 0 3 0 1 2 4 0 0 0 0 0 0 50 70 0 0 1
1 1 38.1 60 12 3 3 3 1 0 4 3 3 2 2 0 0 51 65 0 0 1
2 1 37.8 60 42 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 38.3 72 30 4 3 3 2 3 3 3 2 1 0 3 5 43 7 2 3.9 1
1 1 37.8 48 12 3 1 1 1 0 3 2 1 1 0 1 3 37 5.5 2 1.3 1
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1
5、准备数据
类别标签为+1和-1而非1和0。
# general function to parse tab -delimited floats
def loadDataSet(fileName):
# get number of fields
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
7、训练算法
def adaBoostTrainDS(dataArr, labelArr, numIt=40):
"""adaBoostTrainDS(adaBoost训练过程放大)
Args:
dataArr 特征标签集合
labelArr 分类标签集合
numIt 实例数
Returns:
weakClassArr 弱分类器的集合
aggClassEst 预测的分类结果值
"""
weakClassArr = []
m = shape(dataArr)[0]
D = mat(ones((m, 1))/m)
aggClassEst = mat(zeros((m, 1)))
for i in range(numIt):
# 得到决策树的模型
bestStump, error, classEst = buildStump(dataArr, labelArr, D)
alpha = float(0.5*log((1.0-error)/max(error, 1e-16)))
bestStump['alpha'] = alpha
# store Stump Params in Array
weakClassArr.append(bestStump)
expon = multiply(-1*alpha*mat(labelArr).T, classEst)
D = multiply(D, exp(expon))
D = D/D.sum()
aggClassEst += alpha*classEst
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
def adaClassify(datToClass, classifierArr):
# do stuff similar to last aggClassEst in adaBoostTrainDS
dataMat = mat(datToClass)
m = shape(dataMat)[0]
aggClassEst = mat(zeros((m, 1)))
# 循环 多个分类器
for i in range(len(classifierArr)):
classEst = stumpClassify(dataMat, classifierArr[i]['dim'], classifierArr[i]['thresh'], classifierArr[i]['ineq'])
aggClassEst += classifierArr[i]['alpha']*classEst
# print aggClassEst
return sign(aggClassEst)
if __name__ == "__main__":
dataArr, labelArr = loadDataSet("horseColicTraining2.txt")
weakClassArr, aggClassEst = adaBoostTrainDS(dataArr, labelArr, 40)
print(weakClassArr, '\n-----\n', aggClassEst.T)
# 计算ROC下面的AUC的面积大小
plotROC(aggClassEst.T, labelArr)
# 测试集合
dataArrTest, labelArrTest = loadDataSet("horseColicTest2.txt")
m = shape(dataArrTest)[0]
predicting10 = adaClassify(dataArrTest, weakClassArr)
errArr = mat(ones((m, 1)))
# 测试:计算总样本数,错误样本数,错误率
print(m, errArr[predicting10 != mat(labelArrTest).T].sum(), errArr[predicting10 != mat(labelArrTest).T].sum()/m)
from numpy import *
def loadSimpData():
""" 测试数据
Returns:
dataArr feature对应的数据集
labelArr feature对应的分类标签
"""
dataArr = array([[1., 2.1], [2., 1.1], [1.3, 1.], [1., 1.], [2., 1.]])
labelArr = [1.0, 1.0, -1.0, -1.0, 1.0]
return dataArr, labelArr
def stumpClassify(dataMat, dimen, threshVal, threshIneq):
"""stumpClassify(将数据集,按照feature列的value进行 二分法切分比较来赋值分类)
Args:
dataMat Matrix数据集
dimen 特征列
threshVal 特征列要比较的值
Returns:
retArray 结果集
"""
# 默认都是1
retArray = ones((shape(dataMat)[0], 1))
if threshIneq == 'lt':
retArray[dataMat[:, dimen] <= threshVal] = -1.0
else:
retArray[dataMat[:, dimen] > threshVal] = -1.0
return retArray
def buildStump(dataArr, labelArr, D):
"""buildStump(得到决策树的模型)
Args:
dataArr 特征标签集合
labelArr 分类标签集合
D 最初的特征权重值
Returns:
bestStump 最优的分类器模型
minError 错误率
bestClasEst 训练后的结果集
"""
# 转换数据
dataMat = mat(dataArr)
labelMat = mat(labelArr).T
# m行 n列
m, n = shape(dataMat)
# 初始化数据
numSteps = 10.0
bestStump = {}
bestClasEst = mat(zeros((m, 1)))
# 初始化的最小误差为无穷大
minError = inf
# 循环所有的feature列,将列切分成 若干份,每一段以最左边的点作为分类节点
for i in range(n):
rangeMin = dataMat[:, i].min()
rangeMax = dataMat[:, i].max()
stepSize = (rangeMax-rangeMin)/numSteps
for j in range(-1, int(numSteps)+1):
# go over less than and greater than
for inequal in ['lt', 'gt']:
threshVal = (rangeMin + float(j) * stepSize)
predictedVals = stumpClassify(dataMat, i, threshVal, inequal)
errArr = mat(ones((m, 1)))
# 正确为0,错误为1
errArr[predictedVals == labelMat] = 0
weightedError = D.T*errArr
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
def plotROC(predStrengths, classLabels):
"""plotROC(打印ROC曲线,并计算AUC的面积大小)
Args:
predStrengths 最终预测结果的权重值
classLabels 原始数据的分类结果集
"""
import matplotlib.pyplot as plt
# variable to calculate AUC
ySum = 0.0
numPosClas = sum(array(classLabels)==1.0)
yStep = 1/float(numPosClas)
xStep = 1/float(len(classLabels)-numPosClas)
sortedIndicies = predStrengths.argsort()
fig = plt.figure()
fig.clf()
ax = plt.subplot(111)
# cursor光标值
cur = (1.0, 1.0)
# loop through all the values, drawing a line segment at each point
for index in sortedIndicies.tolist()[0]:
if classLabels[index] == 1.0:
delX = 0
delY = yStep
else:
delX = xStep
delY = 0
ySum += cur[1]
ax.plot([cur[0], cur[0]-delX], [cur[1], cur[1]-delY], c='b')
cur = (cur[0]-delX, cur[1]-delY)
ax.plot([0, 1], [0, 1], 'b--')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve for AdaBoost horse colic detection system')
ax.axis([0, 1, 0, 1])
plt.show()
print("the Area Under the Curve is: ", ySum*xStep)
[{'dim': 9, 'thresh': 3.0, 'ineq': 'gt', 'alpha': 0.4616623792657674}, {'dim': 17, 'thresh': 52.5, 'ineq': 'gt', 'alpha': 0.31248245042467104}, {'dim': 3, 'thresh': 55.199999999999996, 'ineq': 'gt', 'alpha': 0.2868097320169577}, {'dim': 18, 'thresh': 62.300000000000004, 'ineq': 'lt', 'alpha': 0.23297004638939506}, {'dim': 10, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.19803846151213741}, {'dim': 5, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.18847887349020634}, {'dim': 12, 'thresh': 1.2, 'ineq': 'lt', 'alpha': 0.15227368997476778}, {'dim': 7, 'thresh': 1.2, 'ineq': 'gt', 'alpha': 0.15510870821690512}, {'dim': 5, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.13536197353359405}, {'dim': 4, 'thresh': 28.799999999999997, 'ineq': 'lt', 'alpha': 0.12521587326132078}, {'dim': 11, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.1334764812820767}, {'dim': 9, 'thresh': 4.0, 'ineq': 'lt', 'alpha': 0.1418224325377107}, {'dim': 14, 'thresh': 0.0, 'ineq': 'gt', 'alpha': 0.10264268449708028}, {'dim': 0, 'thresh': 1.0, 'ineq': 'lt', 'alpha': 0.11883732872109484}, {'dim': 4, 'thresh': 19.199999999999999, 'ineq': 'gt', 'alpha': 0.09879216527106625}, {'dim': 2, 'thresh': 36.719999999999999, 'ineq': 'lt', 'alpha': 0.12029960885056867}, {'dim': 3, 'thresh': 92.0, 'ineq': 'lt', 'alpha': 0.10846927663989175}, {'dim': 15, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.09652967982091411}, {'dim': 3, 'thresh': 73.599999999999994, 'ineq': 'gt', 'alpha': 0.08958515309272022}, {'dim': 18, 'thresh': 8.9000000000000004, 'ineq': 'lt', 'alpha': 0.09210361961272426}, {'dim': 16, 'thresh': 4.0, 'ineq': 'gt', 'alpha': 0.10464142217079622}, {'dim': 11, 'thresh': 3.2000000000000002, 'ineq': 'lt', 'alpha': 0.09575457291711606}, {'dim': 20, 'thresh': 0.0, 'ineq': 'gt', 'alpha': 0.09624217440331524}, {'dim': 17, 'thresh': 37.5, 'ineq': 'lt', 'alpha': 0.0785966288518967}, {'dim': 9, 'thresh': 2.0, 'ineq': 'lt', 'alpha': 0.0714286363455072}, {'dim': 5, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.07830753154662214}, {'dim': 4, 'thresh': 28.799999999999997, 'ineq': 'lt', 'alpha': 0.07606159074712784}, {'dim': 4, 'thresh': 19.199999999999999, 'ineq': 'gt', 'alpha': 0.08306752811081955}, {'dim': 7, 'thresh': 4.2000000000000002, 'ineq': 'gt', 'alpha': 0.0830416741141175}, {'dim': 3, 'thresh': 92.0, 'ineq': 'lt', 'alpha': 0.08893356802801224}, {'dim': 14, 'thresh': 3.0, 'ineq': 'gt', 'alpha': 0.07000509315417908}, {'dim': 7, 'thresh': 5.3999999999999995, 'ineq': 'lt', 'alpha': 0.07697582358565964}, {'dim': 18, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.08507457442866707}, {'dim': 5, 'thresh': 3.2000000000000002, 'ineq': 'lt', 'alpha': 0.0676590387302069}, {'dim': 7, 'thresh': 3.0, 'ineq': 'gt', 'alpha': 0.08045680822237049}, {'dim': 12, 'thresh': 1.2, 'ineq': 'lt', 'alpha': 0.05616862921969557}, {'dim': 11, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.06454264376249863}, {'dim': 7, 'thresh': 5.3999999999999995, 'ineq': 'lt', 'alpha': 0.05308888435382875}, {'dim': 11, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.0734605861478849}, {'dim': 13, 'thresh': 0.0, 'ineq': 'gt', 'alpha': 0.07872267320907414}]
-----
[[ -3.46206894e-01 5.39820797e-01 1.34706655e+00 -1.96577914e-01
-2.92640472e-01 1.41661959e+00 1.02056225e+00 7.09312478e-01
-6.97844480e-01 8.52681888e-01 -1.51497974e-01 1.03289265e+00
1.43744689e+00 5.23008588e-01 1.00754226e+00 -5.04904838e-01
-1.55314011e+00 3.37496140e-01 1.83380220e-01 -2.73211412e-01
1.83753941e-01 1.94948307e+00 1.36536919e+00 1.51795899e+00
4.95458633e-01 1.66431604e-01 1.58899728e-01 7.56968915e-01
2.22941652e-01 2.33498196e+00 -9.09968780e-01 -2.25738386e-02
1.02102068e+00 6.63777579e-01 -2.08699355e-01 -1.78741084e+00
-3.78931896e-01 1.31751382e-01 1.67107366e+00 1.44392330e-01
-1.99093605e+00 5.16925045e-01 6.03341572e-01 -8.92743621e-01
-1.40693534e+00 -1.12567454e+00 -1.05681881e+00 1.72070073e+00
-8.66939191e-01 -1.60476417e+00 1.36634010e+00 3.79725055e-01
1.48452270e+00 6.64838547e-01 -3.26008621e-01 9.02376775e-02
3.93090801e-01 -1.14416817e-01 -6.16067208e-01 -1.27022815e+00
1.09311484e+00 1.72115916e+00 -4.29767329e-01 8.56337614e-02
-5.03473910e-01 4.64372963e-01 4.37330130e-01 1.93105924e+00
3.76440825e-02 1.53848847e+00 -1.70686489e-01 1.65834558e+00
-1.10078594e-01 -8.87042088e-01 3.93090801e-01 -7.93642352e-02
1.53618383e+00 2.00712868e+00 -1.29429189e-01 3.01572381e-01
-7.39738757e-01 1.05727042e+00 6.20389927e-01 -1.54961074e+00
5.38841873e-02 1.97319467e+00 -1.03933604e+00 5.95474367e-01
1.07315325e+00 2.02648722e+00 8.84069009e-01 -3.26008621e-01
1.39748643e+00 1.57824639e-03 1.20825738e+00 1.30012673e+00
7.59283818e-01 -1.32980287e+00 1.58143651e+00 -7.74682670e-01
1.61012477e+00 -1.58747355e+00 7.92723052e-01 1.62137341e+00
-1.44363067e-01 7.62472658e-01 5.55115414e-01 1.76395746e+00
-8.07172746e-01 -7.13443067e-01 -7.62149648e-01 1.06275540e+00
1.18148515e+00 -6.66282330e-01 2.36684357e-01 1.89994809e+00
2.24478748e+00 -9.17624883e-02 2.96253630e-01 1.08742569e+00
1.36883746e+00 -1.13525331e+00 1.80620011e+00 -5.59442382e-01
3.73123890e-01 1.84054205e+00 1.06799214e-01 5.89414867e-01
-6.54353819e-01 1.19724374e+00 4.63540870e-01 3.74879494e-01
1.47856059e+00 -6.57446519e-01 -6.93668829e-01 -1.29429189e-01
1.31594962e+00 1.64420444e+00 9.53502459e-01 7.40170420e-01
-4.35385025e-01 -1.30434214e+00 1.65834558e+00 -1.61422920e-01
7.50544036e-01 1.50390920e+00 8.12006783e-01 -1.11433828e-01
1.58948356e+00 1.80166124e+00 -1.24848181e+00 -3.16358922e-01
1.39748643e+00 2.36697540e+00 5.45445830e-01 1.30735427e+00
6.47538358e-01 1.16305757e+00 1.74396199e+00 -7.62381985e-01
4.27163890e-01 1.51465087e+00 -1.12436666e-01 8.09957092e-01
7.23764279e-03 1.94052195e+00 1.48306468e+00 2.64418198e-01
-1.21867130e+00 1.20420927e+00 -1.30937256e+00 -4.84404331e-01
-1.34263866e+00 -1.01739294e+00 2.22941652e-01 2.00510724e+00
-2.29750158e+00 -3.83556393e-01 -7.55614485e-01 -1.34943874e+00
8.51461579e-01 -1.54961074e+00 1.86860473e+00 2.09992462e+00
-4.31918141e-01 9.12376049e-01 1.32753580e-01 1.05799984e+00
3.94948721e-01 8.84028367e-01 5.37930835e-01 1.84470134e+00
-1.78544316e+00 6.35626744e-01 2.15191386e+00 -9.72238538e-02
1.90924894e-01 1.59095456e+00 8.40972426e-01 1.49370558e+00
-5.84176145e-01 4.54713517e-01 2.13758537e+00 -3.16164749e-01
-7.55614485e-01 5.31183150e-01 5.50284059e-01 -4.07776113e-01
2.05323133e+00 -1.22382729e-01 -9.51971888e-01 7.76212308e-01
1.02082939e+00 1.72495570e+00 2.05710397e+00 4.60616309e-01
-4.02664156e-01 8.58959865e-01 3.77072878e-02 -6.71174191e-01
7.47080450e-01 -3.81125550e-01 1.12389210e+00 1.75800100e+00
1.73857489e+00 -1.33101576e+00 5.50284059e-01 -1.30289376e+00
1.31228529e+00 -5.60455028e-01 -1.46354481e+00 7.90883276e-01
1.58899728e-01 1.20825738e+00 -8.87042088e-01 1.65728396e+00
1.22103595e+00 2.14912978e-01 3.64699577e-02 -1.32127479e+00
1.33000192e+00 -4.70065248e-02 -4.22251353e-02 7.70710258e-01
-1.27022815e+00 -8.61045169e-01 -9.56969900e-01 -7.95783983e-02
2.08738328e+00 -4.85855645e-01 3.91162341e-01 2.72751462e-01
-6.20974162e-01 -5.83646639e-01 1.44817145e-01 1.36706959e+00
-1.21222173e+00 1.92002542e+00 1.70722977e-01 9.55937244e-01
1.70564235e+00 -2.45144481e-01 -5.56039012e-01 1.94646186e-01
1.12867995e+00 5.63912150e-01 4.95748848e-01 1.20050741e+00
5.50857009e-01 6.29115697e-01 -1.11443306e-01 -2.08699355e-01
-1.63615949e+00 -4.00661971e-01 2.54103847e-01 8.38248031e-01
1.32784858e+00 1.87814608e+00 2.34862459e-01 1.67991427e+00
-6.70647873e-01 -7.62149648e-01 6.00705546e-02 2.24515155e+00
1.05333955e+00 -1.17411061e+00 1.57410447e-01 2.22941652e-01
1.51614920e+00 1.76240799e+00 -8.66939191e-01 -9.92873427e-01
-4.92052272e-01 2.52829341e+00 -1.55549790e-01 -1.18640330e+00
-1.35781920e+00 -1.94654268e-01 4.54752882e-01]]
the Area Under the Curve is: 0.8918191104095092
67 13.0 0.194029850746
集成方法通过组合多个分类器的分类结果,得到比简单的单分类器更好的分类结果。当然,也有一些利用不同分类器的集成方法。
多个分类器组合可能会进一步凸显出单分类器的不足,例如过拟合问题。遇到多分类器之间差异显著的化,则多个分类器组合会缓解这一问题。分类器之间的差别,可以是算法本身或者是应用于算法上的数据不同。
本文介绍了两种集成方式--bagging和boosting。bagging中,是通过随机抽样的替换方式,得到了与原始数据集规模一样的数据集;而boosting是在bagging的基础上更进一步,它在数据集上顺序应用了多个不同的分类器。而boosting中最流行的一个算法是AdaBoost算法。AdaBoost以弱学习为基础分类器,且输入数据,使其通过权重向量进行加权。第一次迭代中,所有数据都等权重,但后续迭代中,前次迭代中分错的数据权重会增大。这里针对错误的调节能力正是AdaBoost的优势。
非均衡分类问题是指在分类器训练时正例数目和反例数目不相等且相差很大。用于度量分类中的非均衡性的工具之一是ROC曲线。
截止目前,笔者已经梳理了一系列相当不错的分类技术,都是属于监督分类方面的技术。由于笔者水平有限,有不足之处,请各位多多指点。