【机器学习实战】K-近邻算法之海伦约会

2024-03-10 13:40

本文主要是介绍【机器学习实战】K-近邻算法之海伦约会,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【机器学习实战】K-近邻算法之海伦约会


文章是阅读《机器学习实战》【美】Peter Harrington著 李锐李鹏 曲亚东 王斌 译 的读书笔记,具体可以去参考这本书。

1.准备数据:文本文件中解析数据

海伦将约会数据放在datingTestSet.txt中,每个样本数据占一行,总共有1000行。海伦的样本主要包含以下三种特征:

  • 每年获得的飞行常客里程数
  • 玩视频游戏所消耗时间百分比
  • 每周消费的冰淇淋公升数

在上述数据输入到分类器之前,需要将待处理数据格式改变为分类器可以接受的格式。由csv文件构建相对应的numpy数组, 输入为文件名字字符串,输出为训练样本矩阵和类标签向量。

def file2matrix(filename):fr = open(filename)arrayOLines = fr.readlines()# 得到文件行数numberOfLines = len(arrayOLines)# 创建返回的numpy数组,因为是海伦约会数据集有3个特征returnMat = zeros((numberOfLines, 3))classLabelVector = []index = 0# 解析文本数据到列表for line in arrayOLines:# 截取掉所有的回车字符line = line.strip()# 使用'\tab'键将整行数据转换为列表listFromLine = line.split('\t')# 将海伦约会的每一行数据转换为要返回的numpy数据行returnMat[index, :] = listFromLine[0:3]classLabelVector.append((listFromLine[-1]))# 将字符标签转换为数字标签# if listFromLine[-1] == 'didntLike':#     classLabelVector.append(1)# if listFromLine[-1] == 'smallDoses':#     classLabelVector.append(2)# if listFromLine[-1] == 'largeDoses':#     classLabelVector.append(3)index += 1return returnMat, classLabelVector

加载数据
在这里插入图片描述

2.标题分析数据

使用Matplotlib制作原始数据的散点图分析数据
博主陈多鱼这块代码写的很好,在这借鉴了一下,感兴趣可以去看原帖,感谢博主

https://blog.csdn.net/qq_42338771/article/details/108270830

代码及其解释

# 图像数据分析
def showData(returnMat, classLabelVector):fig, axs = plt.subplots(nrows=2, ncols=2, sharex=False, sharey=False, figsize=(13, 8))labelColors = []for i in datingLables:if i == 1:labelColors.append('black')if i == 2:labelColors.append('orange')if i == 3:labelColors.append('red')# 设置第一张图片,飞行里程数和游戏百分比, 散点大小为15, 透明度0.5axs[0][0].scatter(x=datingDataMat[:, 0], y=datingDataMat[:, 1], color=labelColors, s=15, alpha=0.5)# 设置标题和坐标轴备注axs0_title_text = axs[0][0].set_title('flight_play')axs0_xlabel_text = axs[0][0].set_xlabel('飞行里程')axs0_ylabel_text = axs[0][0].set_ylabel('游戏时间')# 中文标题正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.setp(axs0_title_text, size=9, weight='bold', color='red')plt.setp(axs0_xlabel_text, size=7, weight='bold', color='black')plt.setp(axs0_ylabel_text, size=7, weight='bold', color='black')# 设置第二张图片, 飞行里程数和冰淇淋axs[0][1].scatter(x=datingDataMat[:, 0], y=datingDataMat[:, 2], color=labelColors, s=15, alpha=0.5)axs1_title_text = axs[0][1].set_title('flight_eat')axs1_xlabel_text = axs[0][1].set_xlabel('飞行里程')axs1_ylabel_text = axs[0][1].set_ylabel('冰淇淋量')plt.setp(axs1_title_text, size=9, weight='bold', color='red')plt.setp(axs1_xlabel_text, size=7, weight='bold', color='black')plt.setp(axs1_ylabel_text, size=7, weight='bold', color='black')# 设置第三张图片,游戏时间和冰淇淋量axs[1][0].scatter(x=datingDataMat[:, 1], y=datingDataMat[:, 2], color=labelColors, s=15, alpha=0.5)axs2_title_text = axs[1][0].set_title('play_eat')axs2_xlabel_text = axs[1][0].set_xlabel('游戏时间')axs2_ylabel_text = axs[1][0].set_ylabel('冰淇淋量')plt.setp(axs2_title_text, size=9, weight='bold', color='red')plt.setp(axs2_xlabel_text, size=7, weight='bold', color='black')plt.setp(axs2_ylabel_text, size=7, weight='bold', color='black')# 设置图例didntLike = mlines.Line2D([], [], color='black', marker='.',markersize=6, label='didntLike')smallDoses = mlines.Line2D([], [], color='orange', marker='.',markersize=6, label='smallDoses')largeDoses = mlines.Line2D([], [], color='red', marker='.',markersize=6, label='largeDoses')# 添加图例axs[0][0].legend(handles=[didntLike, smallDoses, largeDoses])axs[0][1].legend(handles=[didntLike, smallDoses, largeDoses])axs[1][0].legend(handles=[didntLike, smallDoses, largeDoses])# 画出图片plt.show()

