K-近邻算法(KNN)

目录

概述

一个简单的分类器

示例:使用k-近邻算法改进约会网站的配对效果

(1)收集数据

(2)准备数据:用python解析,归一化数值

(3)分析数据:使用Matplotlib创建散点图

(4)训练算法(此步骤不适合k-近邻算法)

(5)测试算法

(6)使用算法

使用k-邻近算法识别手写数字


概述

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

缺点:计算,空间,复杂度较高

适用于:数值型(连续型),标称型

简单来说:就是采用测量不同特征值之间的距离方法进行分类

一个简单的分类器

大致的作用:自己构建了四个点,为它们附上标签,让程序以这些为指标,判断不同的点应该对应A还是B

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          #返回值

group,labels=createDataSet()

def classify0(inX, dataSet, labels, k):#(要判断的数据,原数据,原数据类型,前k个)
    dataSetSize = dataSet.shape[0] #矩阵第一维的长度
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #根据训练数据大小生成
    sqDiffMat = diffMat**2 #二维特征相减后平方
    sqDistances = sqDiffMat.sum(axis=1) ########沿着列(但不是很懂为啥)
    distances = sqDistances**0.5 #累加开方
    sortedDistIndicies = distances.argsort()#返回distances中元素从小到大排序后的索引值
    classCount = {} #开一个记录类别次数的字典
    for i in range(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]

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

示例:使用k-近邻算法改进约会网站的配对效果

(1)收集数据

   此处有给定的一些数据,存放在同一个文件夹下ceshi1.txt文件中

(2)准备数据:用python解析,归一化数值

import numpy as np
import operator


def file2matrix(filename):
    love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}#字典定义三的类别
    fr = open(filename)#打开文件
    arrayOLines = fr.readlines() #逐行处理,readlines()方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
    numberOfLines = len(arrayOLines) #算行数
    returnMat = np.zeros((numberOfLines, 3)) #初始化numpy型, numberOfLines*3大小的特征矩阵
    classLabelVector = [] #初始化标签
    index = 0   #行索引
    for line in arrayOLines:
        line = line.strip() #删空格
        listFromLine = line.split('\t') #用空格分割   成列表
        #没懂为啥是三个
        returnMat[index, :] = listFromLine[0:3]
        #如果是数字
        if(listFromLine[-1].isdigit()):
            #直接赋值到标签
            classLabelVector.append(int(listFromLine[-1]))
        else:
            #如果是字符串,用love_dictionary转换
            classLabelVector.append(love_dictionary.get(listFromLine[-1]))
        index += 1 #索引的移动
    return returnMat, classLabelVector


def autoNorm(dataSet):
    #最大最小
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    #创建全0的初始矩阵
    normDataSet = np.zeros(np.shape(dataSet))
    #行数
    m = dataSet.shape[0]
    #原始值减去最小值除以最大和最小值的差(书上归一化数据的方法)
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet/np.tile(ranges, (m, 1))
    return normDataSet, ranges, minVals

returnMat,classLabelVector=file2matrix('ceshi1.txt')
normDataSet,ranges,minVals=autoNorm(returnMat)

print(normDataSet)
print(ranges)
print(minVals)

(3)分析数据:使用Matplotlib创建散点图

import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt


