机器学习(一):K近邻算法

在这里插入图片描述
图中红线代表曼哈顿距离,绿色代表欧氏距离,也就是直线距离,而蓝色和黄色代表等价的曼哈顿距离。曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。
在这里插入图片描述

K近邻算法
在这里插入图片描述
在这里插入图片描述

意思就是:我输入的测试数据, 放在已经训练好的训练集 中,找与这个测试数据较近的 k 个数据,在这个k个数据点中出现最多的类别,则确定这个测试数据的类别就是这个。
接下来对KNN算法的思想总结一下:就是在训练集中数据和标签已知的情况下,输入测试数据,将测试数据的特征与训练集中对应的特征进行相互比较(也就是算测试数据和其他数据的距离),找到训练集中与之最为相似(即最为接近)的前K个数据,则该测试数据对应的类别就是K个数据中出现次数最多的那个分类,其算法的描述为:

1)计算测试数据与各个训练数据之间的距离;

2)按照距离的递增关系进行排序;

3)选取距离最小的K个点;

4)确定前K个点所在类别的出现频率;

5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
**

近似误差和估计误差解释

**:

统计学习方法中说:k值越小,学习的近似误差(approximation error)越小,估计误差(estimation error)越大,反之则相反
http://blog.csdn.net/weixin_37895339/article/details/78794190

近似误差:可以理解为对现有训练集的训练误差。 估计误差:可以理解为对测试集的测试误差。*

近似误差关注训练集,如果近似误差小了会出现过拟合的现象,对现有的训练集能有很好的预测,但是对未知的测试样本将会出现较大偏差的预测。模型本身不是最接近最佳模型。

https://www.zhihu.com/question/60793482

近似误差其实可以理解为模型估计值与实际值之间的差距。 估计误差其实可以理解为模型的估计系数与实际系数之间的差距。

在这个k临近法中其实设定的k值越小,得出的模型是越复杂的,因为k值越小会导致特征空间被划分成更多的子空间(可以理解为模型的项越多)。而k值越大得到的模型其实是越简单的 - -
所以当k值越小,对于训练集的预测更加精确,近似误差会越小(因为你选择了更加复杂的模型去预测训练集)。当k值越大,对于训练集的预测则不会那么准确,所以近似误差会越大(因为你选择了更加简单的模型去预测)。
而另一方面,由于设定了比较小的k值,模型比较复杂就会产生过度拟合(overfitting)的问题。

近似误差,更关注于“训练”。

最小化近似误差,即为使估计值尽量接近真实值,但是这个接近只是对训练样本(当前问题)而言,模型本身并不是最接近真实分布。换一组样本,可能就不近似了。这种只管眼前不顾未来预测的行为,即为过拟合。

估计误差,更关注于“测试”、“泛化”。

最小化估计误差,即为使估计系数尽量接近真实系数,但是此时对训练样本(当前问题)得到的估计值不一定是最接近真实值的估计值;但是对模型本身来说,它能适应更多的问题(测试样本)

交叉验证法

 交叉验证(Cross Validation)是用来验证分类器的性能一种统计分析方法,基本思想是把在某种意义下将原始数据
 (dataset)进行分组、 一部分做为训练集 (training set),另一部分做为验证集(validation set) ,
 首先用训练集对分类器进行训练,在利用验证集来测试训练得到的模型(model),
以此来做为评价分类器的性能指标。
 常见的交叉验证方法如下:

1、Hold-Out Method

    将原始数据随机分为两组,一组做为训练集,一组做为验证集,利用训练集训练分类器,然后利用验证集验证模型,记录最后的分类准确率为此分类器的性能指标。 此种方法的好处的处理简单,只需随机把原始数据分为两组即可,其实严格意义来说Hold-Out Method并不能算是CV,因为这种方法没有达到交叉的思想,由于是随机的将原始数据分组,所以最后验证集分类准确率的高低与原始数据的分组有很大的关 系,所以这种方法得到的结果其实并不具有说服性。

2、Double Cross Validation(2-fold Cross Validation,记为2-CV)

   做法是将数据集分成两个相等大小的子集,进行两回合的分类器训练。在第一回合中,一个子集作为training set,另一个便作为testing set;在第二回合中,则将training set与testing set对换后,再次训练分类器,而其中我们比较关心的是两次testing sets的辨识率。不过在实务上2-CV并不常用,主要原因是training set样本数太少,通常不足以代表母体样本的分布,导致testing阶段辨识率容易出现明显落差。此外,2-CV中分子集的变异度大,往往无法达到“实 验过程必须可以被复制”的要求。

