k-近邻算法改进约会网站配对效果

k-近邻算法改进约会网站配对效果

一、理论学习

1. 阅读内容

请务必仔细阅读《机器学习实战》书籍第1章及第2章,本节实验通过解决约会网站配对效果问题来实战 k-近邻算法(k-Nearest Neighbour,KNN)

2. 扩展阅读

本节推荐内容可以辅助书中理论知识,比书中内容更容易理解,可以加深理论知识,请仔细阅读:

二、在线实验

1. 分析需求

我在约会网站看到的人,分为三类:

  1. 不喜欢的
  2. 一般喜欢的
  3. 非常喜欢的

我希望分类算法可以实现替我区分这三类人。

而现在我有一群人的下面的数据:

  1. 每年的飞行里程
  2. 玩视频游戏消耗时间的百分比
  3. 每周吃的冰淇淋(公升)

如何根据这些数据对这群人进行分类?这就是我的需求。

2. 准备数据

下载数据

下载实验所需资料:

$ cd /home/shiyanlou
$ wget http://labfile.oss.aliyuncs.com/courses/499/lab2.zip
$ unzip lab2.zip

将测试数据拷贝到我们自己的目录:

$ cd /home/shiyanlou
$ mkdir mylab2
$ cd mylab2/
$ cp /home/shiyanlou/lab2/datingTestSet2.txt ./

使用 gedit 或 vim 打开数据文件查看如下:

文件中每一行代表一个人的数据,共有4列内容,分别为:

  1. 每年的飞行里程
  2. 玩视频游戏消耗时间的百分比
  3. 每周吃的冰淇淋(公升)
  4. 分到的类别(1:不喜欢 2:一般喜欢 3:非常喜欢)

根据这些数据我们开始实现KNN算法。

我们需要打开一个 Xfce 终端,输入 ipython 进入到交互式模式来边写代码边测试。

解析数据

为了能让KNN算法可以处理我们的数据,需要将数据读取到矩阵中。

我们实现函数 file2matrix() 来做数据解析:

  1. 读取数据文件每一行
  2. 输出为特征矩阵和类标签向量

函数的实现如下,注意这里用到 numpy 来构建矩阵:

from numpy import *

def file2matrix(filename):

    # 打开数据文件,读取每行内容
    fr = open(filename)
    arrayOLines = fr.readlines()

    # 初始化矩阵
    numberOfLines = len(arrayOLines)
    returnMat = zeros((numberOfLines,3))

    # 初始化类标签向量
    classLabelVector = []

    # 循环读取每一行数据
    index = 0
    for line in arrayOLines:
        # 去掉回车符
        line = line.strip()
        # 提取4个数据项
        listFromLine = line.split(‘\t‘)
        # 将前三项数据存入矩阵
        returnMat[index,:] = listFromLine[0:3]
        # 将第四项数据存入向量
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

将上述代码输入到ipython中,注意python代码的缩进。

完成后我们测试下函数读取数据的返回值:

这个时候我们看到矩阵中第一项数据都是几千甚至上万,而第二和第三项数据则小很多,为了避免求取KNN距离时第一项影响过大,需要对数据进行第二步处理:归一化,将数值范围处理为0~1-1~1之间。

实验中我们将用下面的公式将数值归一化到0~1范围内:

newValue = (oldValue-min)/(max-min)

实现一个 autoNorm() 函数来完成数据的归一化,其中使用numpy的tile()函数来将minVals处理成与dataSet同样大小的矩阵,从而可以执行矩阵减法,最后矩阵除法得到归一化后的矩阵:

def autoNorm(dataSet):
    # 读取矩阵中数据项的最大和最小值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)

    # 获得最大和最小值间差值
    ranges = maxVals - minVals

    # 初始化输出结果
    normDataSet = zeros(shape(dataSet))

    # 获取矩阵的行数
    m = dataSet.shape[0]

    # 矩阵运算:实现归一化公式中的 oldValue - min 一步
    normDataSet = dataSet - tile(minVals, (m,1))

    # 矩阵除法:实现归一化公式中的除法
    normDataSet = normDataSet/tile(ranges, (m,1))

    # 返回归一化后的数据,数据范围及最小值矩阵
    return normDataSet, ranges, minVals