def file2matrix(filename):
    love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)           
    returnMat = np.zeros((numberOfLines, 3))      
    classLabelVector = []                       
    index = 0
    for line in arrayOLines:
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index, :] = listFromLine[0:3]
        if(listFromLine[-1].isdigit()):
            classLabelVector.append(int(listFromLine[-1]))
        else:
            classLabelVector.append(love_dictionary.get(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector
a,b=file2matrix('ceshi1.txt')

fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(a[:,1],a[:,2],15.0*np.array(b),15.0*np.array(b))
 # 保证图片中输出的文字为中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 输出横纵坐标上的文字
plt.xlabel("玩游戏所耗时间百分比")
plt.ylabel("每周消耗的冰淇淋公升数")
plt.show()

(4)训练算法(此步骤不适合k-近邻算法)

(5)测试算法

import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt

#读取数据
def file2matrix(filename):
    love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}#字典定义三的类别
    fr = open(filename)#打开文件
    arrayOLines = fr.readlines() #逐行处理,readlines()方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
    numberOfLines = len(arrayOLines) #算行数
    returnMat = np.zeros((numberOfLines, 3)) #初始化numpy型, numberOfLines*3大小的特征矩阵
    classLabelVector = [] #初始化标签
    index = 0   #行索引
    for line in arrayOLines:
        line = line.strip() #删空格
        listFromLine = line.split('\t') #用空格分割   成列表
        #没懂为啥是三个
        returnMat[index, :] = listFromLine[0:3]
        #如果是数字
        if(listFromLine[-1].isdigit()):
            #直接赋值到标签
            classLabelVector.append(int(listFromLine[-1]))
        else:
            #如果是字符串,用love_dictionary转换
            classLabelVector.append(love_dictionary.get(listFromLine[-1]))
        index += 1 #索引的移动
    return returnMat, classLabelVector

#归一化处理
def autoNorm(dataSet):
    #最大最小
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    #创建全0的初始矩阵
    normDataSet = np.zeros(np.shape(dataSet))
    #行数
    m = dataSet.shape[0]
    #原始值减去最小值除以最大和最小值的差(书上归一化数据的方法)
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet/np.tile(ranges, (m, 1))
    return normDataSet, ranges, minVals


def classify0(inX, dataSet, labels, k):#(要判断的数据,原数据,原数据类型,前k个)
    dataSetSize = dataSet.shape[0] #矩阵第一维的长度
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #根据训练数据大小生成
    sqDiffMat = diffMat**2 #二维特征相减后平方
    sqDistances = sqDiffMat.sum(axis=1) ########沿着列(但不是很懂为啥)
    distances = sqDistances**0.5 #累加开方
    sortedDistIndicies = distances.argsort()#返回distances中元素从小到大排序后的索引值
    classCount = {} #开一个记录类别次数的字典
    for i in range(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]


def datingClassTest():
    #整个数据10%来测试
    hoRatio = 0.1
    datingDataMat, datingLabels = file2matrix('ceshi1.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    #样本个数
    m = normMat.shape[0]
    #测试个数
    numTestVecs = int(m*hoRatio)
    #错误计数
    errorCount = 0.0
    for i in range(numTestVecs):
        #前一些为测试的,后一些用作训练
        classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print("the total error rate is: %f" % (errorCount / float(numTestVecs)))
    print(errorCount)


datingClassTest()












(6)使用算法

import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt

#读取数据
def file2matrix(filename):
    love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}#字典定义三的类别
    fr = open(filename)#打开文件
    arrayOLines = fr.readlines() #逐行处理,readlines()方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
    numberOfLines = len(arrayOLines) #算行数
    returnMat = np.zeros((numberOfLines, 3)) #初始化numpy型, numberOfLines*3大小的特征矩阵
    classLabelVector = [] #初始化标签
    index = 0   #行索引
    for line in arrayOLines:
        line = line.strip() #删空格
        listFromLine = line.split('\t') #用空格分割   成列表
        #没懂为啥是三个
        returnMat[index, :] = listFromLine[0:3]
        #如果是数字
        if(listFromLine[-1].isdigit()):
            #直接赋值到标签
            classLabelVector.append(int(listFromLine[-1]))
        else:
            #如果是字符串,用love_dictionary转换
            classLabelVector.append(love_dictionary.get(listFromLine[-1]))
        index += 1 #索引的移动
    return returnMat, classLabelVector

#归一化处理
def autoNorm(dataSet):
    #最大最小
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    #创建全0的初始矩阵
    normDataSet = np.zeros(np.shape(dataSet))
    #行数
    m = dataSet.shape[0]
    #原始值减去最小值除以最大和最小值的差(书上归一化数据的方法)
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet/np.tile(ranges, (m, 1))
    return normDataSet, ranges, minVals


def classify0(inX, dataSet, labels, k):#(要判断的数据,原数据,原数据类型,前k个)
    dataSetSize = dataSet.shape[0] #矩阵第一维的长度
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #根据训练数据大小生成
    sqDiffMat = diffMat**2 #二维特征相减后平方
    sqDistances = sqDiffMat.sum(axis=1) ########沿着列(但不是很懂为啥)
    distances = sqDistances**0.5 #累加开方
    sortedDistIndicies = distances.argsort()#返回distances中元素从小到大排序后的索引值
    classCount = {} #开一个记录类别次数的字典
    for i in range(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]


def classifyPerson():
    resultList = ['not at all', 'in small doses', 'in large doses']
    percentTats = 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?"))
    datingDataMat, datingLabels = file2matrix('ceshi1.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr = np.array([ffMiles, percentTats, iceCream, ])
    classifierResult = classify0((inArr - \
                                  minVals)/ranges, normMat, datingLabels, 3)
    print("You will probably like this person: %s" % resultList[classifierResult - 1])


classifyPerson()








使用k-邻近算法识别手写数字

未完待续

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心刍

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

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

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

打赏作者

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

抵扣说明:

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

余额充值