欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《机器学习实战》第二章学习笔记1(knn算法)

程序员文章站 2022-07-14 19:42:12
...

一、k-近邻分类算法

1.1 工作原理

存在一个样本数据集合,也称作训练样本集,并且样本集的每个数据都存在标签,即我们知道样本集的每一数据与所属分类的对应关系。输入没有标签的新数据后, 将新数据的每个特征与样本集的数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

1.2 一般流程

  • 收集数据:可以使用任何方法。
  • 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
  • 分析数据:可以使用任何方法。
  • 训练算法:此步驟不适用于k-近邻算法。
  • 测试算法:计算错误率。
  • 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

1.3 优缺点及适用范围

  • 优点:精度高、对异常值不敏感、无数据输入假定。
  • 缺点:计算复杂度高、空间复杂度高。
  • 适用数据范围:数值型和标称型。

二、使用k-近邻算法改进约会网站的配对效果

2.1 利用k-近邻算法实现分类器

代码示例:

# -*- coding: utf-8 -*-
"""
Created on Thu Apr 12 21:23:22 2018
将该文件保存为kNN.py文件
@author: lizihua
"""
import numpy as np
import operator
import matplotlib.pyplot as plt

#k-近邻算法
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]     #获取行数
    #计算欧式距离
    #将inX扩维,使其与dataSet形状一致,以便实现获得X-dataSet数组
    diffMat = np.tile(inX, (dataSetSize,1))-dataSet  
    sqdiffMat = diffMat**2
    sqDisatances = sqdiffMat.sum(axis=1)
    distances=sqDisatances**0.5
    #argsort返回distance从小到大的排序索引,此时,distance并没有改变
    sortedDistIndicies=np.argsort(distances)
    classCount={}
    for i in range(k):
        #voteIlabel是按照distance从小到大排序的label
        voteIlabel = labels[sortedDistIndicies[i]]
        #计算前k个数中,各类出现的频率
        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
        #对字典进行排序,并返回列表
        #key=operator.itemgetter(1)代表按照第二个元素对字典排序,reversed=True代表从大到小排序
        #返回列表形式,例如:[('B', 2), ('A', 1)]
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

#输入文件名,输出训练样本矩阵和类标签向量
def file2matrix(filename):
    fr = open(filename)
    arrayOfLines = fr.readlines()
    numberOfLines = len(arrayOfLines)
    #样本有三个特征
    returnMat = np.zeros((numberOfLines,3))
    classLabelVector = []
    index = 0
    for line in arrayOfLines:
        line = line.strip()
        listFormLine = line.split('\t')
        #训练样本矩阵
        returnMat[index,:] = listFormLine[0:3]
        #类标签向量
        classLabelVector.append(int(listFormLine[-1]))
        index +=1
    return returnMat,classLabelVector

#归一化特征值
#newValue = (oldValue - min)/(max-min)
def autoNorm(dataSet):
    #求每一个特征的最小值、最大值及其差值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(dataSet.shape)
    m = dataSet.shape[0]
    normDataSet = dataSet -np.tile(minVals,(m,1))
    normDataSet = normDataSet/np.tile(ranges,(m,1))
    return normDataSet, ranges, minVals
    

#测试
if __name__=="__main__":
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals =autoNorm(datingDataMat)
    print("归一化后的数据:",normMat)
    print("三个特征的最大最小差值:",ranges)
    print("三个特征的最小值:",minVals)
    resultList = ['not at all','in small does','in large does']
    inArr=np.array([10000,10,0.5])
    resultindex = classify0(inArr,normMat,datingLabels,3)
    print("你喜欢这个人的可能性:",resultList[resultindex])   
    
    #飞行常客里程数与视频游戏百分比之间的散点图
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:,0],datingDataMat[:,1],
               15.0*np.array(datingLabels),15.0*np.array(datingLabels))
    #飞行常客里程数与每周冰淇淋公斤数之间的散点图
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111)
    ax1.scatter(datingDataMat[:,0],datingDataMat[:,2],
               15.0*np.array(datingLabels),15.0*np.array(datingLabels))    
    #视频游戏百分比与每周冰淇淋公斤数之间的散点图
    fig2 = plt.figure()
    ax2 = fig2.add_subplot(111)
    ax2.scatter(datingDataMat[:,1],datingDataMat[:,2],
               15.0*np.array(datingLabels),15.0*np.array(datingLabels))

