KNN最近邻算法是机器学习中最简单的学习算法之一,容易理解,也容易编程实现。一方面可以根据算法的思路采用python自己编写程序,熟悉整个学习流程,另一方面在机器学习SCIKIT learn包还专门有KNN模块,可以直接使用这个模块中的KNeighborsClassifier类。
下面介绍两种方案的具体流程和思路:
第一种:根据算法自己编程
主要流程:计算测试样点与已知样点之间的欧式距离,用距离来度量测算。这里已知样点已经明确了类别属性,然后对测试样点与已知样点之间的距离进行排序,选择前k个距离最小的样点,并提取其类别属性,对类别属性进行概率分析(占比例分析),最终确定其概率较大的类别为测试点的类别。
举例说明:下图中黑色测试样点属于哪一类?
在采用KNN算法的时候,就先计算黑色点和空间中所有点的欧式距离,然后进行排序。省略掉具体计算过程,我们从图中可以看到与黑色样点距离最近的几个样点,包括黄色菱形、圆形、三角形三种类别。如果k取4,那距离黑色样点最近的就是4个点,包括两个菱形,一个圆形,一个三角形。按照类别比例,菱形占50%,圆形和三角形各占25%,其中菱形概率要大于后两种,因此认为黑色样点属于菱形。如果k取5,就分析与黑色样点距离最近的5个样点,包括三个菱形,一个圆形,一个三角形,计算类别比例,其中菱形要占60%,圆形和三角形各占20%,所以菱形概率要大于后两种,黑色样点也还是属于菱形。
具体构造函数如下:
def knn(x_test, x_train, label, k):
datasize=x_train.shape[0] #获得样本数据的记录数量
data_sub = x_train - np.tile(x_test,(datasize,1)) #计算测试数据与已知样本之间的坐标之差,采用tile函数复制与样本数量一致大小的矩阵,假设样本记录为130行4列(130x4)矩阵,构造一个与样本记录数量一致的测试数据矩阵,形成130x1大小的矩阵。
dismat=data_sub**2 #对测试样本与已知样本的距离进行平方计算,注意这里data_sub是一个130x4大小的矩阵
dissum=dismat.sum(axis=1) #沿着行方向对测试点与已知点之间的距离计算距离平方和。
distance=dissum**0.5 #对距离求均方根,获得测试样本与已知样本之间的欧式距离
dis_sort = distance.argsort() #对获得的欧式距离进行标签排序
num=dis_sort[0:k] #选择前k个标签号
k_label=label[num] #获得这k个标签号所对应的类别
countlabel=k_label.value_counts() #对着k个标签号的类别进行个数统计
res_label=countlabel.index[0] #获得个数最多出现频率最高的那个类别,也即是测试样本的类别
return res_label # knn算法分类最终结果
第二种:使用sklearn机器学习模块
具体用法为:
from sklearn.neighbors import KNeighborsClassifier
knn=KNeighborsClassifier()
knntrain=knn.fit(samples, types)
knnresult=knn.predict(tests)
其中参数samples为处理好的已知样本记录数据,types为已知样本类别数据,这两种数据通常情况下会放在一个文件里,因此可以利用pandas或者numpy来把样本数据及其类别准备好。tests为测试样本数据,其格式应该与已知样本数据一致。
对于KNeighborsClassifier类,其用法为:KNeighborsClassifier(n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2,metric=’minkowski’, metric_params=None, n_jobs=1, **kwargs)。如果不填参数,那就是选用默认参数。
参数中:n_neighbors为选择邻近样本数,默认为5;
weights为权重,默认为uniform即同样权重,如果修改为distance,就按距离远近分配权重,距离近的权重系数大,距离远的权重系数小;
algorithm=’auto’,默认为自动选择最好的算法,共包括三种算法:Kd-tree、ball-tree和brute,其中前两种为排序时采用的二叉树算法中的两种算法,brute为暴力算法。当已知样本记录数据很大时,再采用上述的算法,即用测试样本与所有已知样本数据进行距离计算形成一个超大维矩阵,涉及超大维矩阵运算,会很损耗机器内存资源,导致速度慢,效率较低。如果采用kd-tree或者ball-tree算法,可以先把已知样本数据之间按距离远近分类排序,处理后就是一个有序的数据,那测试样本就可以根据其特征在优化排序好的已知样本数据中寻找自己的位置,其效率就会很高。
leaf_size默认是30,用于设定kd-tree或ball-tree的叶子节点数
如下为对iris数据进行KNN最近邻测试:
def getdata(path):
data = pd.read_csv(path) #读取数据集
character = data.iloc[:,0 :4] #用iloc方法选取第1列到第4列为样本特征集
label = data.iloc[0:130, 4] #用iloc方法选取第5列为花的类别
return character ,label
def knn(character,label,test,k):
knn=KNeighborsClassifier(n_neighbours=k) #调用KNeighborsClassifier类,给定近邻数目为k个
knn.fit(character,label) #使用fit方法,输入已知样本数据和类别标签进行训练匹配
result=knn.predict(test) #使用predit方法,输入测试样本数据进行分类预测
return result #返回分类值