机器学习实战—— Chap02.kNN

一、k-邻近算法概述

k-邻近算法,即 K-Nearest Neighbors Algorithm

简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。

距离度量

这里提到距离度量的概念:

距离度量是用来描述不同元素之间距离远近的标准,而这种“标准”不只有一种。

在这里插入图片描述

最一般使用的度量单位,也是一般k-临近算法使用的,是欧氏距离。

算法特点

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

工作原理

•存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每个数据与所属分类的对应关系。

•输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。

•一般来说,只选择样本数据集中前N个最相似的数据。K一般不大于20,最后,选择k个中出现次数最多的分类,作为新数据的分类

算法的一般流程

•收集数据:可以使用任何方法

•准备数据:距离计算所需要的数值,最后是结构化的数据格式。

•分析数据:可以使用任何方法

•训练算法:(此步骤kNN中不适用)

•测试算法:计算错误率

•使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

K值选择

•如果选择较小的K值

  1. “学习”的近似误差(approximation error)会减小,但 “学习”的估计误差(estimation error) 会增大,

  2. 噪声敏感

  3. K值的减小就意味着整体模型变得复杂,容易发生过 拟合.

•如果选择较大的K值

  1. 减少学习的估计误差,但缺点是学习的近似误差会增大.
  2. K值的增大,就意味着整体的模型变得简单.

小结

由此,KNN算法的最重要的三个点可以总结为:

  1. K值的确定
  2. 权重设置:即虽然最后选择了K个数据作为参考依据,但K个数据与测试数据的相对位置各不相同,因此需要对K个数据进行不同的权重设置
  3. 距离的度量方式:计算距离是使用欧氏距离还是马氏距离巴氏距离曼哈顿距离等等,亦或有其他算法。

二、kNN算法理想化实现

注意:这一部分是完全架空,在理想、抽象的条件下,为了实现算法而构建的部分。实际应用时,无论是调用诸如sk-learn中封装好的函数,还是重写、设定参数,都会比下面这个复杂且完善。

0.数据准备

  • 导入了两个模块:第一个是科学计算包NumPy;第二个是运算符模块
from numpy import *
import operator
  • 定义createDataSet()函数,用于创建数据集和标签
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

1.算法实施

  • kNN算法的伪代码

对未知类别属性的数据集中的每个点依次执行以下操作:

(1) 计算已知类别数据集中的点与当前点之间的距离;

(2) 按照距离递增次序排序;

(3) 选取与当前点距离最小的k个点;

(4) 确定前k个点所在类别的出现频率;

(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。

  • kNN算法实现 classify0()函数

二维坐标下,两个向量点的欧式距离计算:

d = ( x A 0 − x B 0 ) 2 + ( x A 1 − x B 1 ) 2 d=\sqrt{(xA_0-xB_0)^2+(xA_1-xB_1)^2} d=(xA0xB0)2+(xA1xB1)2

def classify0(inX, dataSet, labels, k):
    # numpy函数shape[0]返回dataSet的行数
    dataSetSize = dataSet.shape[0]
    # 将inX重复dataSetSize次并排成一列
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    # 二维特征相减后平方(用diffMat的转置乘diffMat)
    sqDiffMat = diffMat ** 2
    # sum()所有元素相加,sum(0)列相加,sum(1)行相加
    sqDistances = sqDiffMat.sum(axis = 1)
    # 开平方,计算出距离
    distances = sqDistances ** 0.5
    # argsort函数返回的是distances值从小到大的--索引值
    sortedDistIndicies = distances.argsort()  
    # 定义一个记录类别次数的字典
    classCount = {
   }
    # 选择距离最小的k个点
    for i in range(k):
        # 取出前k个元素的类别
        voteIlabel = labels[sortedDistIndicies[i]]
        # 字典的get()方法,返回指定键的值,如果值不在字典中返回0
        # 计算类别次数
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    # python3中用items()替换python2中的iteritems()
    # key = operator.itemgetter(1)根据字典的值进行排序
    # key = operator.itemgetter(0)根据字典的键进行排序
    # reverse降序排序字典
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    # 返回次数最多的类别,即所要分类的类别
    return sortedClassCount[0][0]

简单测试:

classify0([0,0], group, labels, 3)
# 'B'

至此构造了第一个分类器,使用这个分类器可以完成很多分类任务。

三、实例一:改进约会网站的配对效果

问题描述

海伦使用约会网站寻找约会对象。经过一段时间之后,她发现曾交往过三种类型的人:

  • 1:不喜欢的人
  • 2:魅力一般的人
  • 3:极具魅力的人

她希望:

  • 不喜欢的人则直接排除掉
  • 工作日与魅力一般的人约会
  • 周末与极具魅力的人约会

现在她收集到了一些约会网站未曾记录的数据信息,这更有助于匹配对象的归类。

实现流程

(1) 收集数据

案例中提供了文本文件,但是有一个小插曲:

原始的数据文件 datingTestSet.txt,其数据记录是数字与字符混合的:

在这里插入图片描述
这导致了读文件时出现报错ValueError: invalid literal for int() with base 10: 'largeDoses'。这种现象很常见,原始数据内部数据结构“混乱”,需要Data Cleaning。

……好在,还有一个datingTestSet2.txt文件,已经将三种不同的labels用数字1~3代替。更多时候需要我们实际修改。

海伦把这些约会对象的数据存放在文本文件 datingTestSet2.txt 中,总共有 1000 行。海伦约会的对象主要包含以下 3 种特征:

  • Col1:每年获得的飞行常客里程数
  • Col2:玩视频游戏所耗时间百分比
  • Col3:每周消费的冰淇淋公升数
(2) 准备数据

使用Python解析文本文件。讲文本记录通过NumPy转化为分类器可以接受的格式。

构建file2matrix()函数,以此来处理输入格式问题:

def file2matrix(filename):
    # 打开文件
    fr = open(filename)
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java.lang.ClassNotFoundException是Java的一个异常类,表示在运行时找不到指定的类。当Java虚拟机(JVM)尝试加载一个类时,如果找不到该类的定义,就会抛出ClassNotFoundException异常。 在你的引用,你提到了一个java.lang.ClassNotFoundException: com.example.YourServlet异常。这个异常通常发生在使用Java Servlet时,当服务器无法找到指定的Servlet类时抛出。 要解决这个异常,你可以采取以下步骤: 1. 确保你的类路径正确:检查你的项目配置和部署环境,确保Servlet类的路径正确。如果你使用的是Java Web容器(如Tomcat),请确保Servlet类位于正确的目录下。 2. 检查类名拼写:检查你的代码的类名拼写是否正确。确保类名的大小写和包名的正确性。 3. 检查依赖项:如果你的Servlet类依赖于其他类或库,确保这些依赖项已正确地添加到你的项目,并且可以在运行时访问到。 4. 清理和重新构建项目:有时,编译错误或构建问题可能导致类文件无法正确生成。尝试清理和重新构建你的项目,以确保所有的类文件都已正确生成。 5. 检查类加载器:如果你在自定义类加载器加载类,确保你的类加载器能够正确找到并加载指定的类。 6. 检查运行时环境:如果你在不同的环境运行你的应用程序(例如开发环境和生产环境),请确保运行时环境存在所需的类。 下面是一个示例代码,演示了如何处理java.lang.ClassNotFoundException异常: ```java try { Class.forName("com.example.YourServlet"); } catch (ClassNotFoundException e) { e.printStackTrace(); // 处理异常的代码 } ``` 这段代码尝试加载名为"com.example.YourServlet"的类。如果找不到该类,就会抛出ClassNotFoundException异常,并且可以在catch块处理该异常。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值