K近邻算法

前言

这是机器学习最简单的算法,当然并不是说简单就没人用。knn算法的优点就是简单而且便于实现,并且有一定好的效果。

算法原理

K近邻的算法思路很简单。

背景

假设 有两个类别散落在这个特征空间中。


image.png

现在有一个新的样本需要预测它属于哪个类别。


image.png

思路介绍

step1: 暴力的求出新样本与其余所有样本的“距离”。
step2: 找到距离它最近的k的点。(这就是k近邻的名称由来)
step3: 进行类别打分,新样本属于分数最高的哪个类别。


然后展开细节讲:

距离

欧式距离

欧式距离的计算就是每个维度的平方和开跟号也就是直线距离。这里用二维的比较好理解。就是其实x(p)是预测的样本,x(t)训练样本。


image.png

当然x,y只有两个特征,现实往往有很多个特征也就是说有很多个维度。


image.png

其中的下标标号就是对应的不同维度。

简写就是


image.png

曼哈顿距离

曼哈顿距离的由来是在城市中的行车距离。


image.png

在现实生活中两点之间并不是都是直线可达的,这样可以把区域分成单元的小块。就像开出租车一样。直线绿色的就是欧式距离,蓝色、红色、黄色都是曼哈顿距离。(图来自 维基百科)


image.png

明可夫斯基定理

仔细看曼哈顿距离和欧氏距离
曼哈顿距离


image.png

欧氏距离


image.png

貌似有个惊人的规律
image.png

这好像是找到了距离公式 的通式。这是新发现么?答案是否定的,有个叫明可夫斯基的人早就发现了这个。那么2以上都都叫明可夫斯基距离(名字起光了,断了后路啊。。。)

K

K值是KNN的一个超参数。(超参数:也就是模型运行前需要确定的参数,K就是KNN算法最为直观的一个超参数)。这个参数需要人为的去调,这也就是人工在其中起的最重要的作用(调参狗)。至于怎么调参?一般需要经验和专业的领域知识。当然也可以老中医式的调参。如果计算量比较小可以使用网格搜索的方法去调参。

分类决策

一般思路是这样的,就是把测试数据丢进去,计算与训练集所有点的距离,找到前K个点的类别。然后进行PK算出类别。


image.png

黑色点:测试样本。
紫色点:类别A。
蓝色点:类别B
如图所示,不管使用的什么距离计算方式,我们可以找到与黑色点与所有点的距离。那么我们就可以找到距离它最近的K个点。然后进行类别打分,明显蓝色的分数比较高。那么该点就属于蓝色点。

这样做是没有问题的。但是机器学习目前还是很依赖数据的而且不同的场景下的应用也是不一样的。
举个栗子


image.png

由图所示虽然蓝色类的得分高,但是黑色点距离紫色点的距离更近一点。或许它更有可能是紫色类。那么我们的距离或许需要一个权重(注意:或许。因为这个距离权重不一定有用,要去试)。这个距离权重一般采用距离的倒数作为权重。
重新计算得分表



那么这个类就属于紫色类了。

模型实现

这里自己造的数据,自己做的最简单的实现。只供理解参考。

import numpy as np
import matplotlib.pyplot as plt
import math
from collections import Counter
rad_1=np.random.randint(1,10,size=(5,2))
rad_1
array([[9, 3],
       [6, 6],
       [3, 6],
       [6, 7],
       [7, 1]])
rad_2=np.random.randint(11,20,size=(5,2))
rad_2
array([[13, 18],
       [15, 15],
       [14, 19],
       [13, 11],
       [11, 17]])
raw_data_X=np.vstack([rad_1,rad_2])
raw_data_X
array([[ 9,  3],
       [ 6,  6],
       [ 3,  6],
       [ 6,  7],
       [ 7,  1],
       [13, 18],
       [15, 15],
       [14, 19],
       [13, 11],
       [11, 17]])
raw_data_y=[0,0,0,0,0,1,1,1,1,1]
y_train=np.array(raw_data_y)
y_train
array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
plt.scatter(raw_data_X[y_train==0,0],raw_data_X[y_train==0,1],color='b')
plt.scatter(raw_data_X[y_train==1,1],raw_data_X[y_train==1,1],color='r',alpha=0.5)
plt.show()