完成后对刚才得到的数据进行归一化处理:

对于这些数据我们可以使用matplotlib 创建散点图来查看。

上述步骤创建的散点图显示的横轴是归一化后的玩视频游戏所耗时间的百分比,纵轴是每周消费冰淇淋数量数据。

最终画出来的图如下图所示:

3. 分析数据

KNN 算法我们在理论学习部分已经有所了解,本节内容将实现这个算法的核心部分:计算“距离”。

如何根据三个特征数据计算两个人之间的距离呢,假设归一化后两个人的数据分别为(0.3,0.5,0.3)(0.5,0.2,0.3)使用一个简单的公式来计算二者间的距离:

(A1−B1)2+(A2−B2)2+(A3−B3)2\sqrt{(A1-B1)^2 + (A2-B2)^2 + (A3-B3)^2}√?(A1−B1)?2??+(A2−B2)?2??+(A3−B3)?2?????

得到这两点的距离为 0.3606。

当我们有一定的样本数据和这些数据所属的分类后,输入一个测试数据,我们就可以根据算法得出该测试数据属于哪个类别。

KNN 算法实现过程:

  1. 计算测试数据与每个样本数据之间的距离。
  2. 按照距离递增排序
  3. 选择与测试数据距离最近的k个点(注意这里的k值会影响到最终的分类错误率)
  4. 确定这k个点中三个类别出现的概率,出现概率最高的类别就是返回的结果
  5. 输出结果:算法判断该测试数据属于步骤4中计算得到的类别

算法实现为函数 classify0(),函数的参数包括:

  1. inX:测试数据向量
  2. dataSet:样本数据矩阵
  3. labels:样本数据的类标签向量
  4. k:传说中的k值
import operator

def classify0(inX, dataSet, labels, k):
    # 获取样本数据数量
    dataSetSize = dataSet.shape[0]

    # 矩阵运算,计算测试数据与每个样本数据对应数据项的差值
    diffMat = tile(inX, (dataSetSize,1)) - dataSet

    # sqDistances 上一步骤结果平方和
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)

    # 取平方根,得到距离向量
    distances = sqDistances**0.5

    # 按照距离从低到高排序
    sortedDistIndicies = distances.argsort()
    classCount={}          

    # 依次取出最近的样本数据
    for i in range(k):
        # 记录该样本数据所属的类别
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1

    # 对类别出现的频次进行排序,从高到低
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)

    # 返回出现频次最高的类别
    return sortedClassCount[0][0]

4. 测试算法

完成了对数据的分析后,我们开始测试算法的准确率。测试过程将调用我们上面实现的各个函数。

需要首先说明下,我们的样本数据和测试数据都来自一个数据文件,我们将数据文件的前10%作为测试数据,后90%作为样本数据。

测试的步骤:

  1. 读取数据文件中的样本数据到特征矩阵和类标签向量
  2. 对数据进行归一化,得到归一化的特征矩阵
  3. 执行KNN算法对测试数据进行测试,得到分类结果
  4. 与实际的分类结果进行对比,记录分类错误率
  5. 打印每个人的分类数据及错误率作为最终的结果

测试函数实现:

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)

        # 打印KNN算法分类结果和真实的分类
        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])

        # 判断KNN算法结果是否准确
        if (classifierResult != datingLabels[i]): errorCount += 1.0

    # 打印错误率
    print "the total error rate is: %f" % (errorCount/float(numTestVecs))

测试中的一些数据,其中样本数据900行,测试数据100行:

运行程序进行测试:

最终我们得到错误率为 0.05,可以考虑下有哪些方面可以降低错误率,比如那些值可以影响到最终的错误率。欢迎到实验楼问答与老师和同学进行探讨。

三、经典问答

本节内容不断更新中,列出同学在实验楼问答中提到的有价值的问题供同学参考。

四、完整数据及代码

