资讯专栏INFORMATION COLUMN

机器学习(七)-基于KNN分类的约会网站配对改进算法

Songlcy / 2334人阅读

摘要:项目介绍某用户一直使用在线约会软件寻找适合自己的约会对象。尽管约会网站会推荐不同的人选但她并不是喜欢每一个人。

1 项目介绍

某APP用户一直使用在线约会软件寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结,她发现曾交往过三种类型的人:

不喜欢的人(3)

魅力一般的人(2)

极具魅力的人(1)

某APP用户希望分类软件可以更好地帮助她将匹配对象划分到确切的分类中。此外还可以收集了约会软件未曾记录的数据信息,她认为这些数据更有助于匹配对象的归类。收集的部分信息如下图所示:
数据集下载

样本主要包含以下3种特征:

每年获得的飞行常客里程数

玩视频游戏所耗时间百分比

每周消费的冰淇淋公升数

2 准备数据:从文本文件中解析数据

在将上述特征数据输入到分类器之前,必须将待处理数据的格式改变为分类器可以接受的格式。

import numpy as np
def file2matrix(filename):
    """

    :param filename: APP用户收集的约会数据的文件名
    :return:
        returnMat: 用户提供的每行数据信息,三列,
                    分别是每年获得的飞行常客里程数,
                    玩视频游戏所耗时间百分比,
                    每周消费的冰淇淋公升数
        classLabelVetor:
                    用户的评价信息, 一般分为3类(1,2,3)

    """
    fr = open(filename)
    arrayOfLines = fr.readlines()
    # print(arrayOfLines)
    # 获得文件行数;
    numerOfLines = len(arrayOfLines)
    # 创建要返回的Numpy矩阵;
    returnMat = np.zeros((numerOfLines, 3))
    # 解析文件数据到矩阵中;
    classLabelVetor = []
    index = 0
    for line in arrayOfLines:
        line = line.strip()
        listFromLine = line.split("	")
        returnMat[index, :] = listFromLine[0:3]
        classLabelVetor.append(listFromLine[-1])
        index += 1
    return returnMat, classLabelVetor

print(file2matrix("data/datingTestSet2"))

返回的值显示:

3 分析数据:使用 Matplotlib 创建散点图

使用Matplotlib库图形化清晰地标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同。

def draw_pic(datingDataMat, datingLabels):
    """
    每年获取的飞行常客里程数与每周所消费的冰淇淋公升数”构成的散点图。
    :param datingDataMat:
    :param datingLabels:
    :return:
    """
    #  中文显示乱码问题;
    myfont = font_manager.FontProperties(fname="/usr/share/fonts/cjkuni-uming/uming.ttc", size=12)
    # 创建画布
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:, 0], datingDataMat[:, 2],
               15 * datingLabels, datingLabels)

    plt.xlabel("每年的飞行里程数", fontproperties=myfont)
    plt.ylabel("每周消费的冰淇淋公升数", fontproperties=myfont)
    plt.grid(alpha=0.5)
    plt.show()

效果展示

4 准备数据:归一化数值

计算样本3和样本4之间的距离:

问题:
飞行常客里程数对于计算结果的影响将远远大于其他两个特征的影响

解决方式:
处理不同取值范围的特征值时,通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。

归一化公式: newValue = oldValue / max

def autoNorm(dataSet):
    """
     归一化数值,
    :param dataSet:用户提供的每行数据信息,三列;
    :return:
        normDataSet: 归一化的特征信息;
        maxVals:每个特征数据的最大值;
    """
    # 获取每个特征数据的最大值;
    maxVals = dataSet.max(0)
    # 获取样本个数;
    m = dataSet.shape[0]
    # 根据公式生成归一化的特征信息;
    normDataSet = dataSet / np.tile(maxVals, (m, 1))
    return normDataSet, maxVals
4 实施 kNN 算法

对未知类别属性的数据集中的每个点依次执行以下操作, 与上一个案例代码相同:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。

def classify(inX, dataSet, labels, k):
    """
    :param inX: 要预测的数据
    :param dataSet: 我们要传入的已知数据集
    :param labels:  我们要传入的标签
    :param k: KNN里的k, 也就是说我们要选几个近邻
    :return: 排序的结果
    """
    dataSetSize = dataSet.shape[0]  # (6,2) 6
    # tile会重复inX, 把他重复成(datasetsize, 1)型的矩阵
    # print(inX)
    # (x1 - y1), (x2- y2)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    # 平方
    sqDiffMat = diffMat ** 2
    # 相加, axis=1 行相加
    sqDistance = sqDiffMat.sum(axis=1)
    # 开根号
    distances = sqDistance ** 0.5
    # print(distances)
    # 排序 输出的是序列号index,并不是值
    sortedDistIndicies = distances.argsort()
    # print(sortedDistIndicies)

    classCount = {}
    for i in range(k):
        voteLabel = labels[sortedDistIndicies[i]]
        classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
        # print(classCount)
    sortedClassCount = sorted(classCount.items(), key=lambda d: float(d[1]), reverse=True)
    return sortedClassCount[0]