3、K-fold Cross Validation(K-折交叉验证,记为K-CV)

   将原始数据分成K组(一般是均分),将每个子集数据分别做一次验证集,其余的K-1组子集数据作为训练集,这样会得到K个模型,用这K个模型最终的验证 集的分类准确率的平均数作为此K-CV下分类器的性能指标。K一般大于等于2,实际操作时一般从3开始取,只有在原始数据集合数据量小的时候才会尝试取 2。K-CV可以有效的避免过学习以及欠学习状态的发生,最后得到的结果也比较具有说服性。

4、Leave-One-Out Cross Validation(记为LOO-CV)

     如果设原始数据有N个样本,那么LOO-CV就是N-CV,即每个样本单独作为验证集,其余的N-1个样本作为训练集,所以LOO-CV会得到N个模 型,用这N个模型最终的验证集的分类准确率的平均数作为此下LOO-CV分类器的性能指标。相比于前面的K-CV,LOO-CV有两个明显的优点:

(1)每一回合中几乎所有的样本皆用于训练模型,因此最接近原始样本的分布,这样评估所得的结果比较可靠。
(2)实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。

但LOO-CV的缺点则是计算成本高,因为需要建立的模型数量与原始数据样本数量相同,当原始数据样本数量相当多时,LOO-CV在实作上便有困难几乎就是不显示,除非每次训练分类器得到模型的速度很快,或是可以用并行化计算减少计算所需的时间。

原标题:「交叉验证」到底如何选择K值?

交叉验证(cross validation)一般被用于评估一个机器学习模型的表现。更多的情况下,我们也用交叉验证来进行模型选择(model selection)。往远了说,交叉验证可以用于评估任何过程,但本文仅讨论机器学习评估这个特定领域。

交叉验证有很长的历史,但交叉验证的研究有不少待解决的问题。拿最简单的K折交叉验证来说,如何选择K就是一个很有意思的话题。而更有意思的是,交叉验证往往被用于决定其他算法中的参数,如决定K近邻算法中K的取值。因此我们必须首先决定K折交叉验证中的K。

K折交叉验证(K-fold cross validation)指的是把训练数据D 分为 K份,用其中的(K-1)份训练模型,把剩余的1份数据用于评估模型的质量。将这个过程在K份数据上依次循环,并对得到的K个评估结果进行合并,如求平均或投票。如下图所示的10折交叉验证,训练数据D被分为了 ,每次取其中9份数据作为训练集,1份作为测试集,最终将循环后所有的评估结果取平均。
在这里插入图片描述

  1. 首先第一个问题,为什么要用交叉验证?

根本原因是我们的数据是有限的。当数据量不够大的时候,如果把所有的数据都用于训练模型容易导致模型过拟合。通过交叉验证对数据的划分+对评估结果的整合,我们可以“有效”的降低模型选择中的方差。换句话说,我们期望模型在训练集的多个子数据集上表现良好,这胜过单单在整个训练数据集上表现良好。简单来说,交叉验证也可以用方差偏差分解的思路来看,从某个角度和集成学习及bootstrapping也有相似点。此处不再赘述,可以看知乎讨论[4]。

所以理论保障就是,使用了交叉验证,模型方差“应该”降低了。首先在理想情况下,我们认为K折交叉验证可以 的效率降低模型的方差,从而提高模型的泛化能力,但实际情况并不是这样。主要问题在于我们所得到K折数据之间并非独立,而存在相关性。因此实际情况下,K折交叉验证到底能降低多少方差还不确定,同时带来的偏差上升有多少也还存疑。

  1. K到底该取多少?或者说,为什么大部分人都说要取10?

交叉的折数(fold)取多少一直没有准确的答案。往大了说这是个历史遗留问题,10这个数字也就被一直沿用了下来[2]。一般有两种流行的取值:(i) K=10 (ii) K=n,n指的是训练数据的总数,这种方法也叫做留一法(LOOCV)。

让我们思考交叉验证的两种极端情况:

完全不使用交叉验证是一种极端情况,即K=1。在这个时候,所以数据都被用于训练,模型很容易出现过拟合,因此容易是低偏差、高方差(low bias and high variance)。

留一法是K折的另一种极端情况,即K=n。随着K值的不断升高,单一模型评估时的方差逐渐加大而偏差减小。
但从总体模型角度来看,反而是偏差升高了而方差降低了。