完整的数据及参考代码可以通过wget下载:

$ cd /home/shiyanlou/
$ wget http://labfile.oss.aliyuncs.com/courses/499/lab2.zip
$ unzip lab2.zip

完整代码:

#-*- coding: utf-8 -*-

from numpy import *
import operator

# 读取数据到矩阵
def file2matrix(filename):

    # 打开数据文件,读取每行内容
    fr = open(filename)
    arrayOLines = fr.readlines()

    # 初始化矩阵
    numberOfLines = len(arrayOLines)
    returnMat = zeros((numberOfLines,3))

    # 初始化类标签向量
    classLabelVector = []

    # 循环读取每一行数据
    index = 0
    for line in arrayOLines:
        # 去掉回车符
        line = line.strip()
        # 提取4个数据项
        listFromLine = line.split(‘\t‘)
        # 将前三项数据存入矩阵
        returnMat[index,:] = listFromLine[0:3]
        # 将第四项数据存入向量
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

# 数据归一化
def autoNorm(dataSet):
    # 读取矩阵中数据项的最大和最小值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)

    # 获得最大和最小值间差值
    ranges = maxVals - minVals

    # 初始化输出结果
    normDataSet = zeros(shape(dataSet))

    # 获取矩阵的行数
    m = dataSet.shape[0]

    # 矩阵运算:实现归一化公式中的 oldValue - min 一步
    normDataSet = dataSet - tile(minVals, (m,1))

    # 矩阵除法:实现归一化公式中的除法
    normDataSet = normDataSet/tile(ranges, (m,1))

    # 返回归一化后的数据,数据范围及最小值矩阵
    return normDataSet, ranges, minVals

# kNN算法实现
def classify0(inX, dataSet, labels, k):
    # 获取样本数据数量
    dataSetSize = dataSet.shape[0]

    # 矩阵运算,计算测试数据与每个样本数据对应数据项的差值
    diffMat = tile(inX, (dataSetSize,1)) - dataSet

    # sqDistances 上一步骤结果平方和
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)

    # 取平方根,得到距离向量
    distances = sqDistances**0.5

    # 按照距离从低到高排序
    sortedDistIndicies = distances.argsort()
    classCount={}          

    # 依次取出最近的样本数据
    for i in range(k):
        # 记录该样本数据所属的类别
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1

    # 对类别出现的频次进行排序,从高到低
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)

    # 返回出现频次最高的类别
    return sortedClassCount[0][0]

# 算法测试
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)

        # 打印KNN算法分类结果和真实的分类
        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])

        # 判断KNN算法结果是否准确
        if (classifierResult != datingLabels[i]): errorCount += 1.0

    # 打印错误率
    print "the total error rate is: %f" % (errorCount/float(numTestVecs))

# 执行算法测试
datingClassTest()
时间: 2024-09-30 20:47:34

k-近邻算法改进约会网站配对效果的相关文章

K-近邻算法改进约会网站的配对效果

摘自:<机器学习实战>,用python编写的(需要matplotlib和numpy库) 海伦一直使用在线约会网站寻找合适自己的约会对象.尽管约会网站会推荐不同的人选,但她没有从中找到喜欢的人.经过一番总结,她发现曾交往过三种类型的人: 1.不喜欢的人( 以下简称1 ): 2.魅力一般的人( 以下简称2 ): 3.极具魅力的人(以下简称3 ) 尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归入恰当的分类.她觉得可以在周一到周五约会哪些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴

机器学习实战笔记——利用KNN算法改进约会网站的配对效果

一.案例背景 我的朋友海伦一直使用在线约会网站寻找合适自己的约会对象.尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人.经过一番总结,她发现曾交往过三种类型的人: (1)不喜欢的人: (2)魅力一般的人: (3)极具魅力的人: 尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归入恰当的分类,她觉得可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴.海伦希望我们的分类软件可以更好地帮助她将匹配对象划分到确切的分类中.此外,海伦还收集了一些约会网站未曾记录的数据

吴裕雄--天生自然python机器学习:使用K-近邻算法改进约会网站的配对效果