5 测试算法:作为完整程序验证分类器

如果分类器的正确率满足要求,就可以使用这个软件来处理约会网站提供的约会名单了。机器学习算法一个很重要的工作就是评估算法的正确率,通常我们只提供已有数据的90%作为训练样本来训练分类器,而使用其余的10%数据去测试分类器,检测分类器的正确率。

def datingClassTest():
    """
    分类器针对约会网站的测试代码, 获取错误率;
    :return:
    """
    hoRatio = 0.10
    datingDataMat, datingLabels = file2matrix("data/datingTestSet2")
    normDataSet, maxVals = autoNorm(datingDataMat)
    # 样本个数
    m = normDataSet.shape[0]
    # 测试集个数;
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0

    for i in range(numTestVecs):
        classiferResult = classify(normDataSet[i, :],
                                   normDataSet[numTestVecs:m, :],
                                   datingLabels[numTestVecs:m], 3)
        # print(classiferResult)
        if classiferResult != datingLabels[i]:
            errorCount += 1
            print("正确结果:", datingLabels[i])
            print("预测结果:", classiferResult)

    # print("错误个数:", errorCount)
    return  errorCount

执行效果展示:

6 使用算法:构建完整可用的预测系统
def classifyPerson(Person):
    """
    使用这个分类器为某APP用户来对人们分类。
    :param Person:
    :return:
    """
    datingDataMat, datingLabels = file2matrix("data/datingTestSet2")
    normDataSet, maxVals = autoNorm(datingDataMat)
    classiferResult = classify(Person / maxVals, normDataSet, datingLabels, 3)
    if classiferResult  == "1":
        print("不喜欢")
    elif classiferResult == "2":
        print("有一点喜欢")
    else:
        print("非常喜欢")
完整代码
# encoding:utf-8


