Machine Learning:k近邻算法(KNN)

写在前面的话

大概是上半年准备美赛的时候,才发现仅仅具备C语言的知识,如果想对数据进行分析和挖掘,实在太过简陋,并且当时对相关算法了解甚少。这个学期有幸选了黄教授的数据科学概论一课,他曾经在课上向我们推荐了《机器学习实战》一书。这段时间抽空读了一下,感觉受益颇深,正巧赶完了期末大作业,便把学到的算法以专栏的形式整理出来。一方面便于自己复习巩固,另一方面书中的Python代码并非最新版本,许多参数已经删改,博主也趁此机会完善一下代码,并且给予充足的注释,以飨读者。

k-近邻算法概述

k-近邻算法本质上是一种分类算法,主要采用测量不同特征值之间距离的方法实现

优点

精度高、对异常值不敏感、无数据输入假定

缺点

计算复杂度高、空间复杂度高

适用数据范围

数值型、标称型

原理

(1)计算输入数据与样本集中数据的距离
(2)对距离进行排序
(3)选出前k个最相似的数据(距离最短)
(4)将这些数据中类别出现次数最多的类别作为新数据的分类

Python代码实现

我们以二维数据为例

import numpy as np
import operator
def createDataSet():   #生成数据集的函数
    group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])   #数值坐标
    labels = ['A','A','B','B']   #类别
    return group, labels
def title(inY, Size):   #对输入数据进行预处理的函数
    x = Size[0]   #数据个数
    y = Size[1]   #数据维数
    result = np.zeros((x, y))
    for i in range(x):
        result[[i],:] = inY   #利用逐层替换的方式生成初始化数据,这一矩阵由输入数据重复x遍构成
    return result
def classify0(inX, dataSet, labels, k):   #分类器函数
    dataSetxSize = dataSet.shape[0]
    dataSetySize = dataSet.shape[1]
    diffMat = title(inX, (dataSetxSize, dataSetySize)) - dataSet   #开始计算欧氏距离
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()   #排序
    classCount={}
    for i in range(k):   #获取前k个数据的类别
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]
group,labels = createDataSet()

classify0([0,0], group, labels, 3)   #测试语句

Sklearn直接调用

当然,强大的Python自带KNN算法包,下面简述一下几个重要参数的意义

def KNeighborsClassifier(n_neighbors,    #k值
                       weights,          #权重
                       algorithm,        #用于实现KNN的算法
                       leaf_size,        #停止建子树的叶子节点数量,默认30
                       p,                #当metric参数设置为“minkowski”时,p=1为曼哈顿距离,p=2为欧式距离,默认p=2
                       metric)           #距离度量方法

此外有两个参数有具体选项

weights选项

uniformdistance自定义函数
不加权权重和距离成反比

algorithm选项

brutekd_treeball_treeauto
暴力实现KD树实现KD球树实现默认参数,自动选择合适的方法
import numpy as np
import operator
from sklearn.neighbors import KNeighborsClassifier
def createDataSet():
    group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group, labels
def classify0(inX, dataSet, labels, k):
    inX = np.array(inX).reshape(-1,2)   #改变输入数据格式以符合要求
    knn = KNeighborsClassifier(n_neighbors=k)   #设定k值,构建分类器
    result = knn.fit(dataSet, labels)   #拟合数据
    pre = knn.predict(inX)   #预测新数据
    return pre
group,labels = createDataSet()

print(classify0([0,0], group, labels, 3))

很明显,用自带的库实现这一算法,其代码实现更为简洁(功能、效率都更加强大)

算法测试与结果评价

这里我们采用的方法是K折交叉验证

原理及方法

(1)不重复抽样,将原始数据随机分为 k 份
(2)挑选其中一份作为测试集,剩余 k-1 份作为样本集,进行测试
(3)重复第二步 k 次
(4)计算 k 组测试结果的平均值,作为模型的性能指标

函数主要参数说明

sklearn.model_selection.cross_val_score(estimator,          #需要验证的算法
                                        X,                  #数据数值
                                        y,                  #数据类别
                                        cv)                 #交叉验证折数

Python代码实现

由于我们构建的数据集已不再适合应用这一检验,遂使用更庞大的数据集
代码来源

from sklearn.datasets import load_iris
from sklearn.model_selection  import cross_val_score
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier

iris = load_iris()   #Python自带数据集读取
x = iris.data
y = iris.target
k_range = range(1, 31)
k_error = []

for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    scores = cross_val_score(knn, x, y, cv=6, scoring='accuracy')   #cv参数决定数据集划分比例,这里是按照5:1划分训练集和测试集
    k_error.append(1 - scores.mean())

plt.plot(k_range, k_error)
plt.xlabel('Value of K for KNN')
plt.ylabel('Error')
plt.show()

示例

以后有机会用书中实例予以补充

反思与总结

这是这个专栏的第一篇博客,写完后还是有很多感触的。
初次建模,或者说进行数据分析,一定要构建整个过程的框架,从数据的预处理、构建数据集,到模型的选择、建立、优化,再到预测与评估。
记得曾经在知乎上看到过一项挑战,大致意思是给出一张图片,根据图中信息判断拍摄者所处的位置,看视频时我情绪高涨,事后想了想,当初参与建模比赛,其实向往的是数据背后的故事。
死气沉沉的数字,总能带给我们一些现实意义,对于追寻这些意义的过程,最起码到目前为止,我认为是快乐的。
博主非统计专业,这方面不是专家,如有纰漏或需要补充的地方,烦请各位大佬在评论区指出,如您觉得写的不错,记得一键三连哟
(^U^)ノ~YO

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

放牧星辰dmc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值