在约会网站使用K-近邻算法 准备数据:从文本文件中解析数据 海伦收集约会数据巳经有了一段时间,她把这些数据存放在文本文件(1如1^及抓 比加 中,每 个样本数据占据一行,总共有1000行.海伦的样本主要包含以下3种特征: 每年获得的飞行常客里程数 玩视频游戏所耗时间百分比 每周消费的冰淇淋公升数 将文本记录到转换NumPy的解析程序 import operator from numpy import * from os import listdir def file2matrix(filenam

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

---恢复内容开始--- < Machine Learning 机器学习实战>的确是一本学习python,掌握数据相关技能的,不可多得的好书!! 最近邻算法源码如下,给有需要的入门者学习,大神请绕道. 数字识别文件 ''' Created on Sep 16, 2010 kNN: k Nearest Neighbors Input: inX: vector to compare to existing dataset (1xN) dataSet: size m data set of know

《机器学习实战》代码实现学习一 使用K-近邻算法改进约会网站的配对效果(数据准备)

1.数据准备:从文本文件中解析数据 文本文件datingTestSet2.txt网盘地址为: https://pan.baidu.com/s/19HNwo1TSWjWhbRwsyL-itg 提取码为:mz11 约会数据由1000行,主要包含一下三种特征: 每年获得的飞行常客里程数 玩视频游戏所耗时间百分比 每周消费的冰淇淋公升数 但是在把这些特征输入到分类器之前,必须将待处理数据格式改变为分类器可以接受的格式,在kNN.py中创建名为file2matrix的函数,以此来处理输入格式问题,该函数的

机器学习实战笔记-K近邻算法2(改进约会网站的配对效果)

案例二.:使用K-近邻算法改进约会网站的配对效果 案例分析: 海伦收集的数据集有三类特征,分别是每年获得的飞行常客里程数.玩视频游戏所耗时间百分比. 每周消费的冰淇淋公升数.我们需要将新数据的每个新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签.一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数.最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类. 流程:在约会网站上使用K

机器学习实战1-2 KNN改进约会网站的配对效果 datingTestSet2.txt 下载方法

今天读<机器学习实战>读到了使用k-临近算法改进约会网站的配对效果,道理我都懂,但是看到代码里面的数据样本集 datingTestSet2.txt 有点懵,这个样本集在哪里,只给了我一个文件名,没有任何内容啊. 上网百度了这个文件名,发现很多博主的博客里可以下载,我很好奇,同样是读<机器学习实战>,他们是从哪里下载的数据样本集呢?就重新读了这本书.终于在"关于本书"最后的"作者在线里面"找到了网址!就是这个,大家需要可以来这里下载. http

机器学习算法( 二、K - 近邻算法)

一.概述 k-近邻算法采用测量不同特征值之间的距离方法进行分类. 工作原理:首先有一个样本数据集合(训练样本集),并且样本数据集合中每条数据都存在标签(分类),即我们知道样本数据中每一条数据与所属分类的对应关系,输入没有标签的数据之后,将新数据的每个特征与样本集的数据对应的特征进行比较(欧式距离运算),然后算出新数据与样本集中特征最相似(最近邻)的数据的分类标签,一般我们选择样本数据集中前k个最相似的数据,然后再从k个数据集中选出出现分类最多的分类作为新数据的分类. 二.优缺点 优点:精度高.对

《机器学习实战》-k近邻算法

目录 K-近邻算法 k-近邻算法概述 解析和导入数据 使用 Python 导入数据 实施 kNN 分类算法 测试分类器 使用 k-近邻算法改进约会网站的配对效果 收集数据 准备数据:使用 Python 解析文本文件 分析数据:使用 Matplotlib 画二维散点图 准备数据:归一化数值 测试算法:验证分类器 使用算法:构建完整可用系统 手写识别系统 准备数据 测试算法 使用算法:构建完整可用系统 总结 K-近邻算法 k-近邻分类算法概述 使用 k-近邻算法改进约会网站的配对效果 手写识别系统