"""
KNN实现,基于KNN分类的约会网站配对改进算法
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager


def file2matrix(filename):
    """

    :param filename: APP用户收集的约会数据的文件名
    :return:
        returnMat: 用户提供的每行数据信息,三列,
                    分别是每年获得的飞行常客里程数,
                    玩视频游戏所耗时间百分比,
                    每周消费的冰淇淋公升数
        classLabelVetor:
                    用户的评价信息, 一般分为3类(1,2,3)

    """
    fr = open(filename)
    arrayOfLines = fr.readlines()
    # print(arrayOfLines)
    # 获得文件行数;
    numerOfLines = len(arrayOfLines)
    # 创建要返回的Numpy矩阵;
    returnMat = np.zeros((numerOfLines, 3))
    # 解析文件数据到矩阵中;
    classLabelVetor = []
    index = 0
    for line in arrayOfLines:
        line = line.strip()
        listFromLine = line.split("	")
        returnMat[index, :] = listFromLine[0:3]
        classLabelVetor.append(listFromLine[-1])
        index += 1
    return returnMat, classLabelVetor


def autoNorm(dataSet):
    """
    归一化数值,
    计算样本3和样本4之间的距离: [(0-67)**2 + (20000 - 32 000)**2 + (1.1 - 0.1)**2]**0.5
    问题:
            飞行常客里程数对于计算结果的影响将远远大于其他两个特征的影响
    解决方式:
            处理不同取值范围的特征值时,
            通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。
            归一化公式: newValue = oldValue / max
    :param dataSet:用户提供的每行数据信息,三列;
    :return:
        normDataSet: 归一化的特征信息;
        maxVals:每个特征数据的最大值;
    """
    # 获取每个特征数据的最大值;
    maxVals = dataSet.max(0)
    # 获取样本个数;
    m = dataSet.shape[0]
    # 根据公式生成归一化的特征信息;
    normDataSet = dataSet / np.tile(maxVals, (m, 1))
    return normDataSet, maxVals


def draw_pic(datingDataMat, datingLabels):
    """
    每年获取的飞行常客里程数与每周所消费的冰淇淋公升数”构成的散点图。
    :param datingDataMat:
    :param datingLabels:
    :return:
    """
    #  中文显示乱码问题;
    myfont = font_manager.FontProperties(fname="/usr/share/fonts/cjkuni-uming/uming.ttc", size=12)
    # 创建画布
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:, 0], datingDataMat[:, 2],
               15 * datingLabels, datingLabels)

    plt.xlabel("每年的飞行里程数", fontproperties=myfont)
    plt.ylabel("每周消费的冰淇淋公升数", fontproperties=myfont)
    plt.grid(alpha=0.5)
    plt.show()


def classify(inX, dataSet, labels, k):
    """
    :param inX: 要预测的数据
    :param dataSet: 我们要传入的已知数据集
    :param labels:  我们要传入的标签
    :param k: KNN里的k, 也就是说我们要选几个近邻
    :return: 排序的结果
    """
    dataSetSize = dataSet.shape[0]  # (6,2) 6
    # tile会重复inX, 把他重复成(datasetsize, 1)型的矩阵
    # print(inX)
    # (x1 - y1), (x2- y2)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    # 平方
    sqDiffMat = diffMat ** 2
    # 相加, axis=1 行相加
    sqDistance = sqDiffMat.sum(axis=1)
    # 开根号
    distances = sqDistance ** 0.5
    # print(distances)
    # 排序 输出的是序列号index,并不是值
    sortedDistIndicies = distances.argsort()
    # print(sortedDistIndicies)

    classCount = {}
    for i in range(k):
        voteLabel = labels[sortedDistIndicies[i]]
        classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
        # print(classCount)
    sortedClassCount = sorted(classCount.items(), key=lambda d: float(d[1]), reverse=True)
    return sortedClassCount[0][0]

def datingClassTest():
    """
    分类器针对约会网站的测试代码, 获取错误率;
    :return:
    """
    hoRatio = 0.10
    datingDataMat, datingLabels = file2matrix("data/datingTestSet2")
    normDataSet, maxVals = autoNorm(datingDataMat)
    # 样本个数
    m = normDataSet.shape[0]
    # 测试集个数;
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0

    for i in range(numTestVecs):
        classiferResult = classify(normDataSet[i, :],
                                   normDataSet[numTestVecs:m, :],
                                   datingLabels[numTestVecs:m], 3)
        # print(classiferResult)
        if classiferResult != datingLabels[i]:
            errorCount += 1
            print("正确结果:", datingLabels[i])
            print("预测结果:", classiferResult)

    # print("错误个数:", errorCount)
    return  errorCount






def classifyPerson(Person):
    """
    使用这个分类器为某APP用户来对人们分类。
    :param Person:
    :return:
    """
    datingDataMat, datingLabels = file2matrix("data/datingTestSet2")
    normDataSet, maxVals = autoNorm(datingDataMat)
    classiferResult = classify(Person / maxVals, normDataSet, datingLabels, 3)
    if classiferResult  == "1":
        print("不喜欢")
    elif classiferResult == "2":
        print("有一点喜欢")
    else:
        print("非常喜欢")


if __name__ == "__main__":
    # personData = [30000, 10, 1.3]
    personData = [40920, 8.326976, 0.953952]
    classifyPerson(personData)

执行结果

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43593.html

相关文章

  • 机器学习()-基于KNN分类约会网站配对改进算法

    摘要:项目介绍某用户一直使用在线约会软件寻找适合自己的约会对象。尽管约会网站会推荐不同的人选但她并不是喜欢每一个人。 1 项目介绍 某APP用户一直使用在线约会软件寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结,她发现曾交往过三种类型的人: 不喜欢的人(3) 魅力一般的人(2) 极具魅力的人(1) 某APP用户希望分类软件可以更好地帮助她将匹...

    RyanQ 评论0 收藏0
  • k邻近算法应用实例(一) 改进约会网站配对效果

    摘要:邻近算法实例额一改进约会网站的配对效果应用背景某约会网站收集了一些数据放在中,每个样本数据占据一行,总共有行。在中创建名为的函数,以此来处理输人格式问题。该函数的输人为文件名字符串输出为训练样本矩阵和类标签向量。 k邻近算法实例额(一) 改进约会网站的配对效果 应用背景: 某约会网站收集了一些数据放在datingTestSet.txt中,每个样本数据占据一行,总共有1000行。样本主要...

    airborne007 评论0 收藏0
  • 机器学习1——k近邻算法

    k近邻(k-Nearest Neighbor,kNN)算法是经典的带监督的分类算法,核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则针对该样本的划分结果也属于这个类别。 1. 算法步骤 准备训练数据和测试数据; 确定参数 k; 计算测试数据与各个训练数据之间的距离,距离的递增关系进行排序; 选取距离最小的 k 个点; 确定前 k 个点所在类别的出现频率; 返回前 ...

    seanlook 评论0 收藏0
  • 机器学习实战 Task1】 (KNN)k近邻算法应用

    摘要:背景近邻算法的概述近邻算法的简介近邻算法是属于一个非常有效且易于掌握的机器学习算法,简单的说就是采用测量不同特征值之间距离的方法对数据进行分类的一个算法。完美的分类器的错误率为,而最差的分类器的错误率则为。 1 背景 1.1 k近邻算法的概述 (1)k近邻算法的简介 k-近邻算法是属于一个非...

    toddmark 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<