学渣也学ML:K-近邻算法之笔记二

再来个案例:约会网站配对效果

书上例出了K-近邻算法的一般流程:
收集数据:可以使用任意方法,此例使用文本文件
准备数据:距离计算所需的数值,最好是结构化的数据格式。
分析数据:可以使用任何方法,此例用Matplotlib画二维扩散图
训练算法:此步骤不适用于K-近邻算法
测试算法:计算错误率。此例使用部分数据作测试样本。
使用算法:首先需要输入样本数据和结构化的输出结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算的分类执行后续的处理
不作解释了,往案例里死搬硬套吧
案例分析
海伦想使用在线约会网站找朋友,真是人生寂寞如雪,难求一知己啊,身边找不到志趣相投,只能求助万能的网络啦。
特征:我们来看看海伦的爱好是什么呢:
每年获得飞行常客里程数
玩视频游戏所耗时间百分比
每周消费的冰淇淋公升数
(惊恐,以公升数来计冰淇淋,绝对的吃货啊。)
分类:她按她的爱好标准将这些数据中的人分为三种类型:
不喜欢的人didntlike
魅力一般的人smallDoses
极具魅力的人largeDoses
任务:现在使用算法目标任务应该也算是清晰明了,就是根据数据集中的三个(兴趣爱好)特征值,来判断这个人属于哪一种:是海伦不喜欢的、还是一般喜欢,或者特别喜欢。
开始任务
根据书上列出的流程一步一步来:
#1收集数据2准备数据

import pandas as pd
testDate=pd.read_table('datingTestSet.txt',header=None)
testDate.head()  #查看数据前五条
 
testDate.shape #查看数据结构,即行数*列数 (1000, 4)

前五条数据
发现数据集中,第一个特征是飞行里程数,第二个特列值是游戏所占时间比,第三个特列值是冰淇淋公升数
#3分析数据
利用数据可视化查看三种特征数据对应的三种不同结果分布。

#使用Matplotlib创建散点图,查看数据的分布情况
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
Colors=[]
#三种特征值用三种不同的颜色显示
for i in (testDate.iloc[:,-1]):    
    if i=='didntLike':
        Colors.append('blue')
    if i=='smallDoses':
        Colors.append('green')
    if i=='largeDoses':
        Colors.append('red')      
plt.rcParams['font.sans-serif']=['simhei']#显示中文
p1=plt.figure(figsize=(12,8)) #设置图像区域大小
fig1=p1.add_subplot(221)#两行两列四个子图,在第一个图像区画图
plt.scatter(testDate.iloc[:,1],testDate.iloc[:,2],c=Colors)
plt.xlabel('玩游戏视频所占时间比')
plt.ylabel('每周消费冰淇淋公升数')

fig2=p1.add_subplot(222) #两行两列四个子图,在第二个图像区画图
plt.scatter(testDate.iloc[:,0],testDate.iloc[:,2],c=Colors)
plt.xlabel('每年飞行常客里程')
plt.ylabel('每周消费冰淇淋公升数')

fig3=p1.add_subplot(223)
plt.scatter(testDate.iloc[:,1],testDate.iloc[:,2],c=Colors)
plt.xlabel('玩游戏视频所占时间比')
plt.ylabel('每年飞行常客里程')

plt.show()

在这里插入图片描述
#计算距离
在这里插入图片描述
根据样本中的数据,比如样本3和样本4之间的距离可以使用欧氏距离公式得到:
√(〖(75136-38344)〗2+〖(1.669788-13.147394)〗2+〖(0.124296-0.428964)〗^2 )
我们发现里程数的数值特别大,而其他两个数据值相对而言特别小,这样算出来的距离在很大程度是受里程数影响,相对的,玩游戏冰淇淋的影响就很小了。但是在海伦看来,这三个兴趣的比重应该是同等重要的。这该如何解决呢?
书上给我们提供的方法是:数值归一化。
数值归一化
数据归一化或者说特征值归一化:通俗地来说不管你原来的数值有多大,我们都要想办法把它转化为0到1,或者-1到1之间的数值。
转化方法:0-1标准化,Z-Score标准化,Sigmoid压缩法。各种方法等我们用到了再来详细地学。在这里我们就选择最简的0-1标准化,公式如下:

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