结果显示:

《机器学习实战》第二章学习笔记1(knn算法)

飞行常客里程数与视频游戏百分比之间的散点图:

《机器学习实战》第二章学习笔记1(knn算法)

飞行常客里程数与每周冰淇淋公斤数之间的散点图:

《机器学习实战》第二章学习笔记1(knn算法)

视频游戏百分比与每周冰淇淋公斤数之间的散点图:

《机器学习实战》第二章学习笔记1(knn算法)

2.2 验证分类器

代码示例:

# -*- coding: utf-8 -*-
"""
Created on Thu Apr 12 20:25:41 2018
将该文件保存为kNN_test.py
@author: lizihua
"""
from kNN import file2matrix,autoNorm,classify0

def datingClassTest():
    hoRatio = 0.10
    datingDataMat,datingLabels =file2matrix('datingTestSet2.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("预测结果:%d,实际结果:%d"%(classifierResult,datingLabels[i]))
        if classifierResult!=datingLabels[i]:
            errorCount +=1
    print("错误率:",errorCount/numTestVecs)

#测试
if __name__=="__main__":
    datingClassTest()

部分结果显示:

《机器学习实战》第二章学习笔记1(knn算法)

三、利用sklearn模块中的knn算法

代码示例:

# -*- coding: utf-8 -*-
"""
Created on Fri Apr 13 17:08:14 2018

@author: Administrator
"""

from sklearn.neighbors import KNeighborsClassifier
import numpy as np

#输入文件名,输出训练样本矩阵和类标签向量
def file2matrix(filename):
    fr = open(filename)
    arrayOfLines = fr.readlines()
    numberOfLines = len(arrayOfLines)
    #样本有三个特征
    returnMat = np.zeros((numberOfLines,3))
    classLabelVector = []
    index = 0
    for line in arrayOfLines:
        line = line.strip()
        listFormLine = line.split('\t')
        #训练样本矩阵
        returnMat[index,:] = listFormLine[0:3]
        #类标签向量
        classLabelVector.append(int(listFormLine[-1]))
        index +=1
    return returnMat,classLabelVector

#归一化特征值
#newValue = (oldValue - min)/(max-min)
def autoNorm(dataSet):
    #求每一个特征的最小值、最大值及其差值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(dataSet.shape)
    m = dataSet.shape[0]
    normDataSet = dataSet -np.tile(minVals,(m,1))
    normDataSet = normDataSet/np.tile(ranges,(m,1))
    return normDataSet, ranges, minVals

#测试
if __name__=="__main__":
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals =autoNorm(datingDataMat)
    print("归一化后的数据:",normMat)
    print("三个特征的最大最小差值:",ranges)
    print("三个特征的最小值:",minVals)
    hoRatio = 0.10
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    resultList = ['not at all','in small does','in large does']
    #n_neighbors就是knn算法中的k,调用knn
    neigh = KNeighborsClassifier(n_neighbors=3)
    #训练:neigh.fit(X,y)//X是训练集,y是训练集对应的目标集,即分类标签
    neigh.fit(normMat[numTestVecs:m], datingLabels[numTestVecs:m])
    #预测回归结果:predict_proba(X)//X是测试集,返回预测回归结果(值)
    #预测分类结果:neigh.predict(X)//X是测试集,返回预测的分类结果(分类值)
    pred=neigh.predict(normMat[:numTestVecs])
    #计算准确率
    diff=pred-datingLabels[:numTestVecs]
    acc=np.sum(diff==0)/numTestVecs
    print("准确率:",acc)
    

结果显示:

《机器学习实战》第二章学习笔记1(knn算法)