KNN算法改进约会网站匹配效果

本文介绍了如何使用KNN算法改进约会网站的匹配系统。海伦通过收集数据并进行预处理,包括数据归一化,然后利用KNN分类器进行测试和验证。最终,该算法被用于构建一个约会网站的预测系统,根据用户的游戏时间、飞行里程和冰淇淋消费量等特征,预测其可能的约会偏好。

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

实验

一、示例:KNN改进约会网站配对

海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她没有从中找到喜欢的人。经过一番总结,她发现曾交往过三种类型的人:
不喜欢的人
魅力一般的人
极具魅力的人
尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归入恰当的分类。她觉得可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴,海伦希望我们的分类软件可以更好地帮助她将匹配对象划分到确切的分类中。此外海伦还收集了一些约会网站未曾记录的数据信息,她认为这些数据更有助于匹配对象的归类。
海伦收集约会数据有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,每个样本数据占据一行,总共有1000行。海伦的样本主要包含以下3种特征:
每年获得的飞行常客里程数
玩视频游戏所耗时间百分比
每周消费的冰淇淋公升数
(datingTestSet.txt这个文本自己上网找哈,挺多的)

二、实验过程

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

import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)                #得到文本行数
    returnMat = np.zeros((numberOfLines,3))      #创建返回的NumPy二维矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        # line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
        listFromLine = line.split('\t')
        # 选取前面三个元素,存储到特征矩阵中
        returnMat[index,:] = listFromLine[0:3]
        # 使用索引值-1为表示列表中最后一列元素
        if listFromLine[-1] == 'didntLike':      #文本内收集的数据
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    return returnMat, classLabelVector

if __name__ == '__main__':
    #打开的文件名
    filename = "datingTestSet.txt"
    # 打开并处理数据
    datingDataMat, datingLabels = file2matrix(filename)
    print(datingDataMat)
    print(datingLabels)

结果:
在这里插入图片描述

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

import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)                #得到文本行数
    returnMat = np.zeros((numberOfLines,3))      #创建返回的NumPy二维矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        # line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
        listFromLine = line.split('\t')
        # 选取前面三个元素,存储到特征矩阵中
        returnMat[index,:] = listFromLine[0:3]
        # 使用索引值-1为表示列表中最后一列元素
        if listFromLine[-1] == 'didntLike':      #文本内收集的数据
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    return returnMat, classLabelVector


if __name__ == '__main__':
    #打开的文件名
    filename = "datingTestSet.txt"
    # 打开并处理数据
    datingDataMat, datingLabels = file2matrix(filename)
    print(datingDataMat)
    print(datingLabels)

    # 数据可视化
    fig = plt.figure()
    ax = fig.add_subplot(111)  # 111,参数111的意思是:将画布分割成11列,图像画在从左到右从上到下的第1块
    ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])
    plt.show()

结果:
在这里插入图片描述

3.准备数据:归一化数值

import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)                #得到文本行数
    returnMat = np.zeros((numberOfLines,3))      #创建返回的NumPy二维矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        # line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
        listFromLine = line.split('\t')
        # 选取前面三个元素,存储到特征矩阵中
        returnMat[index,:] = listFromLine[0:3]
        # 使用索引值-1为表示列表中最后一列元素
        if listFromLine[-1] == 'didntLike':      #文本内收集的数据
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    return returnMat, classLabelVector

# 归一化特征值
def autoNorm(dataSet):
    minVals = dataSet.min(0)         #从列中选取最小值
    maxVals = dataSet.max(0)         #从列中选取最大值
    # 当前值减去最小值,然后除以取值范围
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet / np.tile(ranges, (m, 1))     #特征值相除
    return normDataSet, ranges, minVals

if __name__ == '__main__':
    #打开的文件名
    filename = "datingTestSet.txt"
    # 打开并处理数据
    datingDataMat, datingLabels = file2matrix(filename)
    print(datingDataMat)
    print(datingLabels)

    #归一化特征值
    normDataSet, ranges, minVals = autoNorm(datingDataMat)
    print(normDataSet)
    print(ranges)
    print(minVals)

结果:
在这里插入图片描述

4.测试算法:作为完整程序验证分类器(写入KNN分类器函数classify0)

import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator

