机器学习实战
第一章 机器学习基础
- 2007年选出的十大数据挖掘算法
C4.5决策树、K-均值(K-mean)、支持向量机(SVM)、Apriori、最大期望算法(EM)、PageRank算法、AdaBoost算法、k-近邻算法(kNN)、朴素贝叶斯算法(NB)和分类回归树(CART)算法 - 文章结构
- 监督学习:分类
- k-近邻算法(距离矩阵)
- 决策树
- 概率分布进行分类
- 朴素贝叶斯算法
- Logistic回归算法(算法优化+处理集合中的缺失值,最优参数)
- 支持向量机
- Adaboost集成方法(样本非均匀分布,导致非均衡分类)
- 监督学习:连续型数值的回归预测
- 回归、去噪、局部加权线性回归
- 基于树的回归算法/分类回归树(CART)算法
- 无监督学习(算法找到共同特征)
- K0均值聚类算法
- 关联分析的Apriori算法
- 使用FP-Growth算法改进关联分析
- 其他
- 主成分分析和奇异值分解
- 分布式计算:mapreduce
- 基本概念
- 特征和目标变量
- 监督学习和无监督学习
- 监督学习:解决分类问题(目标变量的分类信息,目标变量为离散型)、预测数值型数据(最优拟合曲线,目标变量为连续性)
- 无监督学习:聚类(数据划分成离散的组);描述数据统计值的过程为密度估计(数据与每个分组的相似程度)
- 了解数据
- 离散型变量还是连续性变量(标称型和数值型)
- 特征值是否有缺失值、异常值、发生频率
- python
- 简单,但是效率低
- numpy库
- 两种数据类型:matrix、array
第二章 k-近邻居算法
- k-近邻算法基本理论(测量不同特征值之间的距离方法进行分类)
- 样本集:打标签的数据
- 新的没有标签的数据,与样本集对比,找出前k个最相近的样本数据
- 前k个最相似数据中出现次数最多的分类,为新数据的分类
- k-近邻算法优缺点
- 缺点:基于实例的学习,保存所有数据集,较大的存储空间;每一个测试样例要与所有的实例计算距离,并排序,时间复杂度高;没有抽取特征的环节,是比较特征的环节。
- 数据相关
- 数据特征观察:直接浏览文本非常不友好,应借用python工具来图形化展示数据内容
- 数据归一化处理:0到1区间内的值
- python语法
- shape函数:矩阵大小
- np.tile函数:按照某种重复的方式,重构矩阵 (m,n)m行n次
- argsort函数:numpy库中函数,返回从小到大的索引值
- np.zeros(shape):生成全0矩阵
- matplotlib.pyplot.add_subplot(111): 1行1列第1个
- scatter带label的散点图,会根据label的数值随机对应一种颜色
- min(0):每一列的最小值;min(1):每一行的最小值
第三章 决策树
- 决策树:数据形式容易理解,但可能过度匹配,createBranch算法见下
检测数据集中的每个子项是否属于同一分类:
If so return 类标签;
Else
寻找划分数据集的最好特征
划分数据集
创建分支节点
for每个划分的子集
调用createBranch函数并增加返回结果到分支节点中
return 分支节点
- ID3算法划分数据集;
- 选择获得信息增益最高的特征
- 信息增益:划分数据集之前后信息发生的变化
- 熵:信息的期望值(集合信息的度量方式)
H = \sum_{i=1}^np(x_i)log_2p(x_i)
- 其他的决策树构造算法:C4.5 和 CART
- 基本算法:选择某特征划分之后熵最高的特征,进行划分;不断建立决策树,直到每个分支下所有实例都具有相同的分类。具体可以查看相关代码
- matplotlib的注解功能绘制树形图
- python样例代码运行有一个小bug,需要把keys转换成list,再取[0]:list(dict.keys())[0]
- 使用决策树执行分类
- 在决策树里面查找叶子节点,不断的查找子树
- 决策树的存储:使用python的pickle模块(类似于json,但两者有区别)
- 决策树的剪枝
- 为了防止过度匹配,合并相邻的无法产生大量信息增益的叶子节点
第四章 基于概率论的朴素贝叶斯
- 朴素贝叶斯分类器
- 称“朴素”,整个形式化过程中只做最原始、最简单的假设
- 核心思想:选择高概率对应的类别
- 贝叶斯概率引入先验知识和逻辑推理来处理不确定命题
- 使用条件概率来分类(独立性假设)
- P(A|B) = P(B|A) P(A) / P(B)
- 文档分类的常用算法
- 例子1:文本分类【留言是否恶意】
- 将句子转换成词向量
- 每个单词在句子中可能出现多次
- 词向量计算概率
- 使用log,避免下溢出或者浮点数舍入
- 多个概率的乘积:所有词的出现数初始化为1
- 例子2:过滤垃圾邮件
- 运行代码,会出现文本编码的问题,copy出来覆盖一份就好了
- 随机选择10份邮件进行测试,剩余40份进行训练
- 留存交叉验证:样本集中一部分用来训练,一部分用来测试
- 例子3:广告中发现区域信息
- 删除高频词
- python语法
- 正则表达式,\w表示一个“字”(数字、字符、下划线)
- range格式的数据,不能直接delete;可以转换成list,然后delete
第五章 Logistic回归
- Logistic回归主要思想
- 根据现有数据对分类边界线建立回归公式(非线性函数),从而开展分类
- 回归:找到最佳拟合参数集
- 最优化算法的一种
- 最优化算法
- 基本的梯度上升法
- 改进的随机梯度上升法
- Sigmoid函数
- 很像单位阶跃函数(输出0/1)
- 每个特征乘以回归系数,总和相加,代入Sigmoid函数,进而得到0-1的值,则大于0.5分为1类,小于0.5分为0类【概率估计】
\sigma(z) = \frac{1}{1+e^{-z}}
- 基于最优化方法的最佳回归系数确定
- Sigmoid输入记为z,找最佳参数w
- 梯度上升法找w
z = w_0x_0+w_1x_1+w_2x_2+...+w_nx_n
z = w^Tx
- 梯度上升法
- 基本思想:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。不断沿着梯度方向移动,直到达到某个停止条件为止。
- 梯度上升算法求取函数最大值;梯度下降算法求取函数最小值。
- 缺点:每次迭代,需要遍历整个数据集来更新回归系数【当数据集很大,就惨了】
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatI #convert to NumPy matrix
labelMat = np.mat(classLabels).transpose()
m,n = np.shape(dataMatrix)
alpha = 0.001
maxCycles = 500
weights = np.ones((n,1))
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights)
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose()* error
return weights
- 随机梯度上升算法
- 基本思想:每次仅用一个样本点来更新回归系数
def stocGradAscent0(dataMatrix, classLabels):
m,n = np.shape(dataMatrix)
alpha = 0.01
weights = np.ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights
- 改进算法:alpha系数随着迭代次数不断减少;随机选取样本,减少周期性的波动【weights值将会收敛的更快】
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
dataMatrix = np.array(dataMatrix)
m,n = np.shape(dataMatrix)
weights = np.ones(n)
for j in range(numIter):
dataIndex = range(m)
dataIndex = list(dataIndex)
for i in range(m):
alpha = 2/(1.0+j+i)+0.0001
randIndex = int(np.random.uniform(0,len(dataIndex)))
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
- 例子:疝气病症预测病马的死亡率
- 数据处理:缺失特征数据置为0,因为不会影响weight更新;缺失类别数据,直接从训练集删除
- SVM支持向量机
- 与Logistic回归类似的一种分类算法
- 目前最好的现成算法之一【本书认为】
- python函数
- np.transpose:表示转置
第六章 SVM
- SVM基本概念
- 线性可分数据
- 分割超平面
- 2维的是将数据集分开的直线
- 分类的决策边界:分布在超平面一侧的所有数据属于某个类别,另一侧属于另一个类别
- 数据点离边界越远,数据越可信
w^TX + b = \sum_{i=1}^m\alpha_ix^Tx^{(i)} + b (4.1)
- 间隔:点A到分割面的距离
\frac{|w^TA + b|}{||w||}
- 支持向量:离分割超平面最近的那些点
- 测试中只需要保留支持向量,就可以进行测试
- 支持向量机是一个二类分类器,多类问题需要扩展
- 拉格朗日相关知识
- 带不等式约束的最优化问题
minf(x)
s.t.g_i(x) \leq 0 (j=1,2,3...J)
- 拉格朗日乘子法
- 引入拉格朗日乘子,将原目标函数和约束条件联系到一起,求解极值(各个变量的解 + 拉格朗日乘子)
- 松弛变量 v
- 拉格朗日函数
L(x,\lambda,v) = f(x) + \sum_{j=1}^{J}\lambda_j[g_j(x)+v_j^2]
- 将拉格朗日乘子、松弛变量、自变量求导,求极值
- 拉格朗日函数中的KKT条件
- 原可行性 g(x*)≤0
- 对偶可行性 α≥0
- α被称为KKT乘子或对偶变量
- 如果α≥0, 那么 ▽f 和 ▽g 方向是同向的(▽f(x*)=α×▽g(x*)).同样,如果α≤0, 那么▽f 和▽g方向是相反的。
- 互补松弛条件 αg(x*)=0
- 拉格朗日平稳性 ▽f(x*)=α×▽g(x*)
- 约束优化问题的极值总是发生在切点上
- 函数的梯度和函数的水平曲线的相切是正交的
- 知乎上拉格朗日讲解
- 简化版的SMO算法
- 第一篇cnblogs上讲解很好的公式推导
- 第二篇cnblogs上讲解很好的公式推导,可以和代码对应
- 第三篇cnblogs上讲解很好的公式推导
- 每次只优化两个变量,将其他变量视为常数->两变量优化问题
- L和H的取值,所有k都有满足,所以需要分别对两个区间的最大值取min,最小值取max,因为正间隔和负间隔都会被测试。
- 仅看公式就废老大劲了,先和代码对应上,基本思想理解了
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
dataMatrix = np.mat(dataMatIn); labelMat = np.mat(classLabels).transpose()
b = 0; m,n = np.shape(dataMatrix)
alphas = np.mat(np.zeros((m,1)))
iter = 0
while (iter < maxIter):
alphaPairsChanged = 0
for i in range(m):
fXi = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
Ei = fXi - float(labelMat[i])#if checks if an example violates KKT conditions
if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
j = selectJrand(i,m)
fXj = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
Ej = fXj - float(labelMat[j])
alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
if (labelMat[i] != labelMat[j]):
L = max(0, alphas[j] - alphas[i])
H = min(C, C + alphas[j] - alphas[i])
else:
L = max(0, alphas[j] + alphas[i] - C)
H = min(C, alphas[j] + alphas[i])
if L==H: print("L==H"); continue
eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T
if eta >= 0: print("eta>=0"); continue
alphas[j] -= labelMat[j]*(Ei - Ej)/eta
alphas[j] = clipAlpha(alphas[j],H,L)
if (abs(alphas[j] - alphaJold) < 0.00001): print("j not moving enough"); continue
alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#update i by the same amount as j
#the update is in the oppostie direction
b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T
b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T
if (0 < alphas[i]) and (C > alphas[i]): b = b1
elif (0 < alphas[j]) and (C > alphas[j]): b = b2
else: b = (b1 + b2)/2.0
alphaPairsChanged += 1
print("iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))
if (alphaPairsChanged == 0): iter += 1
else: iter = 0
print("iteration number: %d" % iter)
return b,alphas
- 计算w
- 参考以上公式,alphas*labelMat是真正的alpha值
def calcWs(alphas,dataArr,classLabels):
X = np.mat(dataArr); labelMat = np.mat(classLabels).transpose()
m,n = np.shape(X)
w = np.zeros((n,1))
for i in range(m):
w += np.multiply(alphas[i]*labelMat[i],X[i,:].T)
return w
- 完整版的Platt SMO算法
- ecache 误差缓存
- 选择步长最大的j
- 修改了i和j则需要updateEk
- 当选中的i和j没有变化时,重新遍历所有的alpha进行验证【覆盖了整个数据值】
- 核函数相关的分类
- 两类数据点分别分布在一个圆的内部和外部
- 通过核函数,将数据从一个特征空间转换到另一个特征空间
- 空间转换,可以在高维空间解决线性问题
- 最流行的核函数:径向基函数
- rbf 是径向基的缩写 radial basis function
- 机器学习实战的这本书,讲的真的很偏实战了,具体的原理推荐《统计学习方法》2012年
- 到达率会影响准确率
- 非线性支持向量机
f(x) = sign(\sum_{i=1}^N\alpha_i^*y_iK(x,x_i) + b^*)
- 回顾线性支持向量机
f(x) = sign(w^*X + b^*) = sign(\sum_{i=1}^N\alpha_i^*y_i(xx_i) + b)
- python
- 输出numpy A中大于0的元素 A[A>0]
- nonzero 输出非零列表值
- numpy.random.standard_normal:产生标准正态分布随机数
第七章 Adaboost
- 基本概念
- 元算法/集成方法:将不同的分类器进行组合的一种方式
- bagging
- bootstrap aggregating自举汇聚法
- 数据随机重抽样得到S个数据集,学习方法应用到S个数据集,得到S个分类器;对新数据进行分类,采用S个分类器分类的投票结果。
- 更先进的bagging方法:随机森林
- boosting
- 不同分类器通过串行训练获得,集中关注已有分类器错分的那些数据来获得新的分类器
- boosting分类的结果:基于所有分类器的加权求和,每个权重代表其对应分类器在上一轮迭代中的成功度
- boosting方法的其中一个比较流行的版本AdaBoost
- AdaBoost, adaptive boosting
- 全部的样本进行训练,权重初始化成相等的值
- 训练出弱分类器,计算错误率,并根据弱分类器的结果重新调整权重(第一次分对的权重将降低,第一次分错的权重将提高)
- 不断迭代(错误率为0,或者弱分类器数目达到一定程度)
- 最终,每个分类器都有一个权重值alpha,相关的计算公式见下
\epsilon = \frac{the \quad number \quad of \quad error \quad samples}{the \quad number \quad of \quad all \quad samples}
\alpha = \frac{1}{2}ln(\frac{1-\epsilon}{\epsilon})
D_i^{(t+1)} = \frac{D_i^{t}e^{\pm\alpha}}{Sum(D)}
3.例子 单层决策树
# 单层决策树:树桩弱分类器
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq): #输入:样本特征矩阵,指定特征,阈值,是否反转类别
retArray = ones((shape(dataMatrix)[0], 1))
if threshIneq == 'lt':
retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:, dimen] > threshVal] = -1.0
return retArray # 返回类别向量
# 遍历分类函数所有可能的输入 找到基于D的最佳单层决策树
def buildStump(dataArr, classLabels, D): # 输入:样本特征矩阵,样本标签,样本权重
dataMatrix = mat(dataArr);
labelMat = mat(classLabels).T
m, n = shape(dataMatrix)
numSteps = 10.0; # 用于遍历特征的阈值
bestStump = {}; # 记录最佳单层树桩的信息
bestClasEst = mat(zeros((m, 1)))
minError = inf # 记录最小错误率
for i in range(n): # 遍历所有特征
rangeMin = dataMatrix[:, i].min();
rangeMax = dataMatrix[:, i].max();
stepSize = (rangeMax - rangeMin) / numSteps
for j in range(-1, int(numSteps) + 1): # 遍历所有阈值
for inequal in ['lt', 'gt']: # 反转类别
threshVal = (rangeMin + float(j) * stepSize)
predictedVals = stumpClassify(dataMatrix, i, threshVal,inequal) # 指定特征,阈值,类别判定 后 树桩进行分类
errArr = mat(ones((m, 1)))
errArr[predictedVals == labelMat] = 0
weightedError = D.T * errArr # 计算加权错误率
#print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError)
if weightedError < minError: # 更新最佳树桩配置信息
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst# 返回决策树,最小错误率,及其预测类别
---------------------
作者:xiaxzhou
来源:CSDN
原文:https://blog.csdn.net/xiaxzhou/article/details/72872270
版权声明:本文为博主原创文章,转载请附上博文链接!
- 其他分类性能度量指标
- 错误率:错分的样例比例
- 二类问题的混淆矩阵
/ | 预测+1 | 预测-1 |
---|---|---|
真实+1 | 真正例(TP) | 违反例(FN) |
真实-1 | 伪正例(FP) | 真反例(TN) |
- 正确率 = TP/(TP+FP),预测正例样本中真正正例的比例
- 召回率 = TP/(TP+FN),预测正例样本的真实正例占所有真实正例的比例
- ROC曲线
- plotRoc(最终模型训练数据的分类数据,原始分类)
- 最终模型训练数据的分类数据,排序之后:负例在前,正例在后
- 基于代价函数的分类器决策控制
- 处理非均衡问题的数据抽样方法
- 欠抽样:删除样例
- 过抽样:复制样例