数据分析图例
在这里插入图片描述
这三张图可以看出来,第一张图通过飞行里程数和游戏百分比,还是可以把三种约会类型比较清晰的分类出来,而后面两张图类别中互相混合,无法分类出来。

3.数据归一化

在这里插入图片描述
约会网站的原始数据,可以看出来如果使用欧氏距离的话,飞行里程数与另外两个类别的数差距比较大,影响过大,但是海伦认为这三种数据同等重要,处理不同范围的特征值的时候,一般将数值归一化,减小数级的影响,将取值范围处理到0到1或者-1到1之间,下面的公式将数值范围处理在0到1之间。
n e w v a l u e = ( o l d v a l u e − m i n ) / ( m a x − m i n ) newvalue = (oldvalue - min)/(max-min) newvalue=(oldvaluemin)/(maxmin)
数值归一化范围-1到1之间公式:
n e w v a l u e = 2 ∗ ( o l d v a l u e − m i n ) / ( m a x − m i n ) − 1 newvalue = 2*(oldvalue - min)/(max-min) - 1 newvalue=2(oldvaluemin)/(maxmin)1
max与min分别是数据集中的最小特征值和最大特征值,改变数值取值范围会增加分类器的复杂度,但是会使结果更加准确。
代码数值归一化0到1区间函数autoNorm()。

# 数值归一化函数
def autoNorm(dataSet):minValue = dataSet.min(0)maxValue = dataSet.max(0)ranges = maxValue - minValue# 同样规格的零矩阵记录数值归一化的结果normDataset = zeros(shape(dataSet))# 记录数据行数,即数据条数m = dataSet.shape(0)# 复制minvalue到同样大小,然后做数据相减操作normDataset = dataSet - tile(minValue, (m, 1))# 复制ranges到同样规格大小,然后做数据相除操作normDataset = normDataset/tile(ranges, (m, 1))# 返回归一化结果,范围,最小值return normDataset, ranges, minValue

这里面操作的是特征值(数值)相除,不是向量相除,在numpy库中,向量相除使用函数linalg.solve(matA, matB)。

4.分类算法:KNN算法实现

使用的是之前文章中使用的欧式距离计算的方法来判断分类,详细参考文章

https://blog.csdn.net/qq_43587460/article/details/135983033#comments_31185167

# 分类器,使用欧几里得距离
def classify0(inx, dataset, labels, k):''':param inx: 未知标签数据特征:param dataset: 样本数据:param labels: 样本标签:param k: k近邻取值:return: 判断标签值'''# 距离计算datasetSetSize = dataset.shape[0]diffMat = tile(inx, (datasetSetSize, 1)) - datasetsqDiffMat = diffMat ** 2sqDistances = sqDiffMat.sum(axis=1)distance = sqDistances ** 0.5# 距离排序sortedDistIndicies = distance.argsort()classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndicies[i]]classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1sorteClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)return sorteClassCount[0][0]

5.测试算法:作为完整程序验证分类器

评估算法的正确率,通常我们用90%的数据来作为训练样本来训练分类器,用10%的数据去测试分类器,检测分类器的正确率。10%的测试数据应该是随机选择的,海伦约会数据没有根据特定的目的来排序,可以随意选取10%的数据而不影响随机性。
可以使用错误率来检测分类器的性能,错误率就是分类器给出错误结果的次数除以测试数据的总数,完美分类器的错误率为0,而错误率为1.0的分类器不会给出任何正确的分类结果。
代码:

def datingClassTest():# 测试数据比例hoRatio = 0.10datingDataMat, datingLables = file2matrix('datingTestSet.txt')normMat, ranges, minValues = autoNorm(datingDataMat)# 获取归一化后矩阵行数m = normMat.shape[0]# 测试数据数量numTestVecs = int(m * hoRatio)errorCount = 0.0for i in range(numTestVecs):# 使用分类器分类classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :],\datingLables[numTestVecs:m], 3)print("the classifier came back with:%d, the real answer is:%d" % (classifierResult, datingLables[i]))# 分类器分类数据与预测数据对比,最后计算错误率if(classifierResult != datingLables[i]): errorCount += 1.0print("the total error rate is:%f" % (errorCount/float(numTestVecs)))