# 在文本文件中解析数据
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet      # 距离计算
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndices = distances.argsort()
    classCount = {}
    # 选择距离最小的K个点 把classCount分解为元组列表
    for i in range(k):
        voteIlabel = labels[sortedDistIndices[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
        # itemgetter为排序 为逆序,即按照最大到最小的次序
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)                #得到文本行数
    returnMat = np.zeros((numberOfLines,3))      #创建返回的NumPy二维矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        # line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
        listFromLine = line.split('\t')
        # 选取前面三个元素,存储到特征矩阵中
        returnMat[index,:] = listFromLine[0:3]
        # 使用索引值-1为表示列表中最后一列元素
        if listFromLine[-1] == 'didntLike':      #文本内收集的数据
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    return returnMat, classLabelVector

# 归一化特征值
def autoNorm(dataSet):
    minVals = dataSet.min(0)         #从列中选取最小值
    maxVals = dataSet.max(0)         #从列中选取最大值
    # 当前值减去最小值,然后除以取值范围
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet / np.tile(ranges, (m, 1))     #特征值相除
    return normDataSet, ranges, minVals


#测试算法:作为完整程序验证分类器
def datingClassTest():
        filename = "datingTestSet.txt"
        datingDataMat, datingLabels = file2matrix(filename)
        hoRatio = 0.10
        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], 4)
            print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
            if classifierResult != datingLabels[i]:
                errorCount += 1.0
        print("错误率:%f%%" % (errorCount / float(numTestVecs) * 100))

if __name__ == '__main__':
    #打开的文件名
    filename = "datingTestSet.txt"
    # 打开并处理数据
    datingDataMat, datingLabels = file2matrix(filename)
    print(datingDataMat)
    print(datingLabels)

    #归一化特征值
    normDataSet, ranges, minVals = autoNorm(datingDataMat)
    print(normDataSet)
    print(ranges)
    print(minVals)

    #测试算法
    datingClassTest()

结果:
在这里插入图片描述
在这里插入图片描述

5.使用算法:构建完整可用系统

import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator

# 在文本文件中解析数据
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet      # 距离计算
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndices = distances.argsort()
    classCount = {}
    # 选择距离最小的K个点 把classCount分解为元组列表
    for i in range(k):
        voteIlabel = labels[sortedDistIndices[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
        # itemgetter为排序 为逆序,即按照最大到最小的次序
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)                #得到文本行数
    returnMat = np.zeros((numberOfLines,3))      #创建返回的NumPy二维矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        # line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
        listFromLine = line.split('\t')
        # 选取前面三个元素,存储到特征矩阵中
        returnMat[index,:] = listFromLine[0:3]
        # 使用索引值-1为表示列表中最后一列元素
        if listFromLine[-1] == 'didntLike':      #文本内收集的数据
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    return returnMat, classLabelVector


# 归一化特征值
def autoNorm(dataSet):
    minVals = dataSet.min(0)         #从列中选取最小值
    maxVals = dataSet.max(0)         #从列中选取最大值
    # 当前值减去最小值,然后除以取值范围
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet / np.tile(ranges, (m, 1))     #特征值相除
    return normDataSet, ranges, minVals


#测试算法:作为完整程序验证分类器
def datingClassTest():
        filename = "datingTestSet.txt"
        datingDataMat, datingLabels = file2matrix(filename)
        hoRatio = 0.10
        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], 4)
            print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
            if classifierResult != datingLabels[i]:
                errorCount += 1.0
        print("错误率:%f%%" % (errorCount / float(numTestVecs) * 100))

# 约会网站预测函数
def classifyPerson():
        resultList = ['讨厌','有些喜欢','非常喜欢']
        precentTats = float(input("玩视频游戏所耗时间百分比:"))
        ffMiles = float(input("每年获得的飞行常客里程数:"))
        iceCream = float(input("每周消费的冰激淋公升数:"))
        filename = "datingTestSet.txt"
        datingDataMat, datingLabels = file2matrix(filename)
        normMat, ranges, minVals = autoNorm(datingDataMat)
        inArr = np.array([precentTats, ffMiles, iceCream])
        norminArr = (inArr - minVals) / ranges
        classifierResult = classify0(norminArr, normMat, datingLabels, 3)
        print("你可能%s这个人" % (resultList[classifierResult - 1]))

# 数据可视化


if __name__ == '__main__':
    #打开的文件名
    filename = "datingTestSet.txt"
    # 打开并处理数据
    datingDataMat, datingLabels = file2matrix(filename)
    print(datingDataMat)
    print(datingLabels)

    #归一化特征值
    normDataSet, ranges, minVals = autoNorm(datingDataMat)
    print(normDataSet)
    print(ranges)
    print(minVals)

    #测试算法
    datingClassTest()

    # 约会网站预测函数
    classifyPerson()

结果:(数据自己输入,随意的)
在这里插入图片描述

总结

用的是pycharm编译软件,目录如下

在这里插入图片描述
海伦通过收集的数据得到一个非线性的散点图,为了得到准确的分类器,海伦把三个特征值(即每年获得的飞行常客里程数,玩视频游戏所耗时间百分比,每周消费的冰淇淋公升数)选取其中两个为最小特征值(minVals)还有最大特特征值(maxVals),通过权重来计算结果。文本中,只有90%作为训练样本训练,10%去测试分类器,然后测试分类器的效果,如果分类器的正确率满足要求,则海伦能拿着这个软件处理约会网站的约会名单了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值