6行代码实现kNN算法

6行代码实现kNN算法

监督学习-分类算法-kNN


  • kNN:K最近邻算法,k-Nearest Neighbor
  • k个最近的邻居
  • 属于:监督学习,分类算法

kNN算法思想

  • 衡量未知分类点周围邻居的权重
  • 然后把它归类到权重更大的那一类

较适用于类域交叉重叠的样本


kNN算法描述

  1. 输入k值
  2. 对未知类别数据集中的每一个点依此执行以下操作
    1. 计算当前点与已知类别数据集中的点之间的距离
    2. 按照距离以递增次序排序
    3. 选取与当前点距离最小的k个点
    4. 确定前k个点所在的类别出现的频率
    5. 返回前k个点出现频率最高的类别作为当前点的预测类别

kNN算法优缺点

  • 优点:
    • 简单,容易理解和实现
    • 基于实例预测,不需训练模型
    • 适合对象有多个标签的分类
  • 缺点:
    • 样本不均衡时易失效
    • 计算量大,每个待分类对象都需要计算它到 全体已知样本的距离
    • 噪声敏感

kNN算法手动实现

特征和标签

类别重量光洁度
苹果150g光滑
苹果170g光滑
橘子130g粗糙
橘子140g粗糙
import numpy as np
import matplotlib.pyplot as plt
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橘子

# 待预测数据,这里为临时的1维数据
w = np.array([180, 0])

features # 训练集特征
array([[150,   0],
       [170,   0],
       [130,   1],
       [140,   1]])
features[:, 0][:2]  # 苹果重量
array([150, 170])
features[[0, 1], [0, 0]]  # 花式索引(竖着看)
array([150, 170])
features[:, 1][:2]
array([0, 0])
features[[0, 1], [1, 1]]
array([0, 0])
w
array([180,   0])
plt.figure(figsize=(18, 8))

plt.scatter(
    features[:, 0][:2],
    features[:,1][:2],
    color='r',
    s=500,
    alpha=0.8,
    label='苹果',
)

plt.scatter(
    features[:, 0][2:],
    features[:,1][2:],
    color='y',
    s=500,
    alpha=0.8,
    label='橘子',
)

plt.scatter(
    w[0],
    w[1],
    color='#000000',
    s=500,
    alpha=0.8,
    label='未知',
)

plt.legend()
<matplotlib.legend.Legend at 0x54e90f0>

[外链图片转存失败(img-2mvLxkMe-1566634952497)(output_11_1.png)]

1计算未知点到所有已知点的距离
d 12 = ∑ k = 1 n ( x 1 k − x 2 k ) 2 d_{12}=\sqrt{\sum_{k=1}^{n}\left(x_{1 k}-x_{2 k}\right)^{2}} d12=k=1n(x1kx2k)2

features
array([[150,   0],
       [170,   0],
       [130,   1],
       [140,   1]])
w
array([180,   0])
((180-140) ** 2 + (0 - 1) ** 2) ** 0.5
40.01249804748511
(w - features)
array([[30,  0],
       [10,  0],
       [50, -1],
       [40, -1]])

distances = np.sum((w - features) ** 2, axis=1) ** 0.5
distances
array([30.        , 10.        , 50.009999  , 40.01249805])

2 距离从小到大排序

np.sort(distances)  # 返回排序后的值,没用
# 原来的distances,索引0,1表示类别苹果,2,3表示类别橘子
# 返回排序后的原索引,索引和类别的关系没变
nearest = np.argsort(distances)  # 返回从小到大排序以后的索引
nearest
array([1, 0, 3, 2], dtype=int64)
labels  # 类别:0,1,2,3
# 0,1对应0,0(苹果)
# 2,3对应1,1(橘子)
array([0, 0, 1, 1])

3 取前k个值,索引对应的标签值

k = 3
nearest[:k]
array([1, 0, 3], dtype=int64)
labels
labels[[2, 1]]  # 查询对应索引的值
topK_y = labels[nearest[:k]]  # 查询前k个索引对应的值(标签)
topK_y
array([0, 0, 1])

4 计算前k个值类别出现的频次

a = np.array([0, 1, 2, 1, 3, 0, 0])
np.bincount(a) # 0有3个,1有2个,2有1个,3有1个(索引就是原值)
array([3, 2, 1, 1], dtype=int64)
votes = np.bincount(topK_y)  # 2个0,1个1
votes
array([2, 1], dtype=int64)

5 输出出现频次最高的值的索引

np.max(votes)
np.argmax(votes)
0

封装成函数

def knn_classify(k, X_train, y_train, X_test):
    """我手写的机器学习算法:kNN.
    attr:
        k: 邻居个数,1,2,3.。。
        X_train: 训练集特征,[[180, 0], [120, 1]....]
        y_train: 训练集标签, [0, 1, 0, 1....]
        X_test: 测试集特征,[180, 0]
        
    return: 测试集预测的标签, 0, 1
    """
    
    distances = np.sum((X_test - X_train) ** 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?
knn_classify(3, features, labels, w)
0

6行代码完成knn算法案例

import numpy as np
X_train =np.array([[150, 0], [170, 0], [130, 1], [140, 1]])
y_train = np.array([0, 0, 1, 1])
X_test = np.array([180, 0])
y_test = np.argmax(np.bincount(y_train[np.argsort(np.sum((X_test - X_train) ** 2, axis=1) ** 0.5)[:k]]))
y_test
0

sklearn的kNN算法

from sklearn.neighbors import KNeighborsClassifier
my_classifier = KNeighborsClassifier(n_neighbors=3)  # k值设为3,不能超过训练集数量
my_classifier
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
                     metric_params=None, n_jobs=None, n_neighbors=3, p=2,
                     weights='uniform')
my_classifier.fit(X_train, y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
                     metric_params=None, n_jobs=None, n_neighbors=3, p=2,
                     weights='uniform')
X_test  # 特征维度不够
array([180,   0])
X_test.reshape(1, 2)
array([[180,   0]])
# predict函数需要二维的数组
my_classifier.predict(X_test.reshape(1, 2))
array([0])

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值