**小白的搬运python学习**
**K-NN近邻算法**
k邻近算法
K-NN近邻法是一种基本分类与回归方法
工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
KNN近邻算法判断的核心
没错,就是距离度量。
为了便于理解,我先讲最邻近算法,再引入K-NN算法。
如图所示为了判断(101,20)是属于什么电影分类,我们会很自然的想到离哪个标准点近就属于哪种电影。因此我们会使用高中学习到的两点间
距离公式来判断距离量度的大小。
通过计算,我们可以得到如下结果:
(101,20)->动作片(108,5)的距离约为16.55
(101,20)->动作片(115,8)的距离约为18.44
(101,20)->爱情片(5,89)的距离约为118.22
(101,20)->爱情片(1,101)的距离约为128.69
通过计算可知,红色圆点标记的电影到动作片 (108,5)的距离最近,为16.55。如果算法直接根据这个结果,判断该红色圆点标记的电影为动作片,这个算法就是最近邻算法,而非K-NN近邻算法。那么K-NN近邻算法是什么呢?
KNN近邻算法步骤如下:
1.计算已知类别数据集中的点与当前点之间的距离;
2.按照距离递增次序排序;
3.选取与当前点距离最小的k个点;
4.确定前k个点所在类别的出现频率;
5.返回前k个点所出现频率最高的类别作为当前点的预测分类。
比如,现在我这个k值取3,那么在电影例子中,按距离依次排序的三个点分别是动作片(108,5)、动作片(115,8)、爱情片(5,89)。在这三个点中,动作片出现的频率为三分之二,爱情片出现的频率为三分之一,所以该红色圆点标记的电影为动作片。这个判别过程就是k-近邻算法。
既然我们已经了解KNN算法的原理,那么就进入今天的主戏吧。使用pycharm实现KNN算法
1.创建数据集
import numpy as np
import matplotlib.pyplot as plt
"""
函数说明:创建数据集
group 二维训练数据集(对应x,y轴的数据)
labels 对应训练集的标签
"""
def createDataSet():
group = np.array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5],[1.1,1.0],[0.5,1.5]])
labels = np.array(['A','A','B','B','A','B'])
return group,labels
if __name__=='__main__':
group, labels = createDataSet()
#对于类别为A的数据集我们使用红色六角形表示
plt.scatter(group[labels=='A',0],group[labels=='A',1],color = 'r',marker= '*')
#对于类别为B的数据集我们使用绿色六角形表示
plt.scatter(group[labels == 'B', 0], group[labels == 'B', 1], color='g', marker='+')
plt.show()
其实对于group和labels的关系,就是[1.0,2.0]这个数据对应的类别是’A’
(1)引入numpy库Numpy
由于机器学习算法在数据处理过程中大都涉及线性代数的知识,需要用到矩阵操作,Python本身没有处理矩阵的数据类型,因此需要使用附加的函数库。其中NumPy函数库是Python开发环境的一个独立模块,是Python的一种开源的数值计算扩展工具,是处理数值计算最为基础的类库。这种工具可以用来存储和处理大型多维矩阵,比Python自身的列表结构要高效的多。尽管Python的list类型已经提供了类似于矩阵的表示形式,但是NumPy提供了更多的科学计算函数。NumPy被定位为数学基础库,属于比较底层的Python库,其地位趋向于成为一个被其它库调用的核心库。
导入方式如下: import numpy as np
(2)对于if__name__==‘main’:的解释
详细解释请看这位博主的链接
2.(基于欧拉公式)实现属于我们的KNN分类器
到这里,也许有人会疑惑上面例子中的特征是2维的,这样的距离度量可以用两点距离公式计算,但是如果是更高维的呢?对,没错。我们可以用欧氏距离(也称欧几里德度量)
而我们高中所学的两点间距离公式就是欧氏距离在n=2时的情况
****代码如下****
import numpy as np
import operator
import matplotlib.pyplot as plt
"""
函数说明:创建数据集
group 二维训练数据集(对应x,y轴的数据)
labels 对应训练集的标签
"""
def createDataSet():
group = np.array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5],[1.1,1.0],[0.5,1.5]])
labels = np.array(['A','A','B','B','A','B'])
return group,labels
"""
函数说明:KNN分类器
"""
def classify0(inX, dataSet, labels, k):
# numpy函数shape[0]返回dataSet的行数
dataSetSize = dataSet.shape[0]
# 在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
# 二维特征相减后平方
sqDiffMat = diffMat ** 2
# sum()所有元素相加,sum(0)列相加,sum(1)行相加
sqDistances = sqDiffMat.sum(axis=1)
# 开方,计算出距离
distances = sqDistances ** 0.5
# 返回distances中元素从小到大排序后的索引值
sortedDistIndices = distances.argsort()
# 定一个记录类别次数的字典
classCount = {}
for i in range(k):
# 取出前k个元素的类别
voteIlabel = labels[sortedDistIndices[i]]
# dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
# 计算类别次数
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# python3中用items()替换python2中的iteritems()
# key=operator.itemgetter(1)根据字典的值进行排序
# key=operator.itemgetter(0)根据字典的键进行排序
# reverse降序排序字典
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
# 返回次数最多的类别,即所要分类的类别
return sortedClassCount[0][0]
if __name__ == '__main__':
# 创建数据集
group, labels = createDataSet()
# 测试集
test = [1.0,2.1]
# kNN分类
test_class = classify0(test, group, labels, 3)
# 打印分类结果
print(test_class)
test = [0.4, 2.0]
# kNN分类
test_class = classify0(test, group, labels, 3)
# 打印分类结果
print(test_class)
总结
分类器一定是正确的吗?答案是否定的,分类器并不会得到百分百正确的结果,我们可以使用多种方法检测分类器的正确率。此外分类器的性能也会受到多种因素的影响,如分类器设置和数据集等。不同的算法在不同数据集上的表现可能完全不同。为了测试分类
器的效果,我们可以使用已知答案的数据,当然答案不能告诉分类器,检验分类器给出的结果是否符合预期结果。通过大量的测试数据,我们可以得到分类器的错误率-分类器给出错误结果的次数除以测试执行的总数。错误率是常用的评估方法,主要用于评估分类器在某个数据集上的执行效果。完美分类器的错误率为0,最差分类器的错误率是1.0。同时,我们也不难发现,k-近邻算法没有进行数据的训练,直接使用未知的数据与已知的数据进行比较,得到结果。因此,可以说k-近邻算法不具有显式的学习过程。