机器学习实战-笔记

机器学习实战

Github代码

第一章 机器学习基础

  1. 2007年选出的十大数据挖掘算法
    C4.5决策树、K-均值(K-mean)、支持向量机(SVM)、Apriori、最大期望算法(EM)、PageRank算法、AdaBoost算法、k-近邻算法(kNN)、朴素贝叶斯算法(NB)和分类回归树(CART)算法
  2. 文章结构
  • 监督学习:分类
    • k-近邻算法(距离矩阵)
    • 决策树
    • 概率分布进行分类
    • 朴素贝叶斯算法
    • Logistic回归算法(算法优化+处理集合中的缺失值,最优参数)
    • 支持向量机
    • Adaboost集成方法(样本非均匀分布,导致非均衡分类)
  • 监督学习:连续型数值的回归预测
    • 回归、去噪、局部加权线性回归
    • 基于树的回归算法/分类回归树(CART)算法
  • 无监督学习(算法找到共同特征)
    • K0均值聚类算法
    • 关联分析的Apriori算法
    • 使用FP-Growth算法改进关联分析
  • 其他
    • 主成分分析和奇异值分解
    • 分布式计算:mapreduce
  1. 基本概念
  • 特征和目标变量
  • 监督学习和无监督学习
    • 监督学习:解决分类问题(目标变量的分类信息,目标变量为离散型)、预测数值型数据(最优拟合曲线,目标变量为连续性)
    • 无监督学习:聚类(数据划分成离散的组);描述数据统计值的过程为密度估计(数据与每个分组的相似程度)
  • 了解数据
    • 离散型变量还是连续性变量(标称型和数值型)
    • 特征值是否有缺失值、异常值、发生频率
  • python
    • 简单,但是效率低
    • numpy库
      • 两种数据类型:matrix、array

第二章 k-近邻居算法

  1. k-近邻算法基本理论(测量不同特征值之间的距离方法进行分类)
  • 样本集:打标签的数据
  • 新的没有标签的数据,与样本集对比,找出前k个最相近的样本数据
  • 前k个最相似数据中出现次数最多的分类,为新数据的分类
  1. k-近邻算法优缺点
  • 缺点:基于实例的学习,保存所有数据集,较大的存储空间;每一个测试样例要与所有的实例计算距离,并排序,时间复杂度高;没有抽取特征的环节,是比较特征的环节。
  1. 数据相关
  • 数据特征观察:直接浏览文本非常不友好,应借用python工具来图形化展示数据内容
  • 数据归一化处理:0到1区间内的值
  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):每一行的最小值

第三章 决策树

  1. 决策树:数据形式容易理解,但可能过度匹配,createBranch算法见下
检测数据集中的每个子项是否属于同一分类: 
    If so return 类标签;
    Else
        寻找划分数据集的最好特征
        划分数据集 
        创建分支节点
            for每个划分的子集
                调用createBranch函数并增加返回结果到分支节点中
        return  分支节点
  1. ID3算法划分数据集;
  • 选择获得信息增益最高的特征
  • 信息增益:划分数据集之前后信息发生的变化
  • 熵:信息的期望值(集合信息的度量方式)
H = \sum_{i=1}^np(x_i)log_2p(x_i)

公式参考

  • 其他的决策树构造算法:C4.5 和 CART
  1. 基本算法:选择某特征划分之后熵最高的特征,进行划分;不断建立决策树,直到每个分支下所有实例都具有相同的分类。具体可以查看相关代码
  2. matplotlib的注解功能绘制树形图
  • python样例代码运行有一个小bug,需要把keys转换成list,再取[0]:list(dict.keys())[0]
  1. 使用决策树执行分类
  • 在决策树里面查找叶子节点,不断的查找子树
  1. 决策树的存储:使用python的pickle模块(类似于json,但两者有区别)
  2. 决策树的剪枝
  • 为了防止过度匹配,合并相邻的无法产生大量信息增益的叶子节点

第四章 基于概率论的朴素贝叶斯

  1. 朴素贝叶斯分类器
  • 称“朴素”,整个形式化过程中只做最原始、最简单的假设
  • 核心思想:选择高概率对应的类别
  • 贝叶斯概率引入先验知识和逻辑推理来处理不确定命题
  • 使用条件概率来分类(独立性假设)
    • P(A|B) = P(B|A) P(A) / P(B)
  • 文档分类的常用算法
  1. 例子1:文本分类【留言是否恶意】
  • 将句子转换成词向量
    • 每个单词在句子中可能出现多次
  • 词向量计算概率
    • 使用log,避免下溢出或者浮点数舍入
    • 多个概率的乘积:所有词的出现数初始化为1
  1. 例子2:过滤垃圾邮件
    • 运行代码,会出现文本编码的问题,copy出来覆盖一份就好了
    • 随机选择10份邮件进行测试,剩余40份进行训练
    • 留存交叉验证:样本集中一部分用来训练,一部分用来测试
  2. 例子3:广告中发现区域信息
    • 删除高频词
  3. python语法
    • 正则表达式,\w表示一个“字”(数字、字符、下划线)
    • range格式的数据,不能直接delete;可以转换成list,然后delete

