机器学习实战之KNN算法

本文介绍了KNN算法的工作原理和流程,包括数据收集、准备、分析和测试,并通过Python实现了一个KNN算法示例。讨论了算法的优缺点,如精度高但对异常值不敏感,以及在大数据集上可能存在的效率和存储问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  机器学习实战这本是用python进行开发的,python环境的安装就不用多说了。
本书封面
  先来说一下我自己的环境把:我用的是python 3.6.5,本书用的是python 2.7,本书的代码英文版出版商的http://www.manning.com/MachineLearninginAction可以下载到。

  如果你已经配置好了相关的环境,下面可以开始相应的算法实战。

一、k临近算法(KNN)的工作原理

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

  k近邻算法的一般流程:

  1. 收集数据:可以采用公开的数据集
  2. 准备数据:计算距离所需要的数值
  3. 分析数据:剔除垃圾信息
  4. 测试算法:计算错误率
  5. 使用算法:运用在实际中,对实际情况进行预测

二、算法的具体实施过程
   (1)使用python导入数据

from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt
from os import listdir


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

   (2)实施KNN算法

  k近邻算法对未知类别属性的数据集中每个点依次执行如下步骤:

  1. 计算已知类别数据集中的点与当前点之间的距离
  2. 按照距离递增次序排序
  3. 选取与当前点距离最小的k个点
  4. 确定前k个点所在类别的出现频率
  5. 返回前k个点出现频率最高的类别作为当前点的预测分类

具体代码如下:

# -------------------------构建分类器-------------------------------
# KNN算法实施
# @inX  测试样本数据
# @dataSet  训练样本数据
# @labels  测试样本标签
# @k  选取距离最近的k个点
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    print(dataSetSize)  # 获取第一维的维度  4*2  也就是4
    # tile 重复inX维度(4,1) inX = [0,0]  ==>先横向复制4次,纵向复制1次,也就是本身 最后的维度(4,2)
    # 这儿求欧式距离,都是求到0 0 的距离 以下几行都是求欧式距离

    # ————————————欧式距离————————————————————
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet  # 新样本与原样本的差值矩阵
    sqDiffMat = diffMat ** 2  # 求平方
    # .sum()运行加函数,参数axis=1表示矩阵每一行的各个值相加和
    sqDistances = sqDiffMat.sum(axis=1)
    print(sqDistances)
    distances = sqDistances ** 0.5
    # ————————————————————————————————————
    print(distances)
    # 获取排序(有小到大)后的距离值的索引(序号)
    sortedDistIndicies = distances.argsort()
    print(sortedDistIndicies)
    classCount = {}
    for i in range(k):
        # 获取该索引对应的训练样本的标签
        voteIlabel = labels[sortedDistIndicies[i]]
        # 累加几类标签出现的次数,构成键值对key/values并存于classCount中
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    # 将字典列表中按照第二列,也就是次数标签,反序排序(由大到小排序)
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    # 返回第一个元素(最高频率)标签key
    return sortedClassCount[0][0]

   (3)测试分类器
 实例1:使用kNN改进某约会网站的配对效果

# -------------------------约会网站配对-----------------------------------
# --------------1 将text文本数据转化为NumPy可以接受的格式---------------
def file2matrix(filename):
    # 打开文件
    fr = open(filename)
    # 读取文件每一行到array0Lines列表
    # read():读取整个文件,通常将文件内容放到一个字符串中
    # readline():每次读取文件一行,当没有足够内存一次读取整个文件内容时,使用该方法
    # readlines():读取文件的每一行,组成一个字符串列表,内存足够时使用
    array0Lines = fr.readlines()
    # 获取字符串列表行数行数
    numberOfLines = len(array0Lines)
    # 返回的特征矩阵大小
    returnMat = zeros((numberOfLines, 3))
    # list存储类标签
    classLabelVector = []
    index = 0
    for line in array0Lines:
        # 去掉字符串头尾的空格,类似于Java的trim()
        line = line.strip()
        # 将整行元素按照tab分割成一个元素列表
        listFromLine = line.split('\t')
        # 将listFromLine的前三个元素依次存入returnmat的index行的三列
        returnMat[index, :] = listFromLine[0:3]
        # python可以使用负索引-1表示列表的最后一列元素,从而将标签存入标签向量中
        # 使用append函数每次循环在list尾部添加一个标签值
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector


