学渣也学ML:K-近邻算法笔记之一
什么是KNN
书面定义:
k一近邻算法(k-NearestNeighbouralgorithm),又称为KNN算法.是数据挖掘技术中原理最简单的算法,采用测量不同特征之值之间的距离方法来进行分类.KNN的工作原理:给定一个已知标签类别的训练数据集,输入没有标签的新数据后,在训练数据集中找到与新数据最邻近的k个实例,如果这k个实例的多数属于某个类别,那么新数据就属于这个类别.可以简单理解为,由那些离X最近的k个点来投票决定X归为哪一类。
学渣理解:
*物以类聚,人以群分,或者说近朱者亦,近墨者黑,邻居决定的你的颜色。就是寻找离未知类型X最近的K个数据,由它们的投票数来决定X的分类。假如现在有一堆A类数据(蓝色),一堆B类数据(红色),再给出一个不知属哪类的数据X(绿色),用KNN来判断它应该属于哪一类。那么怎么分呢?先以X为中心画一个圈,里面包含了K个数据(A的个数加B的个数等于K),接下来数一数圈中A的个数和是B的个数,哪一类的个数多,X就属于哪一类。
就是如此简单的分类方法吗?好像想得有点美!
再看看这个圈怎么画呢,画小一点,发现X属于B(上图的实线圈),画大一点,发现它又属于A了(上图的虚线圈)。还有一种可能就是如果圈里A的个数和B的个数同样多,又属哪一类?
后面这种问题好解决,要想圈的的个数不相等,最简单的办法就是使K为奇数,这样就可以实施少数服从多数原理了。(其实个数相等也没事,还有距离远近的影响来判断)
圈的大小如何确定,其实也就是K的大小确定,这是一个难题。
书上说有两种方法:
经验法:以前处理过类似问题,按经验来取。学渣看来就是通过猜测尝试取不同的值来看精度进行选择。
均方根误差:这个以后再说
邻居的距离:通常使用的距离函数有:欧氏距离、余弦距离、汉明距离、曼哈顿距离等,一般选欧氏距离作为距离度量,但是这是只适用于连续变量。在文本分类这种非连续变量情况下,汉明距离可以用来作为度量。通常情况下,如果运用特殊的算法来计算度量的话,K近邻分类精度可显著提高,如运用大边缘最近邻法或者近邻成分分析法。
上图为借鉴
不太懂各种距离,仔细看了一下,发现欧氏距离不就是高中数学的求坐标轴上两个点的距离公式吗。或者说直角三角形求斜边的公式,勾股定理a2 + b2=c2的变形啦。
两个点的距离即二维空间用
,
三维空间就再加个Z坐标:
但是现在有n个维度,该怎么算距离呢?
点A = (x1, x2, … , xn)
点B = (y1, y2, … , yn)
AB的距离 平方 = (x1-y1)2+(x2-y2)2+…+(xn-yn)2
AB就是所求的A,B两个多维空间中的点之间的距离,这样就得到欧氏距离的公式:
来个案例:电影分类
书上告诉我们KNN算法的流程:
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类
那就按书上的流程来吧
用K近邻算法根据打斗次数和接吻次数来分类一个电影是爱情片还是动作片
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
---|---|---|---|
无问西东 | 1 | 101 | 爱情片 |
最好的我们 | 5 | 89 | 爱情片 |
前任3 | 12 | 97 | 爱情片 |
流浪地球 | 108 | 5 | 动作片 |
复仇者联盟4 | 112 | 9 | 动作片 |
战狼2 | 115 | 8 | 动作片 |
新电影 | 24 | 67 | ? |
先自己用字典将这个表构建出来,然后用Pandas将它转换为DataFrame结构
import pandas as pd
#构建数据集
rowdata={'电影名称':['无问西东','最好的我们','前任3','流浪地球','复仇者联盟4','战狼2'],
'打斗镜头':[1,5,12,108,112,115],
'接吻镜头':[101,89,97,5,9,8],
'电影类型':['爱情片','爱情片','爱情片','动作片','动作片','动作片']}
#将字典构建的数据集转换为DataFrame格式
movie_data=pd.DataFrame(rowdata)
再按照书的算法流程来
#1根据欧氏距离的公式计算已知类别数据集中的点与新数据点之间的距离
new_data=[24,67]
dist=list((((movie_data.iloc[:6,1:3]-new_data)**2).sum(1))**0.5)
各节点与新数据点[24,67]的距离计算结果为:
#2将距离升序排序,然后选取距离最小的K个点,这里取5个点。你也可以尝试取3,1个查看结果
dist1=pd.DataFrame({'dist':dist,'labels':(movie_data.iloc[:6,3])})
dr=dist1.sort_values(by='dist')[:5]
排序后的结果为:
#3确定前K个点所在的类别出现的频率
#4选择频率最高的类型作为当前数据的预测类别
re=dr.loc[:,'labels'].value_counts()
result=[]
result.append(re.index[0])
print(result)
发现测试结果为:爱情片。
封装函数,构建分类器
我们把KNN算法的几个步骤封装起来,就可以构建成一个分类器了。
封装:三个数据:testX:需要预测分类的数据集(测试集),dataSet:已知分类标签的数据集(训练集),k:k-近邻算法参数,选择距离最小的k个点
一个结果: result:分类结果
import pandas as pd
def classify0(testX,dataSet,k):
result=[]
dist = list((((dataSet.iloc[:6,1:3]-testX)**2).sum(1))**0.5)
dist_l = pd.DataFrame({'dist': dist, 'labels': (dataSet.iloc[:6, 3])})
dr = dist_l.sort_values(by = 'dist')[: k]
re = dr.loc[:,'labels'].value_counts()
result.append(re.index[0])
return result
#定义数据集,调用分类器就可得到分类结果
rowdata={'电影名称':['无问西东','最好的我们','前任3','流浪地球','复仇者联盟4','战狼2'],
'打斗镜头':[1,5,12,108,112,115],
'接吻镜头':[101,89,97,5,9,8],
'电影类型':['爱情片','爱情片','爱情片','动作片','动作片','动作片']}
#将字典构建的数据集转换为DataFrame格式
testX = [46,35]
dataSet = pd.DataFrame(rowdata)
k= 5
classify0 (testX,dataSet,k)
这个分类器用于当前的电影分类数据非常合适,那是否具有通用性可用于其他案例呢?
当然不能完全照搬,需要根据数据集的不同而进行相应的调整啦。
// An highlighted block
var foo = 'bar';
再来个案例
算了,明天再来吧