第五章 Logistic回归

  1. Logistic回归主要思想
    • 根据现有数据对分类边界线建立回归公式(非线性函数),从而开展分类
    • 回归:找到最佳拟合参数集
    • 最优化算法的一种
  2. 最优化算法
    • 基本的梯度上升法
    • 改进的随机梯度上升法
  3. Sigmoid函数
    • 很像单位阶跃函数(输出0/1)
    • 每个特征乘以回归系数,总和相加,代入Sigmoid函数,进而得到0-1的值,则大于0.5分为1类,小于0.5分为0类【概率估计】
\sigma(z) =  \frac{1}{1+e^{-z}}
  1. 基于最优化方法的最佳回归系数确定
    • Sigmoid输入记为z,找最佳参数w
    • 梯度上升法找w
z =  w_0x_0+w_1x_1+w_2x_2+...+w_nx_n 

z = w^Tx 
  1. 梯度上升法
  • 基本思想:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。不断沿着梯度方向移动,直到达到某个停止条件为止。
  • 梯度上升算法求取函数最大值;梯度下降算法求取函数最小值。
  • 缺点:每次迭代,需要遍历整个数据集来更新回归系数【当数据集很大,就惨了】
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
  1. 随机梯度上升算法
  • 基本思想:每次仅用一个样本点来更新回归系数
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
  1. 例子:疝气病症预测病马的死亡率
  • 数据处理:缺失特征数据置为0,因为不会影响weight更新;缺失类别数据,直接从训练集删除
  1. SVM支持向量机
  • 与Logistic回归类似的一种分类算法
  • 目前最好的现成算法之一【本书认为】
  1. python函数
  • np.transpose:表示转置

第六章 SVM

  1. SVM基本概念
  • 线性可分数据
  • 分割超平面
    • 2维的是将数据集分开的直线
    • 分类的决策边界:分布在超平面一侧的所有数据属于某个类别,另一侧属于另一个类别
    • 数据点离边界越远,数据越可信
w^TX + b = \sum_{i=1}^m\alpha_ix^Tx^{(i)} + b  (4.1)
  • 间隔:点A到分割面的距离
\frac{|w^TA + b|}{||w||}
  • 支持向量:离分割超平面最近的那些点
  • 测试中只需要保留支持向量,就可以进行测试
  • 支持向量机是一个二类分类器,多类问题需要扩展
  1. 拉格朗日相关知识
  • 带不等式约束的最优化问题
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*)
      • 约束优化问题的极值总是发生在切点上
      • 函数的梯度和函数的水平曲线的相切是正交的
  • 知乎上拉格朗日讲解
  1. 简化版的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
  1. 完整版的Platt SMO算法
  • ecache 误差缓存
  • 选择步长最大的j
  • 修改了i和j则需要updateEk
  • 当选中的i和j没有变化时,重新遍历所有的alpha进行验证【覆盖了整个数据值】
  1. 核函数相关的分类
  • 两类数据点分别分布在一个圆的内部和外部
    • 通过核函数,将数据从一个特征空间转换到另一个特征空间
    • 空间转换,可以在高维空间解决线性问题
  1. 最流行的核函数:径向基函数
  • 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)
  1. python
  • 输出numpy A中大于0的元素 A[A>0]
  • nonzero 输出非零列表值
  • numpy.random.standard_normal:产生标准正态分布随机数

第七章 Adaboost

  1. 基本概念
  • 元算法/集成方法:将不同的分类器进行组合的一种方式
  • bagging
    • bootstrap aggregating自举汇聚法
    • 数据随机重抽样得到S个数据集,学习方法应用到S个数据集,得到S个分类器;对新数据进行分类,采用S个分类器分类的投票结果。
    • 更先进的bagging方法:随机森林
  • boosting
    • 不同分类器通过串行训练获得,集中关注已有分类器错分的那些数据来获得新的分类器
    • boosting分类的结果:基于所有分类器的加权求和,每个权重代表其对应分类器在上一轮迭代中的成功度
    • boosting方法的其中一个比较流行的版本AdaBoost
  1. 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
真实+1 真正例(TP) 违反例(FN)
真实-1 伪正例(FP) 真反例(TN)
- 正确率 = TP/(TP+FP),预测正例样本中真正正例的比例
- 召回率 = TP/(TP+FN),预测正例样本的真实正例占所有真实正例的比例
  • ROC曲线
    • plotRoc(最终模型训练数据的分类数据,原始分类)
    • 最终模型训练数据的分类数据,排序之后:负例在前,正例在后
  • 基于代价函数的分类器决策控制
  • 处理非均衡问题的数据抽样方法
    • 欠抽样:删除样例
    • 过抽样:复制样例

你可能感兴趣的:(机器学习实战-笔记)