机器学习算法之:KNN

KNN算法简介

首先介绍一下KNN算法的几个特点:

  • KNN,全称K-Nearest Neighbor,中文名为K近邻
  • 思想极度简单,最基础的分类算法,非常适合入门
  • 应用数学知识极少,近乎为零
  • 效果却很好
  • 可以解释机器学习算法使用过程中的很多细节问题,更完整的刻画机器学习应用的流程

KNN算法原理

下面我们开始用一个简单的例子来解释KNN的原理:

假设已有了一组关于肿瘤的样本数据,其中X轴为肿瘤大小,Y轴为发现肿瘤的时间,红色的点为良性肿瘤,蓝色的点为恶性肿瘤


假设现在新出现了一个已知大小和发现时间的肿瘤,如何判断该肿瘤属于良性还是恶性呢?


首先需要取一个k值,k值代表了新来的肿瘤需要比对k个样本数据,具体K值怎么取后续会有详细的介绍

这里先假设k=3,意味着新来的肿瘤需要去比对离新肿瘤最近的3个样本数据的距离


而后,这3个样本数据以它们自身的类别进行投票,比如上图中,这3个点的投票结果为蓝色:红色 = 3:0(概率为100%)。所以新来的肿瘤将被KNN算法判定为蓝色,也就是恶性肿瘤。

综上所述,KNN算法的性质就是,在已知数据样本的特征与分类的情况下,新的数据将会比对距离已知样本最近的k个数据,而后根据这k个数据各自分类数量的比例,即每个分类会计算出各自的概率,将新数据将判定给概率最大的那个类别。

关于k值与样本数据的距离

计算ab两点之间的距离的方式有几种,这里我们通常会采用欧拉距离,下图是欧拉距离在平面几何中的计算方式


在立体几何中,欧拉距离变得有些抽象了,由于多了第三个z轴,所以需要在加上z轴方向的值


在真实机器学习中,脱离了几何的概念会变得有些抽象,且样本的特征可能会更多,所以我们需要统计每个特征的距离,其中大X表示样本集,X右下角的数字角标表示是第几个特征值


简洁的表示为


算法实现

import numpy as np
import matplotlib.pyplot as plt

# 定义一组肿瘤的样本的特征
raw_data_X = [[3.39, 2.33],
              [3.11, 1.78],
              [1.34, 3.36],
              [3.58, 4.67],
              [2.28, 2.86],
              [7.42, 4.69],
              [5.75, 3.53],
              [9.17, 2.51],
              [7.79, 3.42],
              [7.93, 0.79]]

# 对应样本已知的类别,0为良性,1为恶性
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

# 用numpy封装为训练集
X_train = np.array(raw_data_X)
y_train = np.array(raw_data_y)

# 绘制已知肿瘤分类为0和1的散点图
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_new = np.array([8.09, 3.34])

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_new[0], x_new[1], color='b')  # 蓝色为新肿瘤
# 手写一遍kNN算法过程
from collections import Counter
from math import sqrt

# 定义一个空的数组,用于保存新数据与已知样本数据的欧氏距离
distances = []

# 这里可以回顾一下欧氏距离的数学公式
for x_train in X_train:
    d = sqrt(np.sum((x_train - x_new)**2))
    distances.append(d)

# 此时的distances中就已经包含了新肿瘤与每一个样本的距离,打印一下看看
distances
# 可以用更简介生成表达式的语法计算
distances = [sqrt(np.sum((x_train-x_new)**2)) for x_train in X_train]

# 再打印一下看看,一样的吧
distances
# 对距离排序看看
np.sort(distances)
# 但是现在我们需要的是:distance数组在排序后所对应排序前的index
np.argsort(distances)
# 我们将这个索引值保存为nearest变量
nearest = np.argsort(distances)

# 现在拍脑袋定义一个k值6,which means我们将比对距离新数据最近的6个样本,让这6个样本vote
k = 6

# 遍历nearest对象,将正确排序的索引引用到已知分类的结果集y,得到距离最近的6个y的结果
topk_y = [y_train[i] for i in nearest[:k]]

# 打印一下6个样本的投票结果,可以看到是分类1 VS 分类0是5:1
topk_y
# 调用一个计数函数,返回一个kv对象,会自动根据value将key从大到小排序,打印一下可以看到分类1有5票,分类0有1票
votes = Counter(topk_y)
votes
# 由于刚才的结果是个对象,我们用most_common函数转换成tuple
votes.most_common()
# 由于我们只关心计数最多的那个key值(即分类结果),所以我们只需要取第一个tuple的key值
predict_y = votes.most_common(1)[0][0]

# 打印一下,新数据属于分类1,也就是恶性肿瘤
predict_y

scikit-learn中的KNN算法

from sklearn.neighbors import KNeighborsClassifier

KNN_classifier = KNeighborsClassifier(n_neighbors=6)
KNN_classifier.fit(X_train, y_train)

# 直接predict会报一个错,原因是x_new是一个一维向量,而X_train是一个二维矩阵,我们需要将x_new也reshape成一个一行的二维矩阵
y_predict = KNN_classifier.predict(x_new) 

y_predict = KNN_classifier.predict(x_new.reshape(1, -1))

# 再打印一下,problem solved
y_predict
# 强迫症同学还是取一下具体的值吧,就是1了
y_predict[0]
/** 上述的predict会直接给出具体的分类值,但是我们也可以调用predict_proba看一下是0还是1的概率,可以看到0的概率是0.1666,1的概率是0.8333,也就是1:5啦**/
KNN_classifier.predict_proba(x_new.reshape(1, -1))[0]

小结

  • KNN似乎不用建模?
  • KNN算法是非常特殊的,可以认为是没有模型的算法
  • 但是为了和其他算法统一,可以换个角度理解,认为训练的样本集就是模型本身

TBC……

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,814评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,124评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,814评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,924评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,815评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,562评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,944评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,582评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,859评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,881评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,700评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,493评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,943评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,115评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,413评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,978评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,182评论 2 339

推荐阅读更多精彩内容