测试分类器结果:
错误率是%5
可以看出,构建的分类器的错误率是5%,效果还不错,可以改进检测数据的量(hoRatio)与近邻判断的数量(k的值),来检测错误率是否会发生变化。

6.使用算法,构建完整可用的系统

写了一个人工智能,最想的还是可以帮忙来预测数据,来使用自己的构建的机器学习算法,构建预测函数。
代码及其解释如下:

# 约会网站预测函数
def classifyPerson():# 预测结果是数字,对应成字符串resultList = ['not at all', 'in small doses', 'in large doses']# 输入飞行里程,冰淇淋量,游戏时间来进行预测percentTats = float(raw_input(\"percentage of time spent playing video games?"))ffMiles = float(raw_input("frequent filer miles earned per year?"))iceCream = float(raw_input("liters of ice cream consumed per year?"))# 数据读取datingDataMat, datingLables = file2matrix('datingTestSet.txt')# 数据归一化normMat, ranges, minValues = autoNorm(datingDataMat)# 输入的数据格式整合,适配机器学习算法inArr = array([ffMiles, percentTats, iceCream])# 对数据进行归一化处理,并进行预测classifierResult = classify0((inArr - minValues)/ranges, normMat, datingLables, 3)print("You will probably like this person:", resultList[classifierResult - 1])

使用效果:
在这里插入图片描述

7.完整代码