!
output_6_0.png
x=np.array([13,14])
x
array([13, 14])
plt.scatter(raw_data_X[y_train==0,0],raw_data_X[y_train==0,1],color='b')
plt.scatter(raw_data_X[y_train==1,1],raw_data_X[y_train==1,1],color='r')
plt.scatter(x[0],x[1],color='g',alpha=0.5,marker='*')
plt.show()

!
output_8_0.png

KNN过程

X_train=raw_data_X
distance=[]
for x_train in X_train:
    d=np.sum((x-x_train)**2)**0.5
    distance.append(d)
distance
[11.704699910719626,
 10.63014581273465,
 12.806248474865697,
 9.8994949366116654,
 14.317821063276353,
 4.0,
 2.2360679774997898,
 5.0990195135927845,
 3.0,
 3.6055512754639891]

distance1=[math.sqrt(np.sum((x_train-x)**2)) for x_train in X_train]
distance1
[11.704699910719626,
 10.63014581273465,
 12.806248474865697,
 9.899494936611665,
 14.317821063276353,
 4.0,
 2.23606797749979,
 5.0990195135927845,
 3.0,
 3.605551275463989]
distance=[(np.sum((x_train-x)**2)**0.5)for x_train in X_train]
distance
[11.704699910719626,
 10.63014581273465,
 12.806248474865697,
 9.8994949366116654,
 14.317821063276353,
 4.0,
 2.2360679774997898,
 5.0990195135927845,
 3.0,
 3.6055512754639891]
nearest=np.argsort(distance)
nearest
array([6, 8, 9, 5, 7, 3, 1, 0, 2, 4])
k=6
topK_y=y_train[nearest[:6]]
topK_y
array([1, 1, 1, 1, 1, 0])
Votes=Counter(topK_y)
Votes.most_common(1)[0][0]
1
pwd
'/Users/zhangyan/Documents/SystemEnv/anaconda3/bin/boboML'
def knn(k,X_train,y_train,x):
    assert 1<=k<= X_train.shape[0], "k不能大于训练样本的个数"
    assert X_train.shape[0]==y_train.shape[0], "训练样本个数要等于标签数"
    assert X_train.shape[1]==x.shape[0],"测试数据特征个数要与训练样本相同"
    distance=[]
    distance=[(np.sum((x_train-x)**2)**0.5)for x_train in X_train]
    nearest = np.argsort(distance)
    topK_y = y_train[nearest[:6]]
    Votes = Counter(topK_y)
    return Votes.most_common(1)[0][0]

knn(6,X_train,y_train,x)
1
from KNN_function import knn_fun1
from mymodule import FirstML
FirstML.predict(1)
1
knn_fun1.knn(6,X_train,y_train,x)
1

scikit-learn的kNN

from sklearn.neighbors import KNeighborsClassifier
kNN_classifier=KNeighborsClassifier(n_neighbors=6)
kNN_classifier.fit(X_train,y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=6, p=2,
           weights='uniform')
kNN_classifier.predict(x.reshape(1,-1))
array([1])
class KNNClassifier:
    def __init__(self,k):
        assert k>0,"k不能小于0"
        self.k=k
    def fit(self,X_train,y_train):
        assert X_train.shape[0] == y_train.shape[0], "训练样本个数要等于标签数"

        self.X_train=X_train
        self.y_train=y_train
        
        return self
    def prdict(self,x_predict):
        assert self.X_train.shape[1] == x_predict.shape[1], "测试数据特征个数要与训练样本相同"
        return np.array([self._predict(x) for x in x_predict])
        
    
    def _predict(self,x):
        distance = [(np.sum((x_train - x) ** 2) ** 0.5) for x_train in X_train]
        nearest = np.argsort(distance)
        topK_y = y_train[nearest[:6]]
        Votes = Counter(topK_y)
        return Votes.most_common(1)[0][0]
    
cls=KNNClassifier(k=6)
cls.fit(X_train,y_train)
<__main__.KNNClassifier at 0x1094f3b00>
cls.prdict(x.reshape(1,-1))
array([1])
cls1=knn_fun1.KNNClassifier(6)
cls1.fit(X_train,y_train)
<KNN_function.knn_fun1.KNNClassifier at 0x1094f3320>
cls1.predict(x.reshape(1,-1))
array([1])
x=np.array([[1,4],[5,6],[12,12]])
x.shape[1]

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

推荐阅读更多精彩内容