监督学习-分类-kNN
- kNN:K最近邻算法,k-Nearest Neighbor
- k个最近的邻居
- 属于:监督学习,分类算法
kNN算法思想
- 衡量未知分类点周围邻居的权重
- 然后把它归类到权重更大的那一类
较适用于类域交叉重叠的样本
kNN算法描述
- 输入k值
- 对未知类别数据集中的每一个点依此执行以下操作
- 计算当前点与已知类别数据集中的点之间的距离
- 按照距离以递增次序排序
- 选取与当前点距离最小的k个点
- 确定前k个点所在的类别出现的频率
- 返回前k个点出现频率最高的类别作为当前点的预测类别
knn1.png
k值选取
K值太小,如等于1
- 模型更复杂
- 优点:误差减小,训练结果更精确
- 缺点:过拟合,预测失效
knn2.png
K值太大
k值太大,如等于16
- 模型更简单
- 缺点:误差增大,训练结果偏差更大
- 优点:拟合适当,预测效果好
knn3.png
合适的k值
如等于9
knn4.png
如何取k值?
取一个较小的k值
不断交叉验证(训练集/测试集)来选择最优k值
交叉验证
knn5.png
距离度量
欧式距离
knn6.png
曼哈顿距离
knn7.png
knn8.png
kNN算法优缺点
- 优点:
- 简单,容易理解和实现
- 基于实例预测,不需训练模型
- 适合对象有多个标签的分类
- 缺点:
- 样本不均衡时易失效
- 计算量大,每个待分类对象都需要计算它到 全体已知样本的距离
- 噪声敏感
kNN算法手动实现
knn1.png
特征和标签
类别 | 重量 | 光洁度 |
---|---|---|
苹果 | 150g | 光滑 |
苹果 | 170g | 光滑 |
橘子 | 130g | 粗糙 |
橘子 | 140g | 粗糙 |
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
plt.style.use('seaborn')
plt.rcParams['font.family'] = ['Arial Unicode MS', 'Microsoft Yahei', 'SimHei', 'sans-serif']
features = np.array([[150, 0], [170, 0], [130, 1], [140, 1]]) # 特征数据:重量和是否光滑
labels = np.array([0, 0, 1, 1]) # 标签数据:0苹果,1橘子
# 待预测数据
w = np.array([180, 1])
features # 训练集特征
array([[150, 0],
[170, 0],
[130, 1],
[140, 1]])
features[:,0]
features[:,1][2:]
array([1, 1])
plt.figure(figsize=(12, 6))
plt.scatter(features[:,0][:2], features[:,1][:2], linewidth=30, color='g')
plt.scatter(features[:,0][2:], features[:,1][2:], linewidth=30, color='r')
plt.scatter(w[0], w[1], linewidth=30, color='black')
<matplotlib.collections.PathCollection at 0x7727d68>
output_5_1.png
欧氏距离
knn6.png
kNN运算过程
# 训练数据特征
features
array([[150, 0],
[170, 0],
[130, 1],
[140, 1]])
# 预测数据特征
w
array([180, 1])
求预测数据特征到每一个训练数据特征的距离
distances = np.sum((features - w) ** 2, axis=1) ** 0.5
distances
array([30.01666204, 10.04987562, 50. , 40. ])
nearest = np.argsort(distances) # 返回数组值从小到大排列以后的索引
nearest
array([1, 0, 3, 2], dtype=int64)
1,0,3,2对应的就是下面便签的索引值
labels # 训练数据的标签,索引是 0,1,2,3,对应的标签是:0,0,1,1 (苹果,苹果,橘子,橘子)
array([0, 0, 1, 1])
# 设k=3,
nearest[:3] # 离未知值最近的3个已知值的索引
topK_y = labels[nearest[:3]] # 索引对应的训练数据标签值
topK_y
array([0, 0, 1])
votes = np.bincount(topK_y) # 返回从0开始到最大数组值,每个值的频次(索引就数组值,值就是出现频次)
votes
array([2, 1], dtype=int64)
np.argmax(votes) # 返回最大值的索引
0
封装为和scikit-learn一样的函数,供调用
def kNN_classify(k, X_train, y_train, x):
"""我手打的第一个机器学习算法:kNN!
attr:
k: kNN算法的k值(选取最近的多少个点)
X_train: 训练集特征
y_train: 训练集标签
x: 预测集特征
return: 预测分类值
"""
# 注释
distances = np.sum((X_train - x) ** 2, axis=1) ** 0.5
nearest = np.argsort(distances)
topK_y = y_train[nearest[:k]]
votes = np.bincount(topK_y)
return np.argmax(votes)
kNN_classify?
help(kNN_classify)
Help on function kNN_classify in module __main__:
kNN_classify(k, X_train, y_train, x)
我手打的第一个机器学习算法:kNN!
attr:
k: kNN算法的k值(选取最近的多少个点)
X_train: 训练集特征
y_train: 训练集标签
x: 预测集特征
return: 预测分类值
kNN_classify(3, features, labels, w)
0