一、k近邻算法(kNN:k-Nearest Neighbors)
在machine learning中新建一个chapter 4文件夹
在特征空间中,每个样本因其特征不同处于不同的位置。对于一个新的样本,看和它最近的k个样本中哪个类别最多,就认为该样本属于哪个类别。
二、kNN基础
用一个假的数据集演示kNN原理
import numpy as np
import matplotlib.pyplot as plt
raw_data_x = [[3.393533211,2.331273301],
[3.110073483,1.781539638],
[1.343808831,3.368360954],
[3.582294042,4.679179110],
[2.280362439,2.866990263],
[7.423436942,4.696522875],
[5.745051997,3.533989803],
[9.172168622,2.511101045],
[7.792783481,3.424088941],
[7.939820817,0.791637231]
]
raw_data_y=[0,0,0,0,0,1,1,1,1,1]
原始的样本特征用raw_data_x表示,分别表示肿瘤大小和时间。
原始的样本类别用raw_data_y表示,0表示是良性肿瘤,1表示是恶性肿瘤
将原始的样本用作训练集(即训练使用的特征点X和训练使用的label y),创建成numpy形式的数组:
X_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)
绘制散点图查看特征是什么样的:
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='g')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='r')
现在对于一个新的数据:
x = np.array([8.093607318,3.365731514])
现在对于这个x,希望预测它属于哪一类,是红色的这一类,还是绿色的这一类。先看一下它的位置:
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='g')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='r')
plt.scatter(x[0],x[1],color='b')
下面来看一下使用kNN算法的过程
1、首先计算x这个点到每个样本点的距离
使用for循环将每个距离添加到一个距离数组里:
from math import sqrt
distance = []
for x_train in X_train:
d = sqrt(np.sum((x_train - x)**2))
distance.append(d)
也可以用一句话更方便地完成上述操作:
distance = [sqrt(np.sum((x_train - x)**2)) for x_train in X_train]
其中求距离用的是欧拉距离:
2、找到与x最近的是哪些点及其分类
不需要知道最近的距离是多少,而是要知道是哪些点,所以用argsort
先看一下按距离排序的索引:
np.argsort(distance)
array([8, 7, 5, 6, 9, 3, 0, 1, 4, 2], dtype=int64)
找到前k个点的分类(k设置为6):
nearest = np.argsort(distance)
k = 6
topK_y = [y_train[i] for i in nearest[:k]]
topK_y
[1, 1, 1, 1, 1, 0]
3、统计其中各类别的个数
可以方便地使用collection中的Counter这个类,向其中传入一个数组,得到是该数组中元素及元素出现频次的统计。
from collections import Counter
Counter(topK_y)
Counter({1: 5, 0: 1})
得到的结果可以看做是一个字典。
给这个Counter起一个名字votes,将其看做投票的过程(0有1票,1有5票)
可以调用Counter中一个most_common这个方法,找出票数最多的若干个元素,这里找出票数最多的一个元素即可
votes = Counter(topK_y)
votes.most_common(1)
[(1, 5)]
返回的是一个数组,数组中元素是元组,我们只需要知道分类,所以对于x的分类预测可以这样得到
predict_y = votes.most_common(1)[0][0]
1
可知x所属为恶性肿瘤
4、将notebook中代码整理出来写成一个函数
在chapter 4文件夹中新建一个kNN_function文件夹,新建一个kNN.py文件,创建一个kNN_classify函数:
import numpy as np
from math import sqrt
from collections import Counter
def kNN_classify(k,X_train,y_train,x):
assert 1 <= k <= X_train.shape[0],"k must be valid"
assert X_train.shape[0] == y_train.shape[0],\
"the size of X_train must equal to the size of y_train"
assert X_train.shape[1] == x.shape[0],\
"the feature number of x must be equal to X_train"
distances = [sqrt(np.sum((x_train - x)**2)) for x_train in X_train]
nearest = np.argsort(distances)
topK_y = [y_train[i] for i in nearest[:k]]
votes = Counter(topK_y)
return votes.most_common(1)[0][0]
传入的参数中,k是kNN用到的k,X_train,y_train是训练数据集,x是要预测的特征向量,返回x对应y的值是什么。
算法本身只有5行,assert断言保证用户传来的输入合法。
在notebook中运行:
%run kNN_function/kNN.py
predict_y