# ----------------2 准备数据:归一化----------------------------------------------
# 计算欧式距离时,如果某一特征数值相对于其他特征数值较大,那么该特征对于结果影响要
# 远大于其他特征,然后假设特征都是同等重要,即等权重的,那么可能某一特征对于结果存
# 在严重影响
def autoNorm(dataSet):
    # 找出每一列的最小值
    minVals = dataSet.min(0)
    # 找出每一列的最大值
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    # 创建与dataSet等大小的归一化矩阵
    # shape()获取矩阵大小
    normDataSet = zeros(shape(dataSet))
    # 获取dataSet第一维度的大小
    m = dataSet.shape[0]
    # 将dataSet的每一行的对应列减去minVals中对应列的最小值
    normDataSet = dataSet - tile(minVals, (m, 1))
    # 归一化,公式newValue=(value-minvalue)/(maxVal-minVal)
    normDataSet = normDataSet / tile(ranges, (m, 1))
    return normDataSet, ranges, minVals


# -------------------------3 测试算法----------------------------------------------
def datingClassTest():
    # 设定用来测试的样本占比
    hoRatio = 0.10
    # 从文本中提取得到数据特征,及对应的标签
    datingDataMat, datingLabels = file2matrix('dataTestSet2.txt')
    # 对数据特征进行归一化
    normMat, ranges, minVals = autoNorm(datingDataMat)
    # 得到第一维度的大小
    m = normMat.shape[0]
    # 测试样本数量
    numTestVecs = int(hoRatio * m)
    # 错误数初始化
    errorCount = 0.0;
    for i in range(numTestVecs):
        # 利用分类函数classify0获取测试样本数据的分类结果
        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]))
        # 如果预测输出不等于实际标签,错误数增加1.0
        if (classifierResult != datingLabels[i]): errorCount += 1.0
        # 打印最后的误差率
    print("the total error rate is: %f" % (errorCount / float(numTestVecs)))

# -------------------------4 构建可手动输入系统------------------------------------
# 用户输入相关数据,进行预测
def classifyPerson():
    # 定义预测结果
    resultList = ['not at all', 'in small does', 'in large does']
    # 在python3.x中,已经删除raw_input(),取而代之的是input()
    percentTats = float(input("percentage of time spent playing video games?"))
    ffMiles = float(input("frequent filer miles earned per year?"))
    iceCream = float(input("liters of ice cream consumed per year?"))
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0 * array(datingLabels), 15.0 * array(datingLabels))
    plt.show()
    normMat, ranges, minValues = autoNorm(datingDataMat)
    # 将输入的数值放在数组中
    inArr = array([ffMiles, percentTats, iceCream])
    classifierResult = classify0((inArr - minValues) / ranges, normMat, datingLabels, 3)
    print("you will probably like this person:", resultList[classifierResult - 1])

classifyPerson()

测试输入
在这里插入图片描述
返回结果(这里为了方便看数据,我将中间处理过程也打印了出来)
在这里插入图片描述
在这里插入图片描述

三、算法小结
  如果我们改变训练样本的数目,调整相应的k值,都会对最后的预测错误率产生影响,我们可以根据错误率的情况,对这些变量进行调整,从而降低预测错误率。

  k近邻算法的优缺点:
 优点:k近邻算法具有精度高
 缺点:对异常值不敏感的优点

  k近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。k近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离,实际使用时也可能会非常耗时

  此外,k近邻算法无法给出数据的基础结构信息,因此我们无法知道平均实例样本和典型实例样本具有怎样的特征。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值