from numpy import *
import operator
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
from pip._vendor.distlib.compat import raw_inputdef file2matrix(filename):fr = open(filename)arrayOLines = fr.readlines()# 得到文件行数numberOfLines = len(arrayOLines)# 创建返回的numpy数组,因为是海伦约会数据集有3个特征returnMat = zeros((numberOfLines, 3))classLabelVector = []index = 0# 解析文本数据到列表for line in arrayOLines:# 截取掉所有的回车字符line = line.strip()# 使用'\tab'键将整行数据转换为列表listFromLine = line.split('\t')# 将海伦约会的每一行数据转换为要返回的numpy数据行returnMat[index, :] = listFromLine[0:3]# 文本标签收集# classLabelVector.append((listFromLine[-1]))# 将字符标签转换为数字标签if listFromLine[-1] == 'didntLike':classLabelVector.append(1)if listFromLine[-1] == 'smallDoses':classLabelVector.append(2)if listFromLine[-1] == 'largeDoses':classLabelVector.append(3)index += 1return returnMat, classLabelVector# 加载数据
datingDataMat, datingLables = file2matrix('datingTestSet.txt')
# print(datingDataMat)
# print('------------')
# print(datingLables[0:20])# 图像数据分析
def showData(returnMat, classLabelVector):fig, axs = plt.subplots(nrows=2, ncols=2, sharex=False, sharey=False, figsize=(13, 8))labelColors = []for i in datingLables:if i == 1:labelColors.append('black')if i == 2:labelColors.append('orange')if i == 3:labelColors.append('red')# 设置第一张图片,飞行里程数和游戏百分比, 散点大小为15, 透明度0.5axs[0][0].scatter(x=datingDataMat[:, 0], y=datingDataMat[:, 1], color=labelColors, s=15, alpha=0.5)# 设置标题和坐标轴备注axs0_title_text = axs[0][0].set_title('flight_play')axs0_xlabel_text = axs[0][0].set_xlabel('飞行里程')axs0_ylabel_text = axs[0][0].set_ylabel('游戏时间')# 中文标题正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.setp(axs0_title_text, size=9, weight='bold', color='red')plt.setp(axs0_xlabel_text, size=7, weight='bold', color='black')plt.setp(axs0_ylabel_text, size=7, weight='bold', color='black')# 设置第二张图片, 飞行里程数和冰淇淋axs[0][1].scatter(x=datingDataMat[:, 0], y=datingDataMat[:, 2], color=labelColors, s=15, alpha=0.5)axs1_title_text = axs[0][1].set_title('flight_eat')axs1_xlabel_text = axs[0][1].set_xlabel('飞行里程')axs1_ylabel_text = axs[0][1].set_ylabel('冰淇淋量')plt.setp(axs1_title_text, size=9, weight='bold', color='red')plt.setp(axs1_xlabel_text, size=7, weight='bold', color='black')plt.setp(axs1_ylabel_text, size=7, weight='bold', color='black')# 设置第三张图片,游戏时间和冰淇淋量axs[1][0].scatter(x=datingDataMat[:, 1], y=datingDataMat[:, 2], color=labelColors, s=15, alpha=0.5)axs2_title_text = axs[1][0].set_title('play_eat')axs2_xlabel_text = axs[1][0].set_xlabel('游戏时间')axs2_ylabel_text = axs[1][0].set_ylabel('冰淇淋量')plt.setp(axs2_title_text, size=9, weight='bold', color='red')plt.setp(axs2_xlabel_text, size=7, weight='bold', color='black')plt.setp(axs2_ylabel_text, size=7, weight='bold', color='black')# 设置图例didntLike = mlines.Line2D([], [], color='black', marker='.',markersize=6, label='didntLike')smallDoses = mlines.Line2D([], [], color='orange', marker='.',markersize=6, label='smallDoses')largeDoses = mlines.Line2D([], [], color='red', marker='.',markersize=6, label='largeDoses')# 添加图例axs[0][0].legend(handles=[didntLike, smallDoses, largeDoses])axs[0][1].legend(handles=[didntLike, smallDoses, largeDoses])axs[1][0].legend(handles=[didntLike, smallDoses, largeDoses])# 画出图片plt.show()showData(datingDataMat, datingLables)# 分类器,使用欧几里得距离
def classify0(inx, dataset, labels, k):''':param inx: 未知标签数据特征:param dataset: 样本数据:param labels: 样本标签:param k: k近邻取值:return: 判断标签值'''# 距离计算datasetSetSize = dataset.shape[0]diffMat = tile(inx, (datasetSetSize, 1)) - datasetsqDiffMat = diffMat ** 2sqDistances = sqDiffMat.sum(axis=1)distance = sqDistances ** 0.5# 距离排序sortedDistIndicies = distance.argsort()classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndicies[i]]classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1sorteClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)return sorteClassCount[0][0]# 数值归一化函数
def autoNorm(dataSet):minValue = dataSet.min(0)maxValue = dataSet.max(0)ranges = maxValue - minValue# 同样规格的零矩阵记录数值归一化的结果normDataset = zeros(shape(dataSet))# 记录数据行数,即数据条数m = dataSet.shape[0]# 复制minvalue到同样大小,然后做数据相减操作normDataset = dataSet - tile(minValue, (m, 1))# 复制ranges到同样规格大小,然后做数据相除操作normDataset = normDataset/tile(ranges, (m, 1))# 返回归一化结果,范围,最小值return normDataset, ranges, minValue# 归一化实例
normMat, ranges, minValues = autoNorm(datingDataMat)
# print(normMat)
# print('-----------')
# print(ranges)
# print('-------------')
# print(minValues)# 错误率测试代码
def datingClassTest():# 测试数据比例hoRatio = 0.10datingDataMat, datingLables = file2matrix('datingTestSet.txt')normMat, ranges, minValues = autoNorm(datingDataMat)# 获取归一化后矩阵行数m = normMat.shape[0]# 测试数据数量numTestVecs = int(m * hoRatio)errorCount = 0.0for i in range(numTestVecs):# 使用分类器分类classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :],\datingLables[numTestVecs:m], 3)print("the classifier came back with:%d, the real answer is:%d" % (classifierResult, datingLables[i]))# 分类器分类数据与预测数据对比,最后计算错误率if(classifierResult != datingLables[i]): errorCount += 1.0print("the total error rate is:%f" % (errorCount/float(numTestVecs)))# 测试分类器
# datingClassTest()# 约会网站预测函数
def classifyPerson():# 预测结果是数字,对应成字符串resultList = ['not at all', 'in small doses', 'in large doses']# 输入飞行里程,冰淇淋量,游戏时间来进行预测percentTats = float(raw_input(\"percentage of time spent playing video games?"))ffMiles = float(raw_input("frequent filer miles earned per year?"))iceCream = float(raw_input("liters of ice cream consumed per year?"))# 数据读取datingDataMat, datingLables = file2matrix('datingTestSet.txt')# 数据归一化normMat, ranges, minValues = autoNorm(datingDataMat)# 输入的数据格式整合,适配机器学习算法inArr = array([ffMiles, percentTats, iceCream])# 对数据进行归一化处理,并进行预测classifierResult = classify0((inArr - minValues)/ranges, normMat, datingLables, 3)print("You will probably like this person:", resultList[classifierResult - 1])if __name__ == '__main__':classifyPerson()

从简单的开始,一步步进步吧。如有错误,欢迎指正,积极学习。

这篇关于【机器学习实战】K-近邻算法之海伦约会的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/794407

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