机器学习(2)K近邻算法原理及基于KNN的电影题材分类

机器学习(2)K近邻算法原理及基于KNN的电影题材分类

一、K近邻(k-nearest neighbors,简称KNN)算法

在这里插入图片描述
K 近邻是监督学习中比较简单的一种算法,它既可以解决分类问题,也可以解决回归问题。
具体到分类问题中,y 值就是样本类别的取值,一般采用多数表决的原则来对测试样本的类别进行预测。根据涂色样本点和未涂色样本点 X 的距离给涂色样本点编号1-6,即:1号样本点距离X最近,其余次之。那么样本点 X 应该属于哪种颜色呢?是蓝色还是绿色?我们可以根据 X 的相邻样本点来判定。例如,和 X 距离最近的三个样本点中绿色占多数,那么 X 就属于为绿色;和 X 距离最近的 5 个样本点中蓝色占多数,那么 X 就属于蓝色。这种解决问题的思路正是 K 近邻算法的基本思想:根据 K 个近邻样本的 y 值来预测自身的 y 值。具体到上面例子中的 y 值就是样本点的颜色。
在这里插入图片描述
使用 K 近邻来解决回归问题
回归问题中预测的 y 值是一个连续值,上图中每个样本点周围的数字代表其 y 值,K近邻是将离 X 最近的 K个样本的 y 值的平均值作为 X 的预测 y 值。
欧氏距离
在 K 近邻算法中一般选取的是欧式距离,可以类比高中时学过的两点或多点间的距离公式:
在这里插入图片描述
k近邻算法具体流程:
在这里插入图片描述
K 值的选取是会影响到预测结果的,最直观的例子就是课程一开始的涂色问题,很明显 K=3 和 K=5 的分类结果是不一样的:K=3 时,X 属于绿色,K=5 时,X 属于蓝色。如果选择较小的 K 值,则一旦邻近点是噪声(和 X 实际上并不相似的点),预测结果就会出错。如果选择较大的 K 值,则和 X 距离较远的点也会对预测结果产生影响。极端情况下 K 值等于训练样本个数时,无论输入的测试样本是什么,预测结果都将是训练样本中最多的类。在实际应用中,K 值取比较小的数,一般低于训练样本数的平方根。还可以采用交叉验证的方法来选择最优的 K 值。
下面说一下使用简单交叉验证进行K值选择的思路:
首先将数据分为训练集和测试集,然后使用不同的 K 值(如:1,3,5,7,…)进行实验,最后选出在测试集上误差最小的 K 值。
除了 K 值外,K 近邻的预测结果还受距离度量决策规则的影响。距离度量实际上是衡量两个样本的相似程度:距离越小,相似程度越高。常见的相似性度量函数有:欧氏距离、余弦相似性、皮尔逊相关系数。K 近邻中的分类决策规则一般是多数表决,如果采用其他的决策方式,相应的预测结果也会发生变化。

二、基于KNN的电影题材分类

numpy 和 pandas 是 python 中常见的两个库: numpy 可以用来存储和处理大型矩阵,比 python 自身的嵌套列表结构要高效的多;pandas 是基于 numpy 的一种工具,该工具是为了解决数据分析任务而创建的;Counter 用来统计序列中不同元素的个数。

import numpy as np
import pandas as pd
from collections import Counter
def euclidean_distance(vec1,vec2):  # 这个函数的输入参数 vec1 和 vec2 是 numpy 中的一维数组,表示两个特征向量。
    return np.sqrt(np.sum(np.square(vec1 - vec2)))
# 构造数据集
# 训练数据使用字典的形式存储,字典的键作为样本索引,值作为样本记录,使用列表存储。列表中的前 3 个值是样本特征(搞笑镜头、拥抱镜头、打斗镜头),最后一个值是样本标记(电影类型)。
train_data = {'宝贝当家':[45,2,9,'喜剧片'],
              '美人鱼':[21,17,5,'喜剧片'],
              '澳门风云3':[54,9,11,'喜剧片'],
              '功夫熊猫3':[39,0,31,'喜剧片'],
              '谍影重重':[5,2,57,'动作片'],
              '叶问3':[3,2,65,'动作片'],
              '我的特工爷爷':[6,4,21,'动作片'],
              '奔爱':[7,46,4,'爱情片'],
              '夜孔雀':[9,39,8,'爱情片'],
              '代理情人':[9,38,2,'爱情片'],
              '新步步惊心':[8,34,17,'爱情片'],
              '伦敦陷落':[2,3,55,'动作片']
              }
test_data = {'唐人街探案':[23,3,17]}
# 为了便于后续的数据分析操作,我们需要将训练数据 train_data 转换成 dataframe 类型。
train_df = pd.DataFrame(train_data).T  # 由于字典 train_data 中的 “键”(电影名称) 在转换为 dataframe 时是对应列名的,所以需要进行转置操作(df.T)将电影名称从 dataframe 的列索引变成行索引。
train_df.columns = ['搞笑镜头','拥抱镜头','打斗镜头','电影类型']  # 设置 train_df 的列索引(列名),前三列是特征列,最后一列是样本标记列。

转换后的训练数据 train_df 输出如下:
在这里插入图片描述

# 确定K值和分类的电影
K = 5
movie = '唐人街探案'
# 计算欧式距离,这部分代码用来计算新电影《唐人街探案》与训练集中所有电影的欧氏距离。
distance_list = []
for train_X in train_df.values[:,:-1]:
    test_X = np.array(test_data[movie])
    distance_list.append(euclidean_distance(train_X,test_X))

遍历获取训练样本 train_df 的特征向量 train_x,与测试样本 test_data 中的《唐人街探案》的特征向量 test_x 计算欧式距离,然后将计算结果添加到 distance_list 中。train_df.values 得到的是numpy数组,后面的中括号是切片操作,取数范围为:所有行、除倒数第1列的所有列。

# 按照距离递增排序,这部分代码主要是根据计算得到的欧氏距离对训练样本进行排序,方便后面寻找 K 近邻样本。
distance_df = pd.DataFrame({"欧式距离":distance_list},index=train_df.index)
result = pd.concat([train_df,distance_df],axis=1).sort_values(by="欧式距离")

在这里插入图片描述
将两个 dataframe 在列维度上进行拼接, 相当于给原来的训练数据增加了一列 “欧式距离” ;然后对所有样本按照欧式距离进行递增排序。axis =0 时表示行维度的拼接,axis = 1 时表示列维度的拼接;sort_values() 默认升序。
按照欧氏距离递增排序后的训练样本 result 的输出结果如下:
在这里插入图片描述

# 输出分类结果
d = Counter(result.head(K)['电影类型'])
print(movie,max(d,key=d.get))

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值