• KNN算法


    (2017-04-10 银河统计)

    KNN算法即K Nearest Neighbor算法。这个算法是机器学习里面一个比较经典的、相对比较容易理解的算法。其中的K表示最接近自己的K个数据样本。KNN算法是用来做归类的,也就是说,一个样本空间里的样本已经分成很几个类型,然后,给定一个待分类的数据,通过计算接近自己最近的K个样本来判断这个待分类数据属于哪个分类。你可以简单的理解为由那离自己最近的K个点来投票决定待分类数据归为哪一类。

    一个比较经典的KNN图如下:

    从上图中我们可以看到,图中的有两个类型的样本数据,一类是蓝色的正方形,另一类是红色的三角形。而那个绿色的圆形是我们待分类的数据。

    如果K=3,那么离绿色点最近的有2个红色三角形和1个蓝色的正方形,这3个点投票,于是绿色的这个待分类点属于红色的三角形。

    如果K=5,那么离绿色点最近的有2个红色三角形和3个蓝色的正方形,这5个点投票,于是绿色的这个待分类点属于蓝色的正方形。

    我们可以看到,机器学习的本质是基于一种数据统计的方法或准则,k近邻(KNN)方法和其它聚类、分类等数据挖掘方法的理论基础是地理学第一定律(Tobler's First Law),即:

    All attribute values on a geographic surface are related to each other, but closer values are more strongly related than are more distant ones.
    

    “任何事物都相关,相近的事物关联更紧密”。KNN的基本思想类似于“物以类聚,人以群分”,打个通俗的比方就是“如果你要了解一个人,可以从他最亲近的几个朋友去推测他是什么样的人”,如果要判断一个样本点的类别,去看看和它相似的样本点的类别就行了。

    这个算法如何用呢?我们来看2个示例。

    一、KNN算法介绍

    实例一:KNN分类(产品质量判断问题)###

    假设我们需要判断纸巾的品质好坏,纸巾的品质好坏可以抽像出两个向量,一个是“酸腐蚀的时间”,一个是“能承受的压强”。如果我们的样本空间如下:(所谓样本空间,又叫Training Data,也就是用于机器学习的数据),

    耐酸时间(秒)- $X_1$圧强(公斤/平方米) - $X_2$品质 - Y
    77
    74
    34
    14

    那么,如果(X_1=3)(X_2=7), 这个毛巾的品质是什么呢?这里就可以用KNN算法来判断。

    假设K=3,K应该是一个奇数,这样可以保证不会有平票,下面是我们计算(3,7)到所有点的欧氏距离。

    耐酸时间(秒)- $X_1$圧强(公斤/平方米) - $X_2$计算各点到 (3, 7)的距离品质 - Y
    77$sqrt{(7-3)^2+(7-7)^2}=4$
    74$sqrt{(7-3)^2+(4-7)^2}=5$N/A
    34$sqrt{(3-3)^2+(4-7)^2}=3$
    14$sqrt{(1-3)^2+(4-7)^2}=3.61$

    所以,最后的投票,好的有2票,坏的有1票,最终需要测试的(3,7)是合格品。

    实例二:KNN预测(回归问题)###

    设有多元样本如下表:

    样本序号$X_1$$X_2$$X_3$Y
    S112.15.522
    S21.33.24.417
    S33.54.46.820
    S44.15827
    S55.178.930

    自变量样本向量S0为,(X_1=5)(X_2=6)(X_3=8)(Y=?)

    解、依次计算S0到S1、S2、...、S5的欧氏距离为,6.12、5.87、2.5、1.345、1.349,取K=2,(Y=frac{27+31}{2}=28.5);取K=3,(Y=frac{20+27+31}{3}=25.67)

    通过示例可以看出,KNN算法要解决好下面几个问题:

    I、如何度量邻居之间的相似度,也就是如何选取邻居的问题。相似性的度量方式在很大程度上决定了选取邻居的准确性,也决定了分类的效果,因为判定一个样本点的类别是要利用到它的邻居的,如果邻居都没选好,准确性就无从谈起。因此我们需要用一个量来定量的描述邻居之间的距离(如欧氏距离),也可以形象的表述为邻居之间的相似度;
    
    II、找多少个邻居才合适。如果K选大了的话,可能求出来的k最近邻集合可能包含了太多隶属于其它类别的样本点,最极端的就是k取训练集的大小,此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。如果K选小了的话,结果对噪音样本点很敏感。那么到底如何选取K值,一般靠经验或者交叉验证(一部分样本做训练集,一部分做测试集)的方法,就是是K值初始取一个比较小的数值,之后不段来调整K值的大小来时的分类最优,得到的K值就是我们要的,但是这个K值也只是对这个样本集是最优的。一般采用k为奇数,跟投票表决一样,避免因两种票数相等而难以决策;
    
    III、如何去寻找这k个邻居。因为对每一个待测样本点来说,都要对整个样本集逐一计算其与待测点的距离,计算并存储好以后,再查找K近邻,这是最简单、直接的方法,但计算量非常大。因此KNN的一大缺点需要存储全部训练样本,以及繁重的距离计算量。样本过的时,应该寻找简单算法,如KD树等;
    
    IV、用k个邻居估计待测样本点。根据样本特征,采用投票制少数服从多数或算术平均数(也可以考虑中位数)、加权平均数等。加权平均数一般采用两者之间距离的倒数为权重。
    

    二、KNN分类代码样例

    鸢尾花[iris]数据(R语言经典聚类、分类案例数据)

    IDSepal.LengthSepal.WidthPetal.LengthPetal.WidthSpecies
    15.13.51.40.2setosa
    24.93.01.40.2setosa
    34.73.21.30.2setosa
    44.63.11.50.2setosa
    55.03.61.40.2setosa
    65.43.91.70.4setosa
    74.63.41.40.3setosa
    85.03.41.50.2setosa
    94.42.91.40.2setosa
    104.93.11.50.1setosa
    115.43.71.50.2setosa
    124.83.41.60.2setosa
    134.83.01.40.1setosa
    144.33.01.10.1setosa
    155.84.01.20.2setosa
    165.74.41.50.4setosa
    175.43.91.30.4setosa
    185.13.51.40.3setosa
    195.73.81.70.3setosa
    205.13.81.50.3setosa
    215.43.41.70.2setosa
    225.13.71.50.4setosa
    234.63.61.00.2setosa
    245.13.31.70.5setosa
    254.83.41.90.2setosa
    265.03.01.60.2setosa
    275.03.41.60.4setosa
    285.23.51.50.2setosa
    295.23.41.40.2setosa
    304.73.21.60.2setosa
    314.83.11.60.2setosa
    325.43.41.50.4setosa
    335.24.11.50.1setosa
    345.54.21.40.2setosa
    354.93.11.50.2setosa
    365.03.21.20.2setosa
    375.53.51.30.2setosa
    384.93.61.40.1setosa
    394.43.01.30.2setosa
    405.13.41.50.2setosa
    415.03.51.30.3setosa
    424.52.31.30.3setosa
    434.43.21.30.2setosa
    445.03.51.60.6setosa
    455.13.81.90.4setosa
    464.83.01.40.3setosa
    475.13.81.60.2setosa
    484.63.21.40.2setosa
    495.33.71.50.2setosa
    505.03.31.40.2setosa
    517.03.24.71.4versicolor
    526.43.24.51.5versicolor
    536.93.14.91.5versicolor
    545.52.34.01.3versicolor
    556.52.84.61.5versicolor
    565.72.84.51.3versicolor
    576.33.34.71.6versicolor
    584.92.43.31.0versicolor
    596.62.94.61.3versicolor
    605.22.73.91.4versicolor
    615.02.03.51.0versicolor
    625.93.04.21.5versicolor
    636.02.24.01.0versicolor
    646.12.94.71.4versicolor
    655.62.93.61.3versicolor
    666.73.14.41.4versicolor
    675.63.04.51.5versicolor
    685.82.74.11.0versicolor
    696.22.24.51.5versicolor
    705.62.53.91.1versicolor
    715.93.24.81.8versicolor
    726.12.84.01.3versicolor
    736.32.54.91.5versicolor
    746.12.84.71.2versicolor
    756.42.94.31.3versicolor
    766.63.04.41.4versicolor
    776.82.84.81.4versicolor
    786.73.05.01.7versicolor
    796.02.94.51.5versicolor
    805.72.63.51.0versicolor
    815.52.43.81.1versicolor
    825.52.43.71.0versicolor
    835.82.73.91.2versicolor
    846.02.75.11.6versicolor
    855.43.04.51.5versicolor
    866.03.44.51.6versicolor
    876.73.14.71.5versicolor
    886.32.34.41.3versicolor
    895.63.04.11.3versicolor
    905.52.54.01.3versicolor
    915.52.64.41.2versicolor
    926.13.04.61.4versicolor
    935.82.64.01.2versicolor
    945.02.33.31.0versicolor
    955.62.74.21.3versicolor
    965.73.04.21.2versicolor
    975.72.94.21.3versicolor
    986.22.94.31.3versicolor
    995.12.53.01.1versicolor
    1005.72.84.11.3versicolor
    1016.33.36.02.5virginica
    1025.82.75.11.9virginica
    1037.13.05.92.1virginica
    1046.32.95.61.8virginica
    1056.53.05.82.2virginica
    1067.63.06.62.1virginica
    1074.92.54.51.7virginica
    1087.32.96.31.8virginica
    1096.72.55.81.8virginica
    1107.23.66.12.5virginica
    1116.53.25.12.0virginica
    1126.42.75.31.9virginica
    1136.83.05.52.1virginica
    1145.72.55.02.0virginica
    1155.82.85.12.4virginica
    1166.43.25.32.3virginica
    1176.53.05.51.8virginica
    1187.73.86.72.2virginica
    1197.72.66.92.3virginica
    1206.02.25.01.5virginica
    1216.93.25.72.3virginica
    1225.62.84.92.0virginica
    1237.72.86.72.0virginica
    1246.32.74.91.8virginica
    1256.73.35.72.1virginica
    1267.23.26.01.8virginica
    1276.22.84.81.8virginica
    1286.13.04.91.8virginica
    1296.42.85.62.1virginica
    1307.23.05.81.6virginica
    1317.42.86.11.9virginica
    1327.93.86.42.0virginica
    1336.42.85.62.2virginica
    1346.32.85.11.5virginica
    1356.12.65.61.4virginica
    1367.73.06.12.3virginica
    1376.33.45.62.4virginica
    1386.43.15.51.8virginica
    1396.03.04.81.8virginica
    1406.93.15.42.1virginica
    1416.73.15.62.4virginica
    1426.93.15.12.3virginica
    1435.82.75.11.9virginica
    1446.83.25.92.3virginica
    1456.73.35.72.5virginica
    1466.73.05.22.3virginica
    1476.32.55.01.9virginica
    1486.53.05.22.0virginica
    1496.23.45.42.3virginica
    1505.93.05.11.8virginica

    KNN分类算法代码

    ## 函数 - Knn分类
        webTJ.Datamining.getKNNClass(xarrs,yarr,sarrs,k,dtype,p);
    ##参数
        【xarrs,yarr,sarrs,k,dtype,p】
        【学习样本,分类属性样本,测试样本,k近邻,距离类型,闵氏距离系数】
    

    注:距离类型dtype取1、2、3、4、5、6、7、8,9分别为欧氏距离、曼哈顿距离、切比雪夫距离、闵氏距离、马氏距离、皮尔逊相关系数、斯皮尔曼秩相关系数、肯德尔秩相关系数、余弦相似度

    代码样例

    webTJ.clear();
    var oData=oIRIS; //鸢尾花数据字符串
    var oArrs=webTJ.getArrs(oData,"|",","); //鸢尾花数据转数组
    var oK=5; //5个近邻
    var oDType=1; //欧氏距离
    var oP=1.5; //闵氏系数
    var oSarrs=[[4.9,3.5,1.6,0.2],
                [4.5,3.0,1.5,0.2],
                [6.2,3.5,4.5,1.5],
                [5.7,3.8,1.8,0.3]]; //测试样本1
    var oYarr=webTJ.Array.getColData(oArrs,4); //获得鸢尾花数组第4列,分类属性样本
    var oXarrs=webTJ.Matrix.getRemoveCol(oArrs,4); //删除数组第4列,学习样本
    var oKNNarrs=webTJ.Datamining.getKNNClass(oXarrs,oYarr,oSarrs,oK,oDType,oP); //测试样本1KNN计算
    webTJ.show(oKNNarrs[0],2); //k近邻分类属性
    webTJ.show(oKNNarrs[1],2); //k近测试样本距离
    webTJ.show(oKNNarrs[2],2); //k近测分类
    var oStr="4.60,5.35,3.87,2.93|3.03,4.33,3.64,2.14|5.73,3.38,3.37,2.41|3.74,4.12,2.64,1.57|5.66,4.84,2.93,0.60|6.49,6.00,3.92,2.14|6.46,3.53,3.56,2.21|5.64,5.27,3.18,0.49|6.34,3.39,2.99,0.17|3.14,3.60,3.57,2.83|3.43,4.18,3.60,1.98|3.15,5.81,2.77,2.14|6.30,3.72,3.54,0.05|6.23,4.07,2.03,2.05|5.86,3.46,3.09,2.15|4.55,3.86,3.16,1.79|3.47,4.11,3.95,0.64|4.18,4.49,2.85,2.79|4.48,3.54,3.34,1.95|3.47,5.86,3.38,0.68"; //测试样本字符串
    var oArrs=webTJ.getArrs(oStr,"|",","); //转换为数组,测试样本2
    oArrs=webTJ.Array.getQuantify(oArrs); //量化测试样本数组
    oXarrs=webTJ.Array.getQuantify(oXarrs);  //量化学习样本数组
    var oKNNarrs=webTJ.Datamining.getKNNClass(oXarrs,oYarr,oArrs,oK,oDType,oP); //测试样本2KNN计算
    webTJ.show(oKNNarrs[0],2); //k近邻分类属性
    webTJ.show(oKNNarrs[1],2); //k邻近测试样本距离
    webTJ.show(oKNNarrs[2],2); //测试样本和分类数组
    

    注:样例代码可进行批量分类,分类结果为三个数组。如果有m组测试样本、取k近邻,第1个数组返回(m imes k)分类属性数组,即每组测试样本k个最邻近的分类属性;第2个数组返回(m imes k)距离数组,即每组测试样本k个最邻近的距离;第3个数组返回每组测试样本分类属性和判别比例(最后一列);

    三、KNN预测代码样例

    男孩身高、体重和胸围数据(1个月 - 10岁)

    月数体重(kg)身高(cm)男胸围(cm)
    14.350.532.8
    25.1554.5537.9
    35.9558.140
    46.6561.141.3
    57.2563.742.3
    67.8567.842.9
    78.870.9543.8
    109.673.6544.7
    1210.276.145.4
    1510.979.4546.1
    1811.582.447.6
    2112.0585.1548.9
    2412.687.6550.2
    3013.792.3550.5
    3614.794.950.8
    4215.7599.0552.4
    4816.75102.9554
    5417.8106.5555.5
    6018.85109.957
    6619.85113.158.5
    7221116.160
    8423.35121.761.5
    9626.1126.962.75
    10829.15132.1564
    12032.75137.568

    KNN预测算法代码

    ## 函数 - Knn预测
        webTJ.Datamining.getKNNForecast(xarrs,yarr,sarrs,k,dtype,f,r,p);
    ##参数
        【xarrs,yarr,sarrs,k,dtype,f,r,p】
        【学习样本,因变量值样本,测试样本,k近邻,距离类型,预测模式,反距离权重幂,闵氏距离系数】
    

    注:距离类型dtype取1、2、3、4、5、6、7、8,9分别为欧氏距离、曼哈顿距离、切比雪夫距离、闵氏距离、马氏距离、皮尔逊相关系数、斯皮尔曼秩相关系数、肯德尔秩相关系数、余弦相似度;预测模式f取1、2、3分别为K近邻均值、反距离权重法、调整反距离权重法预测

    代码样例

    webTJ.clear();
    var oStr="1,4.3,50.5,32.8|2,5.15,54.55,37.9|3,5.95,58.1,40|4,6.65,61.1,41.3|5,7.25,63.7,42.3|6,7.85,67.8,42.9|7,8.8,70.95,43.8|10,9.6,73.65,44.7|12,10.2,76.1,45.4|15,10.9,79.45,46.1|18,11.5,82.4,47.6|21,12.05,85.15,48.9|24,12.6,87.65,50.2|30,13.7,92.35,50.5|36,14.7,94.9,50.8|42,15.75,99.05,52.4|48,16.75,102.95,54|54,17.8,106.55,55.5|60,18.85,109.9,57|66,19.85,113.1,58.5|72,21,116.1,60|84,23.35,121.7,61.5|96,26.1,126.9,62.75|108,29.15,132.15,64|120,32.75,137.5,68";
    var oArrs=webTJ.getArrs(oStr,"|",","); //转换为数组,测试样本2
    oArrs=webTJ.Array.getQuantify(oArrs); //量化测试样本数组
    var oK=5; //5个近邻
    var oDType=1; //欧氏距离
    var oF=1;  //均值预测
    var oR=2;  //反距离权重幂
    var oP=1.5; //闵氏系数
    var oSarrs=[[6,60,41],
                [8.7,70,44],
                [19,110,57],
                [28,132,65]]; //测试样本
    var oYarr=webTJ.Array.getColData(oArrs,0); //获得数组第0列,因变量值样本
    var oXarrs=webTJ.Matrix.getRemoveCol(oArrs,0); //删除数组第0列,学习样本
    var oCMSD=webTJ.Datamining.getCMSD(oXarrs); //获取学习样本列均值和标准差数组
    //oXarrs=webTJ.Datamining.getSZarr(oXarrs,oCMSD); //学习样本标准化
    //oSarrs=webTJ.Datamining.getYZarrs(oSarrs,1); //测试差标准化
    var oKNNarrs=webTJ.Datamining.getKNNForecast(oXarrs,oYarr,oSarrs,oK,oDType,oF,oP); //测试样本KNN计算
    webTJ.show(oKNNarrs[0],2); //k近邻因变量值
    webTJ.show(oKNNarrs[1],2); //k邻近测试样本距离
    webTJ.show(oKNNarrs[2],2); //测试样本和因变量预测值数组
    

    用KNN算法处理数据时,通常学习样本数据较多,需要将EXCEL或网络表格数据转换为格式化字符串、进而转换为数组,并使用webTJ.Array.getQuantify函数量化数组。具体过程参见银河统计博文:数据输入、转换、展示和存储 - 网络统计类函数(1)

    反距离权重法

    反距离加权插值(IDW,Inverse Distance Weighted),也可以称为距离倒数乘方法。反距离权重插值使用一组样本和某特点样本间的距离的倒数为权数,在运用KNN方法进行预测时,将用K近邻样本量值简单算术平均改为反距离加权平均,体现了距离越近,对估计值影响越大的基本思想。

    在KNN预测样例代码中,对4组测试样本取k=5(5个近邻),可得4组样本最近5个样本量值和对应距离表如下:

    4组测试样本最近5个样本量值表
    测试样本Y1Y2Y3Y4Y5
    143526
    27610125
    36066547248
    4108961208472

    4组测试样本的5个最近距离表
    测试样本D1D2D3D4D5
    11.312.154.126.338.24
    20.982.63.826.446.68
    30.183.553.957.097.99
    41.535.897.8611.8318.08

    如果采用简单算术平均数进行预测,将每组测试样本的最近的k个样本量值计算平均数即可,每组测试样本预测值如下表:

    4组测试样本预测值表
    测试样本X1X2X3预测值Yc
    1660414
    28.770448
    3191105760
    4281326596

    表中第1个测试样本的5个k近邻样本量值为4、3、5、2、6,(frac{(4+3+5+2+6)}{5}=4),其它测试样本同样处理。

    由于最近的k个样本量值的距离不同,本着距离越近相似度越大的原则,可采用反距离加权插值计算。反距离加权公式为,

    [W_i=frac{frac{1}{D_i}}{sumlimits_{k=1}^mfrac{1}{D_i}}=frac{H_i}{sumlimits_{k=1}^mH_i} ]

    4组测试样本反距离权数表为,

    4组测试样本反距离权数表
    测试样本H1H2H3H4H5
    10.760.470.240.160.12
    21.020.380.260.160.15
    35.560.280.250.140.13
    40.650.170.130.080.06

    注:表中每个权数都是距离的倒数,如第1个测试样本的最邻近距离是1.31,其倒数为(frac{1}{1.31}:approx 0.76)

    根据反距离权数计算样本量值加权算术平均数,4组测试样本预测值表如下,

    4组测试样本反距离预测值表
    测试样本X1X2X3预测值$widehat{Y}$
    1660413.83
    28.770447.45
    3191105760.06
    42813265103.85

    以第1个测试样本为例,反距离加权插值算式为,

    [widehat{Y}_1=frac{frac{4}{1.31}+frac{3}{2.15}+frac{5}{4.12}+frac{2}{6.33}+frac{6}{8.24}}{frac{1}{1.31}+frac{1}{2.15}+frac{1}{4.12}+frac{1}{6.33}+frac{1}{8.24}}approx 3.83 ]

    通常,反距离加权插值预测效果优于简单算术平均数。但有时会出现距离很小或等于0的情况。距离很小时反距离加权插值会过分夸大对应样本量值在估值中的权重,距离为0时则无法使用反距离加权插值。为此可以使用调整反距离权重法。

    设k个近邻距离最大值和最小值为Dmax和Dmin。将Dmax向上取整为DUmax、Dmin向下取整为DLmin。例如,k个近邻距离最大值和最小值为12.3和2.6,分别向上和向下取整结果为13和2。调整后的反距离加权公式为,

    [W_i=(frac{DUmax-D_i}{DUmax-DLmin})^p ]

    式中(p)为反距离权数的幂,反距离权重法主要依赖于反距离的幂值。幂参数是一个正实数,默认值为2。幂值大,可进一步强调邻近数据的影响,表面会变得更加详细(更不平滑)。随着幂数的增大,内插值将逐渐接近最近采样点的值。指定较小的幂值将对距离较远的周围点产生更大影响,从而导致更加平滑的表面。

    以第1个测试样本为例,取(p=1.5),最大值向上取整为9、最小值向下取整为1,调整反距离权数算式为,

    [W_i=(frac{DUmax-D_i}{DUmax-DLmin})^p=(frac{9-1.31}{9-1})^{1.5}approx 0.94 ]

    计算4组测试样本每个距离的调整反距离权数,计算表如下,

    4组测试样本调整反距离权数表(P=1.5)
    测试样本W1W2W3W4W5
    10.940.790.480.190.03
    20.800.500.310.020.01
    30.970.410.360.040
    40.960.620.490.250.01

    第1个测试样本为例,取(p=1.5),预测值为,

    [widehat{Y}_1=frac{4 imes(frac{9-1.31}{9-1})^{1.5}+3 imes(frac{9-2.15}{9-1})^{1.5}+5 imes(frac{9-4.12}{9-1})^{1.5}+2 imes(frac{9-6.33}{9-1})^{1.5}+6 imes(frac{9-8.24}{9-1})^{1.5}}{(frac{9-1.31}{9-1})^{1.5}+(frac{9-2.15}{9-1})^{1.5}+(frac{9-4.12}{9-1})^{1.5}+(frac{9-6.33}{9-1})^{1.5}+(frac{9-8.24}{9-1})^{1.5}}approx 3.74 ]

    4组测试样本的调整反距离预测值如下表,

    4组测试样本调整反距离预测值表
    测试样本X1X2X3预测值$widehat{Y}$
    1660413.74
    28.770447.31
    3191105760.44
    42813265104.35

    KNN分类和KNN预测函数返回结果为k近邻因变量值、k邻近距离和测试样本分类或因变量预测值数组,运用KNN进行数据挖掘可以在k近邻因变量值、k邻近距离数组基础上灵活处理。



    代码窗口

    注:可将例题实例代码复制、粘贴到“代码窗口”,点击“运行代码”获得计算结果(Ctrl+C:复制;Ctrl+V:粘贴;Ctrl+A:全选)

    运行效果

  • 相关阅读:
    程序运行bug查看
    c# webbrowser 的html调用js出错
    c# dll使用注意
    支持ie的时间控件 html
    sql 条件插入
    软件自动更新原理
    c# 数组不能直接=,需要clone
    打包成exe程序
    逆袭大学
    Heritage from father
  • 原文地址:https://www.cnblogs.com/cloudtj/p/6688037.html
Copyright © 2020-2023  润新知