所以当K值在1到n之间的游走,可以理解为一种方差和偏差妥协的结果。以K=10为例,在训练时我们的训练集数量仅为训练数据的90%。对比不使用交叉验证的情况,这会使得偏差上升,但对于结果的平均又会降低模型方差,最终结果是否变好取决于两者之间的变化程度。而这种直觉上的解释,并不总是有效。如Hastie曾通过实验证明 K折交叉验证比留一法的方差更小[1],这和我们上面的结论不一样。

另一个值得一提的看法是,交叉验证需要思考场景,而不是普适的。其中关系最大的就是评估模型的稳定性。在2015年的一项研究中,作者发现留一法有最好或者接近最好的结果[2],在他们的实验中 K=10和K=5的效果都远不如留一法或者K=20。

对于稳定模型来说,留一法的结果较为统一,值得信赖。对于不稳定模型,留一法往往比K折更为有效[2]。换句话说,那就是留一法结果较为可靠。

  1. 那么是否K的取值越大越好?

不一定,首先要考虑的是计算的开销。当数据量较大时,使用留一法的计算开销远远超过了我们的承受能力,需要谨慎对待。2017年的一项研究给出了另一种经验式的选择方法[3],作者建议 且保证 ,此处的n代表了数据量,d代表了特征数。感兴趣的朋友可以对照论文进一步了解。

总结
这篇文章的目的不是为了说明K到底该取什么值,而只是为了再次讨论K值其实还是一种方差和偏差之间妥协。K=10或者5并不能给与我们绝对的保障,这还要结合所使用的模型来看。当模型稳定性较低时,增大K的取值可以给出更好的结果。

从实验角度来看,较大的K值也不一定就能给出更小的方差[2],一切都需要具体情况具体讨论。相对而言,较大的K值的交叉验证结果倾向于更好。但同时也要考虑较大K值的计算开销

另一个交叉验证需要关注的点是,当你的数据集太小时,较小的K值会导致可用于建模的数据量太小,所以小数据集的交叉验证结果需要格外注意。建议选择较大的K值

所以总结来看,交叉验证还是一个比较复杂的过程,与模型稳定性,数据集大小等都息息相关。K=10的10折交叉验证不是万灵药,也不是万无一失的真理,但不失为一个良好的尝试。如果计算能力允许,增大K值或许更为保险。
转载:https://wemedia.ifeng.com/72374401/wemedia.shtml

方差和偏差(Bias and Variance)

偏差:描述的是预测值(估计值)的期望与真实值之间的差距。偏差越大,越偏离真实数据,如下图第二行所示。

方差:描述的是预测值的变化范围,离散程度,也就是离其期望值的距离。方差越大,数据的分布越分散,如下图右列所示。
在这里插入图片描述
**

深入讨论模型的好坏判别

**

在机器学习的面试中,能不能讲清楚偏差方差,经常被用来考察面试者的理论基础。偏差方差看似很简单,但真要彻底地说明白,却有一定难度。比如,为什么KNN算法在增大k时,偏差会变大,但RF增大树的数目时偏差却保持不变,GBDT在增大树的数目时偏差却又能变小。本文的目的就是希望能对偏差方差有一个科学的解读,欢迎大家多多交流。

1、引子假设我们有一个回归问题,我们搞到一批训练数据D,然后选择了一个模型M,并用数据D将M训练出来,记作Mt,这里我们故意把模型M与训练出的模型Mt区分开,是为了后面叙述时概念上的清晰。现在,我们怎么评价这个模型的好坏呢?你可能会不屑地说,这么简单的问题还用问吗,当然是用test集来测试啊。

哈哈!你上当了!因为我并没有说明是评价模型M的好坏还是模型Mt的好坏

!这二者有什么区别呢?
我们都知道,模型M代表的是一个函数空间,比如模型y=wx+b,若x,y都是实数,w,b为实数参数,则该模型就代表了平面上所有的直线,这所有的直线就是一个函数空间。同理,y=ax^2+bx+c代表的就是平面上所有的二次曲线,所有的二次曲线组成一个函数空间。当然,所有的直线此时也是二次曲线的特例。回到上面的问题,Mt实际上是用数据D找到的M代表的函数空间中的一个具体的函数。这话有点绕,不过还是不难理解的。Mt的表现好坏不能完整地代表M的好坏。上面这句话有很多内涵,我们一点一点来说明。

2、什么是M的好坏?以上面的一次函数和二次函数为例,当我们说二次函数比一次函数更好时,我们潜在的含义是说,对于某个我们正要解决的机器学习问题来说,二次函数总体上比一次函数表现更好,我们是在函数空间的层次上来比较的。
而且,还是针对一个具体的机器学习问题来比较的,因为对于不同的机器学习问题,二者哪个更好是不一定的。
Note:在下文中,可以把机器学习问题默想成回归问题,这样便于理解。这里再次强调,当我们说模型好坏时,隐含有两个含义:1,比较的是整个函数空间2,针对某个具体机器学习问题比较

