【skLearn练习】KNN分类算法案例 ---- 约会网站的配对效果



KNN算法

在这里插入图片描述
1. 优点

  • 简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归
  • 可用于数值型数据和离散型数据
  • 无数据输入假定
  • 适合对稀有事件进行分类

2. 缺点

  • 计算复杂性高;空间复杂性高;
  • 计算量太大,所以一般数值很大的时候不用这个,但是单个样本又不能太少,否则容易发生误分。

返回顶部


案例描述

海伦一直使用在线约会网站寻找适合自己的约会对象,尽管约会网站会推荐不同的人选,但她并不是每一个都喜欢,经过一番总结,她发现曾经交往的对象可以分为三类:

  • 不喜欢的人
  • 魅力一般的人
  • 极具魅力得人

海伦收集约会数据已经有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,其中各字段分别为:

  1. 每年飞行常客里程
  2. 玩游戏视频所占时间比
  3. 每周消费冰淇淋公升数

返回顶部


代码实现

① 数据集探索

import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = 'Simhei'

# 读取数据集
data = pd.read_csv("G:\Projects\pycharmeProject\Python_Sklearn\K_近邻_KNN\data\datingTestSet.txt", sep="\t", header=None)
data.columns = ['每年飞行常客里程', '玩游戏视频所占时间比', '每周消费冰淇淋公升数', '类型']

# 下面对数据进行两两组合绘图
# 1.划分不同类型的线条颜色
color = []
for i in range(len(data)):
    type = data.iloc[i, -1]
    if type == 'largeDoses':
        color.append('red')
    elif type == 'smallDoses':
        color.append('green')
    else:
        color.append('black')
# 2.设置画布
pl = plt.figure(figsize=(12, 8))

fig1 = pl.add_subplot(221)
plt.scatter(data.iloc[:, 1], data.iloc[:, 2], marker='.', c=color)
plt.xlabel('玩游戏视频所占时间比')
plt.ylabel('每周消费冰淇淋公升数')

fig2 = pl.add_subplot(222)
plt.scatter(data.iloc[:, 0], data.iloc[:, 1], marker='.', c=color)
plt.xlabel('每年飞行常客里程')
plt.ylabel('玩游戏视频所占时间比')

fig3 = pl.add_subplot(223)
plt.scatter(data.iloc[:, 0], data.iloc[:, 2], marker='.', c=color)
plt.xlabel('每年飞行常客里程')
plt.ylabel('每周消费冰淇淋公升数')
plt.show()

通过三个特征的不同组合,对数据集进行可视化展示。可以清晰的看出数据集的分类情况。虽然通过颜色可以了解到分类情况,但是如下图一、三所示,很明显,从他们的角度来看数据集的分布,错综交叉,对于类别的划分很模糊。但是图二就不一样了,每各类别之间的划分还是很明了的。

在这里插入图片描述
返回顶部


② 数据归一化

假设我们想要计算样本1和样本2之间的距离,可以使用欧几里得计算公式:
在这里插入图片描述
我们很容易发现,上面公式中差值最大的属性对计算结果的影响最大,也就是说每年飞行常客里程对计算结果的影响远远大于其他两个特征,原因仅仅是因为它的数值比较大,但是在海伦看来这三个特征是同等重要的,所以接下来我们要进行数值归一化的处理,使得这三个特征的权重相等。

数据归一化的处理方法有很多种,比如0-1标准化Z-score标准化Sigmoid压缩法等等,在这里我们使用最简单的0-1标准化,公式如下:
在这里插入图片描述

"""
函数功能:归一化
参数说明:
dataSet:原始数据集
返回:0-1标准化之后的数据集
"""
def minmax(dataSet):
	minDf = dataSet.min()
	maxDf = dataSet.max()
	normSet = (dataSet - minDf )/(maxDf - minDf)
    return normSet
MM_data = pd.concat([minmax(data.iloc[:, :3]), data.iloc[:,3]], axis=1)    

在这里插入图片描述

返回顶部


③ 划分训练集和测试集

前面概述部分我们有提到,为了测试分类器的效果,我们可以把原始数据集分为训练集和测试集两部分,训练集用来训练模型,测试集用来验证模型准确率。

关于训练集和测试集的切分函数,网上一搜一大堆,Scikit Learn官网上也有相应的函数比如model_selection 类中的train_test_split 函数也可以完成训练集和测试集的切分。

通常来说,我们只提供已有数据的90%作为训练样本来训练模型,其余10%的数据用来测试模型。这里需要注意的10%的测试数据一定要是随机选择出来的,由于海伦提供的数据并没有按照特定的目的来排序,所以我们这里可以随意选择10%的数据而不影响其随机性。

"""
函数功能:切分训练集和测试集
参数说明:
dataSet:原始数据集
rate:训练集所占比例
返回:切分好的训练集和测试集
"""
def randSplit(dataSet,rate=0.9):
	n = dataSet.shape[0]
	m = int(n*rate)
	train = dataSet.iloc[:m,:]
	test = dataSet.iloc[m:,:]
	test.index = range(test.shape[0])
	return train,test
train,test = randSplit(MM_data)	

在这里插入图片描述

返回顶部


④ 分类器针对于约会网站的测试代码

接下来,我们一起来构建针对于这个约会网站数据的分类器,上面我们已经将原始数据集进行归一化处理然后也切分了训练集和测试集,所以我们的函数的输入参数就可以是train、test和k(k-近邻算法的参数,也就是选择的距离最小的k个点)。

"""
函数功能:k-近邻算法分类器
参数说明:
train:训练集
test:测试集
k:k-近邻参数,即选择距离最小的k个点
返回:预测好分类的测试集
"""
# 编写分类器
def data_class(train,test,k):
    n = train.shape[1]-1  # 特征数
    m = test.shape[0]     # 测试数据集的数目
    result = []
    for i in range(m):
        # 计算欧氏距离
        dist =list((((train.iloc[:,:n]-test.iloc[i,:n])**2).sum(1))**0.5)
        # 整合距离与标签数据
        dist_type = pd.DataFrame({"dist":dist,"labels":train.iloc[:,n]})
        # 排序,提取前k个
        sort_dist_k = dist_type.sort_values(by='dist')[:k]
        # 统计频率
        counts = sort_dist_k.loc[:,'labels'].value_counts()
        # 获取预测值添加到结果集中
        result.append(counts.index[0])
    result = pd.DataFrame(result)
    test['predict'] = result.values
    accuracy = (test.iloc[:, -1] == test.iloc[:, -2]).mean()
    print(f"模型的预测准确率为{accuracy}")
    return test
test_final = data_class(train,test,5)
# 模型的预测准确率为0.95

从结果可以看出,利用KNN进行的分类预测结果还是很准的。

在这里插入图片描述
大致流程:

在这里插入图片描述

返回顶部


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑着蜗牛ひ追导弹'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值