机器学习实战之k近邻算法

k近邻算法是一种简单的分类方法,通过计算测试点与样本集中的距离,选择最近的K个点来决定新样本的类别。在处理多分类问题和稀有事件分类时表现出色,但面临样本不平衡和计算量大的问题。在实际应用中,如手写数字识别,需将图像转化为向量。
摘要由CSDN通过智能技术生成

k近邻算法:
或者说K最近邻(kNN,k-NearestNeighbor)
在一个空间中有许多样本,这时候来了一个新的样本即测试点,那么如何判断这个样本的类别。做法就是求测试点和空间中每个样本的距离,用距离最近的前K个判断。
比如下图新来了一个点,这时候K=3,离它最近的3个点就是一个为正方形,两个为三角形,那么就把新的点判定为三角形。
在这里插入图片描述
再比如:
训练集是二维数组[1.0,1.1],[1.0,1.0],[0.1,0],[0,0.1]
标签 labels=[‘A’,‘A’,‘B’,‘B’]
测试集[0.2,0.1]
k=3
首先计算测试集和训练集之间的距离
在这里插入图片描述
点[0.2,0.1]与[1.0,1.1]之间的距离计算为:
在这里插入图片描述
计算完所有点之间的距离之后从小到大排序,选取前k个距离,对进行遍历,将对应标签加一。如[A:1,B:2]这里就输出A

算法的优点:
1、简单,易于理解,易于实现,无需估计参数,无需训练
2、适合对稀有事件进行分类
3、特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好
算法的缺点:
1、该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。 该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。
2、该方法的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。

程序实现:

from numpy import *
import operator
def createDataSet():    #创建标签和数据
    group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group,labels
def classifify0(inX,dataSet,labels,k):      
    dataSetSize=dataSet.shape[0]      # dataSetSize=4    计算距离
    diffMat=tile(inX,(dataSetSize,1))-dataSet #tile(inX,(dataSetSize,1)),让inX变为和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
    sortedCalssCount=sorted(classCount.items(),
                            key=operator.itemgetter(1),reverse=True)
    return sortedCalssCount[0][0]
group,labels=createDataSet()
print(classifify0([1, 0.5], group, labels, 3))

手写数字体识别
图片大小:28×28
为了使用上述分类器,需将图片转换为向量形式1×784

from numpy import *
import operator
from keras.datasets import mnist
import numpy as np
(X_train, Y_train),(X_test, Y_test) = mnist.load_data()
X_train=X_train[0:10000]        #取10000个训练
Y_train=Y_train[0:10000]
X_test=X_test[0:100]             #取100个测试
Y_test=Y_test[0:100]
aa=X_train[1].reshape(1,784)
def classifify0(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]      # dataSetSize=4
    diffMat=tile(inX,(dataSetSize,1))-dataSet #tile(inX,(dataSetSize,1)),让inX变为和dataSet一样的类型
    sqDiffMat=diffMat**2 #
    sqDistances=sqDiffMat.sum(axis=1)
    distances=sqDistances**0.5
    sortedDistIndicies=distances.argsort()
    classCount={}
    for i in range(k):
        voteIlabel=labels[sortedDistIndicies[i]]
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    sortedCalssCount=sorted(classCount.items(),
                            key=operator.itemgetter(1),reverse=True)
    return sortedCalssCount[0][0]

def handwriting(X_train,Y_train,X_test,k):
    hwlabels=[]
    m=len(X_train)
    trainingMat=zeros((m,784))
    for i in range(m):
        trainingMat[i,:]=X_train[i].reshape(1,784)   #将图片转换为向量形式
    mTest=len(X_test)
    for i in range(mTest):
        wordtest=X_test[i].reshape(1,784)
        classresult=classifify0(wordtest,trainingMat,Y_train,k)
        hwlabels.append(classresult)
        #print("result:{},true{}".format(classresult,Y_test[i]))
    return hwlabels
k=[10,50,100,150]         #取前k个
for i in range(len(k)):
    classresult=handwriting(X_train,Y_train,X_test,k[i])
    aa=(classresult == Y_test).astype(np.int32)
    acc=sum(aa)/len(Y_test)
    print(acc)

在这里插入图片描述
总结:k近邻算法比较简单和有效,但是需要大量的存储空间,比较耗时

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值