序言
KNN作为最基础的机器学习算法,是很多学习算法的孩子们最先接触到的,但该算法从头到尾自己实现也是有一定难度,很多课程只是教怎么调封装好的算法库,却没有教核心的算法怎么从头实现,所以有点舍本逐末。
算法核心
1、近朱者赤,近墨者黑。根据临近的标签值通过投票法则确定样本类别。
2、每一个未知样本都要计算它到所有已知有标签样本的距离。
3、k值选择比较重要。
代码实现
import numpy as np
def createdata():
"""
创建一个数据集
Return:
features表示特征:我们这里用身高、体重来表示特征
labels表示类别:有三个类别,分别是胖子、中子、瘦子 -> 对应1 2 3
"""
#["身高", "体重"]
features = np.array([[167, 160],
[170, 140],
[180, 120],
[190, 130],
[150, 148],
[168, 135]])
categories_map = {1:"胖子", 2:"中子", 3:"瘦子"}
labels = np.array([1, 2, 3, 3, 1, 2])
return {"features":features, "labels":labels, "categories_map":categories_map}
def KNNClassify(samples: list, dataset: dict, k: int):
"""
samples表示待分类的特征输入,单一样本.
dataset表示有标签对应的数据集.
"""
samples = np.array(samples)
labels = dataset["labels"]
num_samples = labels.shape[0] #数据集中样本的数量
features = dataset["features"]
diff = np.tile(samples, (num_samples, 1)) - features #这个单一样本特征和数据集中样本特征的差距
L2 = diff**2 #L2距离
L2_ALL = L2[:, 0] + L2[:, 1] #身高的差距和体重的差距和,表示总的差距,这里当然可以加权, 如w1 = 1.2, w2 = 0.8, w1*L2[:, 0] + w2*L2[:, 1]
distance = L2_ALL ** 0.5 #开平方根
sort_index = np.argsort(distance) #从小到大排序,返回索引
class_count = {}
for i in range(k):
#选k个邻居, 误差距离和labels是一一对应的关系,所以可以根据误差排序的index找到对应的label
neighbor_label = labels[sort_index[i]]
#字典的get方法表示,如果字典中有这个key就返回对应的value,如果没有这个key就返回设定的数,这里应该设0.
class_count[neighbor_label] = class_count.get(neighbor_label, 0) + 1
#投票法则,前k个最近距离中某个类别数量最多,就把未知样本确定为这个类别
max_count = 0
for k,v in class_count.items():
if v > max_count:
max_count = v
res = k
return res
if __name__ == "__main__":
input_samples = [[164.5, 98.2],
[175.0, 155.5]]
dataset = createdata()
names = ["ll", "ac"]
categories_map = dataset["categories_map"]
for name, sample in zip(names, input_samples):
res = KNNClassify(samples=sample, dataset=dataset, k=3)
pred = categories_map[res]
print("%s是一个%s"%(name, pred))
思考总结
1、knn是监督算法还是无监督算法?
答:有监督,因为是通过“有标签”的样本最终确定未知样本的类别。
2、knn的k值怎么选择最优?
答:交叉验证,可以用一部分有标签的样本做验证集,选择不同的k值下看KNN对这些验证集样本分类的正确率,选择最高的正确率对应的k值就是寻求最优的一种方法。
3、knn的k选小了会怎么样?大了会怎么样?
答:k值选小了容易过拟合,分类结果不具有代表性。k值选大了也会造成误差积累,偏离了近朱者赤,近墨者黑的思想。
4、knn的优点和缺点?
答:优点:不用学习,简单。缺点:计算量大,每一个未知样本都要全部的训练集样本来确定它的类别。
参考
https://www.cnblogs.com/ahu-lichang/p/7151007.html