KNN(邻近算法)

一、 什么是KNN

1、概念:

KNN(K-NearesNeighbor) 即K邻近法,是一个理论上比较成熟的、也是最简单的机器学习算法之一。用老话就说:“人以群分,物以类聚”。

2、核心思想

一个样本与数据集中的k个样本最相似, 如果这k个样本中的大多数属于某一个类别, 则该样本也属于这个类别。也就是说,该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。KNN方法在类别决策时,只与极少量的相邻样本有关。

3、KNN算法步骤

3.1、计算距离

给定两个样本 公式
公式
,其中n表示特征数 ,X和Y两个向量间的欧氏距离(Euclidean Distance)表示为:
欧氏距离二维表示
拓展到多维空间,则公式变成这样:
欧氏距离多为表示
这样我们就明白了如何计算距离,KNN算法最简单粗暴的就是将预测点与所有点距离进行计算,然后保存并排序,选出前面K个值看看哪些类别比较多。

3.2、升序排列

3.3、去前k个

3.4、加权平均

4、K值选取

KNN的决策边界一般不是线性的,也就是说KNN是一种非线性分类器,如下图。
在这里插入图片描述
1、K越小越容易过拟合,当K=1时,这时只根据单个近邻进行预测,如果离目标点最近的一个点是噪声,就会出错,此时模型复杂度高,稳健性低,决策边界崎岖。

2、但是如果K取的过大,这时与目标点较远的样本点也会对预测起作用,就会导致欠拟合,此时模型变得简单,决策边界变平滑。

3、如果K=N的时候,那么就是取全部的样本点,这样预测新点时,最终结果都是取所有样本点中某分类下最多的点,分类模型就完全失效了。
4、k值的选取,既不能太大,也不能太小,何值为最好,需要实验调整参数确定!

小贴士:
如何选取k值

  • 经验
  • 均方根误差

4、KNN算法的优势和劣势

4.1、优点:

  • 简单有效
  • 重新训练代价低
  • 算法复杂度低
  • 适合类域交叉样本
  • 适用大样本自动分类

4.2、缺点:

  • 惰性学习
  • 类别分类不标准化
  • 输出可解释性不强
  • 不均衡性
  • 计算量较大

二、用Python演示KNN算法

话不多说,直接上代码演示

1、有下面的图片中的数据推测《唐人街探案》属于那种电影类型。

漂亮的数据

import math

movie_data = {"宝贝当家": [45, 2, 9, "喜剧片"],
              "美人鱼": [21, 17, 5, "喜剧片"],
              "澳门风云3": [54, 9, 11, "喜剧片"],
              "功夫熊猫3": [39, 0, 31, "喜剧片"],
              "谍影重重": [5, 2, 57, "动作片"],
              "叶问3": [3, 2, 65, "动作片"],
              "伦敦陷落": [2, 3, 55, "动作片"],
              "我的特工爷爷": [6, 4, 21, "动作片"],
              "奔爱": [7, 46, 4, "爱情片"],
              "夜孔雀": [9, 39, 8, "爱情片"],
              "代理情人": [9, 38, 2, "爱情片"],
              "新步步惊心": [8, 34, 17, "爱情片"]}

# 测试样本  唐人街探案": [23, 3, 17, "?片"]
#下面为求与数据集中所有数据的距离代码:
x = [23, 3, 17]
KNN = []
for key, v in movie_data.items():
    d = math.sqrt((x[0] - v[0]) ** 2 + (x[1] - v[1]) ** 2 + (x[2] - v[2]) ** 2)
    KNN.append([key, round(d, 2)])

# 输出所用电影到 唐人街探案的距离
print(KNN)

#按照距离大小进行递增排序
KNN.sort(key=lambda dis: dis[1])

#选取距离最小的k个样本,这里取k=5;
KNN=KNN[:5]
print(KNN)

#确定前k个样本所在类别出现的频率,并输出出现频率最高的类别
labels = {"喜剧片":0,"动作片":0,"爱情片":0}
for s in KNN:
    label = movie_data[s[0]]
    labels[label[3]] += 1
labels =sorted(labels.items(),key=lambda l: l[1],reverse=True)
print(labels,labels[0][0],sep='\n')

代码示例参考自:https://blog.csdn.net/saltriver/article/details/52502253

2、第二个实例:

示例数据与代码都来自b站智源学院

特别棒的一节课

# -*- coding:utf-8 -*-
"""
@Project: datadig 
@Author: 郑虎虎
@File: KNN2.py
@IDE: PyCharm
@Time: 2020-10-21 08:51:23
"""
import csv
import random

# 读取数据

with open("Prostate_Cancer.csv", "r") as file:
    reader = csv.DictReader(file)  # 借用字典读取文件
    # for row in reader:
    #     print(row)

    datas = [row for row in reader]  # 将数据全部读出,放到列表中
    # print(datas)

# 分组:分成两组,一组学习,一组出结果
random.shuffle(datas)  # 打乱列表顺序,便于切割,不产生特殊结果
n = len(datas) // 3
test_set = datas[0: n]  # 测试集
train_set = datas[n:]  # 训练集


# KNN开始
# 计算距离
def distance(d1, d2):
    sums = 0
    for key in ("radius", "texture", "perimeter", "area", "smoothness", "compactness", "symmetry", "fractal_dimension"):
        sums += (float(d1[key]) - float(d2[key])) ** 2
    return sums ** 0.5


K = 5


def knn(data):
    # 1、距离
    res = [
        {"result": train["diagnosis_result"], "distance": distance(data, train)}  # 返回结果与调用distance方法来你计算data和train之间的距离
        for train in train_set  # 遍历训练集
    ]

    # print(res)

    # 2、排序--升序
    res = sorted(res, key=lambda item: item["distance"])
    # print(res)
    # 3、提取前K个
    res1 = res[0:K]
    # print(res1)
    # 4、加权平均
    result = {"B": 0, "M": 0}  # 最终的返回结果

    # 总距离
    sum = 0
    for r in res1:
        sum += r["distance"]

    for r in res1:
        result[r["result"]] += 1 - r["distance"]/sum

    if result["B"] > result["M"]:
        return"B"
    else :
        return"M"

# 测试阶段
correct = 0
for test in test_set:
    result = test["diagnosis_result"]
    result1 = knn(test)

    if result == result1:
        correct += 1

print("准确率为:{:.2f}%".format(100 * correct / len(test_set)))
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值