用Python完整实现KNN算法

 

目录

前言

1、K-近邻算法概述

2、K-近邻算法的一般流程

3、具体模块实现

4、附完整代码

前言

  • 代码运行环境是pycharm,编译器是anaconda3,任何IDE或者编辑器都能运行此 demo,只要配置好环境即可

  • 数据集链接https://www.manning.com/books/machine-learning-in-action  sourcecode文件中cho2章节datingTestSet2.txt

1、K-近邻算法概述

简单地说,k-近邻算法就是利用不同特征值之间的距离来进行分类。

优点:精度高,对异常值不敏感,无数据输入假定

缺点:计算复杂度高、空间复杂度高

试用数据范围:数值型和标称型

2、K-近邻算法的一般流程

  • 数据收集:可以使用任何方法收集数据,如爬虫、本地数据、第三方数据源等。
  • 数据处理:主要任务是把源数据格式转换成算法要求的输入数据格式。
  • 分析数据:可以使用任何方法,如Python可视化的工具库等,对数据进行主观的分析。
  • 训练算法:将处理好的数据输入到模型中。
  • 测试算法:测试模型的训练效果,一般的衡量指标是错误率(分类错误的实例个数/总的输入实例数)。
  • 使用算法:可将训练测试好的模型进行实际的打包使用。

3、具体模块实现

(1)使用Python导入数据

def file2Matrix(filename):#输入标准化(转变成算法能处理的输入格式)
    fr = open(filename)
    arraylines = fr.readlines()
    numberOfLines = len(arraylines)
    returnMat = zeros((numberOfLines, 3))  # 输入矩阵
    classLabelVector = []  # 标签矩阵
    index = 0
    for line in arraylines:
        lis = line.strip().split('\t')
        returnMat[index, :] = lis[0:3]
        classLabelVector.append(int(lis[-1]))
        index += 1
    return returnMat, classLabelVector  # 返回数据集矩阵和标签矩阵

(2)数据可视化

def data_Show(datingMat,LabelsMat):#数据可视化分析
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingMat[:,0],datingMat[:,1],c=LabelsMat)
    plt.show()

(3)数据归一化

def auto_Norm(datingMat):#数据归一化
    min = datingMat.min(0)
    max = datingMat.max(0)
    range = max - min
    normMat = zeros(shape(datingMat))
    m = datingMat.shape[0]
    normMat = datingMat - tile(min,(m,1))
    normMat = normMat/tile(range,(m,1))
    return normMat, range,min

(4)构造分类器

def classify(inX,datingMat,Labels,k):#构造分类器
    data_size = datingMat.shape[0]#数据集行数
    diffMat = tile(inX,(data_size,1)) - datingMat
    sqdiffMat = diffMat**2
    distance = (sqdiffMat.sum(axis = 1))**0.5#计算距离,先算平方和再开根号 axis = 0是按列(跨行)求和 axis =1是按行(跨列)求和
    sorted_distance = distance.argsort()#返回的是数组值从小到大的索引值
    classcount = {}#字典
    for i in range(k):
        votelabel = Labels[sorted_distance[i]]#sorted_distance[i]是获取第i近的索引值,然后根据索引去Labels中找对应的标签
        classcount[votelabel] = classcount.get(votelabel,0)+1#把第K近的标签都添加到字典中并累加出现的标签次数
    print(classcount)
    sorted_classcount = sorted(classcount.items(),key=operator.itemgetter(1),reverse=True)#python3中items()已取代iteritems()   key指定按哪个轴或者项进行排序
    return sorted_classcount[0][0]#注意下这两个函数 classcount.items()把字典变成可迭代的列表(字典项变成列表项) operator.itemgetter(1)获取第1个域值

(5)测试分类器

def dating_Test(normMat,LabelsMat):#测试分类器
    hoRatio = 0.1#测试率(这里是10%)
    m = normMat.shape[0]
    test_vecs = int(m*hoRatio)#选择测试集
    errorcount = 0
    for i in range(test_vecs):
        classify_result = classify(normMat[i,:],normMat[test_vecs:m,:],LabelsMat[test_vecs:m],3)
        print("the classifier came back with: %d, the real answer is: %d" % (classify_result,LabelsMat[i]))
        if (classify_result != LabelsMat[i]):
            errorcount += 1.0
    print("the total error rate is: %f" % (errorcount/float(test_vecs)))
def classifyPerson(datingMat,LabelsMat):#实际使用,即输入数据集中不存在的实例进行测试
    resultList = ['not at all','in small doses','in large doses']
    personTats = float(input("percentage of time spent playing video games?"))
    ffMiles = float(input("frequent flier miles earned per year?"))
    iceCream = float(input("liters of ice cream consumed per year?"))
    normMat, range, min = auto_Norm(datingMat)
    inArr = array([ffMiles,personTats,iceCream])
    classifyResult = classify((inArr-min)/range,normMat,LabelsMat,3)
    print("you will probably like this person: ",resultList[classifyResult-1])