3,怎么比较M的好坏?
我们可以这样做:
1,找一条不变的万能测试样本在这个具体的机器学习问题中找一条样本x,它的标签为y。在后续的所有训练中都用这条样本做测试集,永远不用作训练集。
2,在测试样本上观察Mt的表现,假设Mt在样本x上的预测值为yt,则y-yt可用来评价Mt的表现好坏。
3,找另外一个训练集D1,训练出Mt1,在测试样本上测试得到yt1,进而得到误差y-yt1,
4,重复第3步多次,直到得到N个具体的模型,和N个yt,N个y-yt。
5,当N足够大时,我们可以这样来评测M的好坏,首先看N个yt的均值ytmean是否等于y,其次,看N个yt相对均值ytmean的方差有多大。显然,若ytmean=y
,说明M学习能力是够的,也就是说,当N趋向无穷大时,N个Mt对x预测的均值能无限接近y。

在这里插入图片描述
很多人会有种错觉,感觉任何M都能达到上面的效果,实际上,不是每一个M都有这样的能力的,举个极端的例子,我们假设M1的函数空间中只有一个函数,且对于任何样本的预测值都恒等于y+1,则无论N多大,ytmean都会比y大1的。
我们称M1由于学习能力不够所造成的对x的预测误差叫做偏差。其次,N个yt相对均值ytmean的方差有多大也能从另一个方面揭示M的好坏,举个例子,假设我们有M1,M2两个模型,当N无穷大时,都能使得ytmean等于y。但是M1的预测值是这样分布的(下面圆点代表一个个的预测值)
…ytmean…
.M2的预测值是这样分布的
. . . .ytmean. . . .
显然,我们会觉得M1比M2更好。你可能会想,N足够大时,二者都能准确地均值到y,这就够了,没必要再比较它们的预测值相对均值的方差。这样的观点错误的地方是:实践中,我们并不能抽样出D1,D2,D3…DN个训练集,往往只有一份训练集D,这种情况下,显然,用M1比用M2更有把握得到更小的误差。

作者:西瓜高中数学
链接:https://www.zhihu.com/question/20448464/answer/339471179
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码块

# -*- coding: UTF-8 -*-
import numpy as np
import operator

"""
函数说明:kNN算法,分类器

Parameters:
    inX - 用于分类的数据(测试集)
    dataSet - 用于训练的数据(训练集)
    labes - 分类标签
    k - kNN算法参数,选择距离最小的k个点
Returns:
    sortedClassCount[0][0] - 分类结果

Modify:
    2017-07-13
"""
def classify0(inX, dataSet, labels, k):
    #numpy函数shape[0]返回dataSet的行数
    dataSetSize = dataSet.shape[0]
    #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    #二维特征相减后平方
    sqDiffMat = diffMat**2
    #sum()所有元素相加,sum(0)列相加,sum(1)行相加
    sqDistances = sqDiffMat.sum(axis=1)
    #开方,计算出距离
    distances = sqDistances**0.5
    #返回distances中元素从小到大排序后的索引值
    sortedDistIndices = distances.argsort()
    #定一个记录类别次数的字典
    classCount = {}
    for i in range(k):
        #取出前k个元素的类别
        voteIlabel = labels[sortedDistIndices[i]]
        #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
        #计算类别次数
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    #python3中用items()替换python2中的iteritems()
    #key=operator.itemgetter(1)根据字典的值进行排序
    #key=operator.itemgetter(0)根据字典的键进行排序
    #reverse降序排序字典
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回次数最多的类别,即所要分类的类别
    return sortedClassCount[0][0]

Numpy 中的 tile 函数 :


>>>a=arange(1,3)
>>>np.tile(a,(1,2)) 
#结果为 
array=([1,2,1,2]) #所以tile第二个参数元组中的第二个参数是管列上重复 a 几次
>>>np.tile(a,(2,1))
#结果为
array=([1,2
       [1,2])
    #所以元组第一个负责行上重复几次

写的较好的博客推荐:
1,机器学习实战:k近邻算法:(https://www.cnblogs.com/ybjourney/p/4702562.html)
2,详细代码 :(https://blog.csdn.net/c406495762/article/details/75172850)
3,tile 详解:(https://blog.csdn.net/baiyu9821179/article/details/53364731)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值