第二章 k-近邻算法
PS:个人笔记 根据《机器学习实战》这本书,Jack-Cui的博客,以及深度眸的视频进行学习
1 KNN原理
它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,⭐通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
2 优缺点及适用数据范围
优点:
①精度高(将测试数据与训练数据根据不同特征值算出其距离,然后设置选取K值,选取的K值中按照vote规则将该数据分类)
②对异常值不敏感 (因为是要设置K值,也就是选取最近的K个数据,所以对于存在的一些极端值异常值,很好的忽略了)
③无数据输入假定 (类比NB算法,该算法要假设样本间是独立的,而对于KNN算法则无需这些假定)
缺点:
①计算复杂度高(虽然是取K值,但是算距离时测试样本要和每个训练样本进行计算,然后进行排序,得出距离最近的K个样本,所以如果训练样本的量是1000,或者更高,就会造成很大的计算)
②空间复杂度高()
③最大的缺点是无法给出数据的内在含义()
适用数据范围:
①数值型
②标称型
3 KNN算法的向量距离度量准则
欧式距离——欧几里得度量(euclidean metric)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。
计算公式:
4 代码实现(代码是Jack-Cui博客中的代码)
4.1 准备数据集
import numpy as np
def createDataSet(): #定义一个函数,函数作用是创建数据集,返回特征列表和标签列表
group = np.array([[1,101],[5,89],[108,5],[115,8]]) #四个数据 np.array()是数组功能即创建数组
labels = ['爱情片','爱情片','动作片','动作片'] #四个数据对应的标签分类
return group, labels
if __name__ == '__main__':
group, labels = createDataSet() #创建数据集
print(group) #打印显示
print(labels)
4.2 k-近邻算法
import numpy as np
import operator
"""
Parameters:
inX - 用于分类的数据(测试集)
dataSet - 用于训练的数据(训练集)
labes - 分类标签
k - kNN算法参数,选择距离最小的k个点
Returns:
sortedClassCount[0][0] - 分类结果
"""
def classify0(inX, dataSet, labels, k): #KNN算法,分类器
dataSetSize = dataSet.shape[0] #np.shape()函数返回的是数组的行和列;这里shape[0]返回的行数
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #np.tile()函数是数组进行复制,第一个参数是数组,第二个参数则是复制的规则,行列分别复制几次;这里是在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向);这里也就是将一个数据inX与所有的训练数据进行二维特征相减,得到一个shape[0]行,1列的数组
sqDiffMat = diffMat**2 #二维特征相减后平方
sqDistances = sqDiffMat.sum(axis=1) #sum()所有元素相加,sum(0)列相加,sum(1)行相加;这里就是行相加
distances = sqDistances**0.5 #开方,计算出距离,这里就得出了距离了
sortedDistIndices = distances.argsort() #argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y
classCount = {} #定一个记录类别次数的字典
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]] #取出前k个元素的类别,这里其实就是要vote,因为前面已经按照从大到小排列了
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。这里key肯定存在,然后计算类别次数
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #items()方法以列表返回可遍历的(键, 值) 元组数组。key=operator.itemgetter(1)根据字典的值进行排序,key=operator.itemgetter(0)根据字典的键进行排序,reverse降序排序字典
return sortedClassCount[0][0] #返回次数最多的类别,即所要分类的类别
4.3 整体代码
import numpy as np
import operator
def createDataSet():
group = np.array([[1,101],[5,89],[108,5],[115,8]])
labels = ['爱情片','爱情片','动作片','动作片']
return group, labels
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 = {}
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
if __name__ == '__main__':
group, labels = createDataSet()
test = [101,20] #测试集
test_class = classify0(test, group, labels, 3) #KNN分类
print(test_class) #打印分类结果