(6)主函数调用

def main():
    path = "datingTestSet2.txt"#数据集路径(默认在当前工作目录下)
    datingMat, LabelsMat = file2Matrix(path)
    #data_show(datingMat,LabelsMat)
    #normMat,range,min = auto_Norm(datingMat)
    #dating_Test(normMat,LabelsMat)
    classifyPerson(datingMat,LabelsMat)
main()

4、附完整代码

from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt
def file2Matrix(filename):#输入标准化(转变成算法能处理的输入格式)
    fr = open(filename)
    arraylines = fr.readlines()
    numberOfLines = len(arraylines)
    returnMat = zeros((numberOfLines, 3))  # 输入矩阵
    classLabelVector = []  # 标签矩阵
    index = 0
    for line in arraylines:
        lis = line.strip().split('\t')
        returnMat[index, :] = lis[0:3]
        classLabelVector.append(int(lis[-1]))
        index += 1
    return returnMat, classLabelVector  # 返回两个矩阵
def data_Show(datingMat,LabelsMat):#数据可视化分析
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingMat[:,0],datingMat[:,1],c=LabelsMat)
    plt.show()
def auto_Norm(datingMat):#数据归一化
    min = datingMat.min(0)
    max = datingMat.max(0)
    range = max - min
    normMat = zeros(shape(datingMat))
    m = datingMat.shape[0]
    normMat = datingMat - tile(min,(m,1))
    normMat = normMat/tile(range,(m,1))
    return normMat, range,min
def classify(inX,datingMat,Labels,k):#构造分类器
    data_size = datingMat.shape[0]#数据集行数
    diffMat = tile(inX,(data_size,1)) - datingMat
    sqdiffMat = diffMat**2
    distance = (sqdiffMat.sum(axis = 1))**0.5#计算距离,先算平方和再开根号 axis = 0是按列(跨行)求和 axis =1是按行(跨列)求和
    sorted_distance = distance.argsort()#返回的是数组值从小到大的索引值
    classcount = {}#字典
    for i in range(k):
        votelabel = Labels[sorted_distance[i]]#sorted_distance[i]是获取第i近的索引值,然后根据索引去Labels中找对应的标签
        classcount[votelabel] = classcount.get(votelabel,0)+1#把第K近的标签都添加到字典中并累加出现的标签次数
    print(classcount)
    sorted_classcount = sorted(classcount.items(),key=operator.itemgetter(1),reverse=True)#python3中items()已取代iteritems()   key指定按哪个轴或者项进行排序
    return sorted_classcount[0][0]#注意下这两个函数 classcount.items()把字典变成可迭代的列表(字典项变成列表项) operator.itemgetter(1)获取第1个域值(从0开始)
def dating_Test(normMat,LabelsMat):#测试分类器
    hoRatio = 0.1#测试率(这里是10%)
    m = normMat.shape[0]
    test_vecs = int(m*hoRatio)#选择测试集
    errorcount = 0
    for i in range(test_vecs):
        classify_result = classify(normMat[i,:],normMat[test_vecs:m,:],LabelsMat[test_vecs:m],3)
        print("the classifier came back with: %d, the real answer is: %d" % (classify_result,LabelsMat[i]))
        if (classify_result != LabelsMat[i]):
            errorcount += 1.0
    print("the total error rate is: %f" % (errorcount/float(test_vecs)))
def classifyPerson(datingMat,LabelsMat):#实际使用,即输入数据集中不存在的实例进行测试
    resultList = ['not at all','in small doses','in large doses']
    personTats = float(input("percentage of time spent playing video games?"))
    ffMiles = float(input("frequent flier miles earned per year?"))
    iceCream = float(input("liters of ice cream consumed per year?"))
    normMat, range, min = auto_Norm(datingMat)
    inArr = array([ffMiles,personTats,iceCream])
    classifyResult = classify((inArr-min)/range,normMat,LabelsMat,3)
    print("you will probably like this person: ",resultList[classifyResult-1])
def main():
    path = "datingTestSet2.txt"#数据集路径(默认在当前工作目录下)
    datingMat, LabelsMat = file2Matrix(path)
    #data_show(datingMat,LabelsMat)
    #normMat,range,min = auto_Norm(datingMat)
    #dating_Test(normMat,LabelsMat)
    classifyPerson(datingMat,LabelsMat)
main()

 

 

 

 

 

你可能感兴趣的:(机器学习)