学渣解读:min和max指是数据集中的最小特征值和最大特征值,oldValues是指原数据集中的特征数据值,比如 校本3中的三个特征值。newValue是运算得到的一个属于0-1之间数值,即归一化后的数值。
可以把数值归一化的功能封装到一个函数中,简化程序:

#特征值归一化
def autoNorm(dataSet):
    minV=dataSet.min() #用min()函数得到最小值
    maxV=datSet.max()
    newVals=(dataSet-minV)/(maxV-minV) #0-1归一化公式
    return newVals
#查看归一化后的数据
newData=pd.concat([autoNorm(testDate.iloc[:,:3]),testDate.iloc[:,3]],axis=1)
newData.head()

此时发现原来的大数据全都变成0-1之间的数值了。那么对于距离的影响三个特征的比重就相同了。
pd.concat()方法是连接两个数据集,因为前面数据归化一时只用到了前三列的数据,最后列的结果是字符型的,并没有传递到归一化函数中,想要最后的数据还是完整的表格,所以在归一化的数据列后面再把结果列拼接上。
#4划分训练集和测试集
训练集:专门用来让机器学习,并从中获取经验,对模型进行训练修正提升。一般训练集是完整的数据,既有特征值,也有实际的分类结果。
测试集:用来验证模型的准确率。也是一些完整的数据,有特征值和结果,只让机器读取特征值,用模型来进行分类。再将分类结果与实际结果进行对比,获得模型的准确率。
训练集和测试的切分:
把数据集用专门的切分函数(网上搜搜N多)把数据集切分成两部分:训练集和测试集,一般来说,训练集里数据多,测试集中数据少且随机选择出来。
在当前案例中,我们用90%当训练样本,10%当测试样本,因为数据集中的数据本身没有排序,可以任意选择10%的数据。


#封装拆分训练集和测试集函数
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(newData)

5构建分类器
仿照上一个案例(电影分类)的分类器来构建适合当前约会案例的分类器。
数据:train为训练集,test为测试集。k为KNN参数,即距离最小的K个点。
返回值:预测分类的结果

#构建分类器
def dataClass(train,test,k):
    n=train.shape[1]-1 #去掉最后一列的结果标签,即n=3
    m=test.shape[0]   #获得测试集的行数,即m=100
    result=[]
    #对这100个点,每个点进行距离计算,并预测其结果
    for i in range(m):
        dist = list((((train.iloc[:,:n]-test.iloc[i,:n])**2).sum(1))**0.5)#计算距离
        dist_l = pd.DataFrame({'dist': dist, 'labels': (train.iloc[:, n])})#将距离与对应的标签转换为结构化数据
        dr = dist_l.sort_values(by = 'dist')[: k]#按距离升序排序,然后选取距离最小的K个点,
        re = dr.loc[:, 'labels'].value_counts() #统计结果标签的个数
        result.append(re.index[0])#将个数最多的结果标签添加到列表reslut中去
    result = pd.Series(result)#将预测结果列表转换为Pandas的结构化数据
    test['predict'] = result#将预测结果列添加到测试数据集中,即在后面多了一列predict
    acc = (test.iloc[:,-1]==test.iloc[:,-2]).mean()#判断预测结果与实际结果相等的个数,再求均值得到准备确,即准确个数/总数
    print('模型预测准确率为{}'.format(acc))
    return test

#6测试算法:计算准确率/错误率。

#调用分类器查看准确率
dataClass(train,test,5) # K值为5

运行结果发现:模型预测准确率为0.95

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值