1.1-机器学习分类算法-k近邻算法

1.K近邻算法原理简介

KNN(k-Nearest Neighbors)也就是传说中的K近邻算法。这个算法的核心是如果一个样本和k个样本最相似,并且这k个样本大多数属于同一个分类,则这个样本也属于该分类。距离一般使用的是欧式距离,欧式距离的计算公式如下:

k近邻算法的基本流程就是以下几步:

  • 1.计算输入点到所有样本点的欧式距离
  • 2.欧式距离排序取最近的K个(通常是不大于20的整数
  • 3.找欧式距离最近的K个中所属分类最多的分类是哪个

因此,从上面的计算过程我们可以发现,最重要的其实就是K值的选取。如果K值选的太大,考虑极限情况K=N,无论输入什么,都将被预测属于样本集中最多的类。如果K值选的太小,可能会发生过拟合。

2.K近邻算法使用案例

2.1 电影分类问题

这里使用根据电影中接吻镜头、打斗镜头等方法来判断电影类型作为案例。假设用于预测的样本数据集格式如下:

电影名称 打斗镜头数量 接吻镜头数量
使命召唤 100 0
功夫熊猫 115 0
极速追杀 135 0
101次求婚 0 5
爱的抱抱 1 13
基因决定我爱你 1 9
#创建数据集
import numpy as np
import matplotlib.pyplot as plt
def createDataSet():
    group = np.array([ [0,5],[115,0],[135,0],[1,13],[1,9],[100,0]])
    labels = ['B','A','A','B','B','A']
    return group,labels
#数据集特征分布示意图
group,labels = createDataSet()
plt.plot(group[:,0], group[:,1], 'o', color='green', markeredgewidth=2, markersize=10)
[<matplotlib.lines.Line2D at 0x1157b7e48>]

#假设新增一个影片,其中特征为70个打斗镜头和1个接吻镜头。
new_movie=[60,9]
def takeElemNeedTobeSorted(elem):
    return elem[0]
def classify(point,group,labels):
    dist_list = []
    num = 0
    for tmp_point in group:
        ##dist = np.sqrt((tmp_point[0]-point[0])**2+(tmp_point[1]-point[1])**2) #计算欧式距离
        numOfFeature = len(tmp_point) #获取特征数量
        dist=0
        for i in range(numOfFeature):
            dist+=(tmp_point[i]-point[i])**2 #累加特征数量平方差
        dist = np.sqrt(dist)
        dist_list.append([dist,num]) #保存距离和序号
        num+=1
    dist_list.sort(key=takeElemNeedTobeSorted) #按照距离排序
    #统计前K个距离最近的点的类型,这里假设K是3
    K=3
    nearKTypeDict = {}
    for i in range(K):
        num = dist_list[i][1]
        if labels[num] in nearKTypeDict.keys():
            nearKTypeDict[labels[num]]+=1
        else:
            nearKTypeDict[labels[num]]=1
    nearKTypeDict= sorted(nearKTypeDict.items(),key=lambda x:x[1],reverse=True)#根据类别数量排序
    return nearKTypeDict[0][0]
print("当前类别为%s"%classify(new_movie,group,labels))
当前类别为A

2.2 基于K近邻算法的约会网站配对优化

提供的样本特征主要包括一下三点: - 每年的飞行里程数 - 玩游戏看视频所占用时间的百分比 - 每周吃冰淇淋的公升数

样本集的分类有以下三种: - didntLike:不喜欢 - smallDoses:有点喜欢 - largeDoses:非常喜欢

数据文件名为:datingTestSet.txt,该文件为一千行文本文件,样例如下:

40920   8.326976    0.953952    largeDoses
14488   7.153469    1.673904    smallDoses
26052   1.441871    0.805124    didntLike
#读入数据,处理成符合之前分类函数的格式
import numpy as np
def getDatingTestSet():
    with open("attach/datingTestSet.txt") as f:
        data=f.read().split("\n")
    DatingTestSet = []
    TestDatalabelSet = []
    for i in data:
        data = i.split("\t")
        #print(data)
        if(len(data)>1):
            data[0] = float(data[0])
            data[1] = float(data[1])
            data[2] = float(data[2])
            TestDatalabelSet.append(data[3])
            data.pop()
            DatingTestSet.append(data)
    DatingTestSet = np.array(DatingTestSet)
    return DatingTestSet,TestDatalabelSet
DatingTestSet,TestDatalabelSet = getDatingTestSet()
#对数值进行归一化处理:这里第一个特征的值明显大于其他两个,所以需要进行归一化处理
def dataNormal(dataSet):
    numOfFeature = len(dataSet[0])
    for i in range(numOfFeature):
        minData = np.min(dataSet[:,i])
        maxData = np.max(dataSet[:,i])
        for data in dataSet:
            data[i] = (data[i]-minData)/(maxData-minData)
    return dataSet
DatingTestSet = dataNormal(DatingTestSet)
#print(DatingTestSet)
#将数据集划分成900个训练数据,100个测试数据。并进行测试
trainDataSet = DatingTestSet[0:900]
testDataSet = DatingTestSet[900:1000]
testDataLabel = TestDatalabelSet[900:1000]
num = 0
trueNum = 0.0
falseNum = 0.0
for data in testDataSet:
    res = classify(data,trainDataSet,TestDatalabelSet)
    if res==testDataLabel[num]:
        trueNum +=1
    else:
        falseNum +=1
    num+=1
accuracy = trueNum/(falseNum+trueNum)
errorRate = falseNum/(falseNum+trueNum)
print("预测成功率为:%f\n"%accuracy)
print("预测失败率为:%f\n"%errorRate)
预测成功率为:0.940000

预测失败率为:0.060000

参考链接:

  • https://www.cnblogs.com/zhangkanghui/p/11289260.html 从0开始手工实现KNN
  • https://blog.csdn.net/sinat_30353259/article/details/80901746 图和数学推导
  • 《机器学习实战》