0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

机器学习理论:k近邻算法

新机器视觉 来源:古月居 2023-06-06 11:15 次阅读

来源:古月居


前言

KNN(k-Nearest Neighbors)思想简单,应用的数学知识几乎为0,所以作为机器学习的入门非常实用、可以解释机器学习算法使用过程中的很多细节问题。能够更加完整地刻画机器学习应用的流程。

首先大致介绍一下KNN的思想,假设我们现在有两类数据集,一类是红色的点表示,另一类用蓝色的点表示,这两类点就作为我们的训练数据集,当有一个新的数据绿色的点,那么我们该怎么给这个绿色的点进行分类呢?

一般情况下,我们需要先指定一个k,当一个新的数据集来临时,我们首先计算这个新的数据跟训练集中的每一个数据的距离,一般使用欧氏距离。

然后从中选出距离最近的k个点,这个k一般选取为奇数,方便后面投票决策。在k个点中根据最多的确定新的数据属于哪一类。

d9f79e6a-0413-11ee-90ce-dac502259ad0.png

KNN基础

1.先创建好数据集x_train, y_train,和一个新的数据x_new, 并使用matplot将其可视化出来。

import numpy as np
import matplotlib.pyplot as plt


raw_data_x = [[3.3935, 2.3313],
       [3.1101, 1.7815],
       [1.3438, 3.3684],
       [3.5823, 4.6792],
       [2.2804, 2.8670],
       [7.4234, 4.6965],
       [5.7451, 3.5340],
       [9.1722, 2.5111],
       [7.7928, 3.4241],
       [7.9398, 0.7916]]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
x_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)


x_new = np.array([8.0936, 3.3657])


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')
plt.show()

1.knn过程

2.计算距离

from math import sqrt
distance = []
for x in x_train:
  d = sqrt(np.sum((x_new - x) ** 2))
  distance.append(d)


# 其实上面这些代码用一行就可以搞定
# distances = [sqrt(np.sum((x_new - x) ** 2)) for x in x_train]

输出结果:

[10.888422144185997,
 11.825242797930196,
 15.18734646375067,
 11.660703691887552,
 12.89974598548359,
 12.707715895864213,
 9.398411207752083,
 15.62480440229573,
 12.345673749536719,
 14.394770082568183]

将距离进行排序,返回的是排序之后的索引位置

nearsest = np.argsort(distances)

输出结果:array([6, 0, 3, 1, 8, 5, 4, 9, 2, 7], dtype=int64)

取k个点,假设k=5

k = 5
topk_y = [y_train[i] for i in nearest[:k]]
topk_y

输出结果:[1, 0, 0, 0, 1]

根据输出结果我们可以发现,新来的数据距离最近的5个点,有三个点属于第一类,有两个点属于第二类,根据少数服从多数原则,新来的数据就属于第一类!

投票

from collections import Counter
Counter(topk_y)

输出结果:Counter({1: 2, 0: 3})

votes = Counter(topk_y)
votes.most_common(1)
y_new = votes.most_common(1)[0][0]

输出结果:0

这样,我们就完成了一个基本的knn!

自己写一个knn函数

knn是一个不需要训练过程的机器学习算法。其数据集可以近似看成一个模型。

import numpy as np
from math import sqrt
from collections import Counter


def kNN_classifier(k, x_train, y_train, x_new):


  assert 1 <= k <= x_train.shape[0], "k must be valid"
    assert x_train.shape[0] == y_train.shape[0], "the size of x_train must be equal to the size of y_train"
    assert x_train.shape[1] == x_new.shape[0], "the feature number of x_new must be equal to x_train"


    distances = [sqrt(np.sum((x_new - x) ** 2)) for x in x_train]
    nearest = np.argsort(distances)


    topk_y = [y_train[i] for i in nearest[:k]]
    votes = Counter(topk_y)


    return votes.most_common(1)[0][0]

测试一下:

raw_data_x = [[3.3935, 2.3313],
       [3.1101, 1.7815],
       [1.3438, 3.3684],
       [3.5823, 4.6792],
       [2.2804, 2.8670],
       [7.4234, 4.6965],
       [5.7451, 3.5340],
       [9.1722, 2.5111],
       [7.7928, 3.4241],
       [7.9398, 0.7916]]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
x_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)


x_new = np.array([8.0936, 3.3657])


y_new = kNN_classifier(5, x_train, y_train, x_new)
print(y_new)

使用sklearn中的KNN

from sklearn.neighbors import KNeighborsClassifier
import numpy as np


raw_data_x = [[3.3935, 2.3313],
       [3.1101, 1.7815],
       [1.3438, 3.3684],
       [3.5823, 4.6792],
       [2.2804, 2.8670],
       [7.4234, 4.6965],
       [5.7451, 3.5340],
       [9.1722, 2.5111],
       [7.7928, 3.4241],
       [7.9398, 0.7916]]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
x_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)


x_new = np.array([8.0936, 3.3657])


knn_classifier = KNeighborsClassifier(n_neighbors=5)
knn_classifier.fit(x_train, y_train)


y_new = knn_classifier.predict(x_new.reshape(1, -1))
print(y_new[0])

自己写一个面向对象的KNN

import numpy as np
from math import sqrt
from collections import Counter


class KNNClassifier():


  def __init__(self, k):
    assert 1 <= k, "k must be valid"
        self.k = k
        self._x_train = None
        self._y_train = None


    def fit(self, x_train, y_train):
        assert x_train.shape[0] == y_train.shape[0],  
        "the size of x_train must be equal to the size of y_train"
        assert self.k <= x_train.shape[0],  
         "the size of x_train must be at least k"


        self._x_train = x_train
        self._y_train = y_train
        return self


    def predict(self, x_new):
        x_new = x_new.reshape(1, -1)
        assert self._x_train is not None and self._y_train is not None, 
        "must fit before predict"
        assert x_new.shape[1] == self._x_train.shape[1], 
        "the feature number of x must be equal to x_train"


        y_new = [self._predict(x) for x in x_new]
        return np.array(y_new)


    def _predict(self, x):
        assert x.shape[0] == self._x_train.shape[1], 
        "the feature number of x must be equal to x_train"


        distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in self._x_train]
        nearest = np.argsort(distances)


        topk_y = [self._y_train[i] for i in nearest[:self.k]]
        votes = Counter(topk_y)


        return votes.most_common(1)[0][0]


    def __repr__(self):
        return "KNN(k=%d)" % self.k

测试一下:

raw_data_x = [[3.3935, 2.3313],
       [3.1101, 1.7815],
       [1.3438, 3.3684],
       [3.5823, 4.6792],
       [2.2804, 2.8670],
       [7.4234, 4.6965],
       [5.7451, 3.5340],
       [9.1722, 2.5111],
       [7.7928, 3.4241],
       [7.9398, 0.7916]]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
x_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)


x_new = np.array([8.0936, 3.3657])


knn_clf = KNNClassifier(6)
knn_clf.fit(x_train, y_train)
y_new = knn_clf.predict(x_new)
print(y_new[0])

分割数据集

import numpy as np
from sklearn import datasets




def train_test_split(x, y, test_ratio=0.2, seed=None):


  assert x.shape[0] == y.shape[0], "the size of x must be equal to the size of y"
  assert 0.0 <= test_ratio <= 1.0, "test_ratio must be valid"


    if seed:
        np.random.seed(seed)


    shuffle_idx = np.random.permutation(len(x))


    test_size = int(len(x) * test_ratio)
    test_idx = shuffle_idx[:test_size]
    train_idx = shuffle_idx[test_size:]


    x_train = x[train_idx]
    y_train = y[train_idx]


    x_test = x[test_idx]
    y_test = y[test_idx]


    return x_train, y_train, x_test, y_test

sklearn中鸢尾花数据测试KNN

import numpy as np
from sklearn import datasets
from knn_clf import KNNClassifier


iris = datasets.load_iris()
x = iris.data
y = iris.target


x_train, y_train, x_test, y_test = train_test_split(x, y)
my_knn_clf = KNNClassifier(k=3)
my_knn_clf.fit(x_train, y_train)


y_predict = my_knn_clf.predict(x_test)
print(sum(y_predict == y_test))
print(sum(y_predict == y_test) / len(y_test))
# 也可以使用sklearn中自带的数据集拆分方法
from sklearn.model_selection import train_test_split
import numpy as np
from sklearn import datasets
from knn_clf import KNNClassifier


iris = datasets.load_iris()
x = iris.data
y = iris.target
x_train, y_train, x_test, y_test = train_test_split(x, y, 
                          test_size=0.2, random_state=666)
my_knn_clf = KNNClassifier(k=3)
my_knn_clf.fit(x_train, y_train)
y_predict = my_knn_clf.predict(x_test)
print(sum(y_predict == y_test))
print(sum(y_predict == y_test) / len(y_test))

sklearn中手写数字数据集测试KNN

首先,先来了解一下手写数字数据集。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets


digits = datasets.load_digits()
digits.keys()
print(digits.DESCR)
y.shape
digits.target_names
y[:100]
x[:10]
some_digit = x[666]
y[666]
some_digit_image = some_digit.reshape(8, 8)
plt.imshow(some_digit_image, cmap=plt.cm.binary)
plt.show()

接下来,就开始动手试试。

from sklearn import datasets
from shuffle_dataset import train_test_split
from knn_clf import KNNClassifier


digits = datasets.load_digits()
x = digits.data
y = digits.target


x_train, y_train, x_test, y_test = train_test_split(x, y, test_ratio=0.2)
my_knn_clf = KNNClassifier(k=3)
my_knn_clf.fit(x_train, y_train)
y_predict = my_knn_clf.predict(x_test)


print(sum(y_predict == y_test) / len(y_test))

把求acc封装成一个函数,方便调用。

def accuracy_score(y_true, y_predict):
  assert y_true.shape[0] == y_predict.shape[0],  
  "the size of y_true must be equal to the size of y_predict"


  return sum(y_true == y_predict) / len(y_true)

接下来把它封装到KNNClassifier的类中。

import numpy as np
from math import sqrt
from collections import Counter
from metrics import accuracy_score


class KNNClassifier():


  def __init__(self, k):
    assert 1 <= k, "k must be valid"
        self.k = k
        self._x_train = None
        self._y_train = None


    def fit(self, x_train, y_train):
        assert x_train.shape[0] == y_train.shape[0], 
        "the size of x_train must be equal to the size of y_train"
        assert self.k <= x_train.shape[0], 
        "the size of x_train must be at least k"


        self._x_train = x_train
        self._y_train = y_train
        return self


    def predict(self, x_new):
        # x_new = x_new.reshape(1, -1)
        assert self._x_train is not None and self._y_train is not None, 
        "must fit before predict"
        assert x_new.shape[1] == self._x_train.shape[1], 
        "the feature number of x must be equal to x_train"


        y_new = [self._predict(x) for x in x_new]
        return np.array(y_new)


    def _predict(self, x):
        assert x.shape[0] == self._x_train.shape[1], 
        "the feature number of x must be equal to x_train"


        distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in self._x_train]
        nearest = np.argsort(distances)


        topk_y = [self._y_train[i] for i in nearest[:self.k]]
        votes = Counter(topk_y)


        return votes.most_common(1)[0][0]


    def score(self, x_test, y_test):
        y_predict = self.predict(x_test)
        return accuracy_score(y_test, y_predict)


    def __repr__(self):
        return "KNN(k=%d)" % self.k

其实,在sklearn中这些都已经封装好了。

from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier


digits = datasets.load_digits()
x = digits.data
y = digits.target


x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
knn_classifier = KNeighborsClassifier(n_neighbors=3)
knn_classifier.fit(x_train, y_train)
knn_classifier.score(x_test, y_test)

超参数

k

在knn中的超参数k何时最优?

from sklearn.metrics import accuracy_score 
from sklearn.model_selection import train_test_split 
from sklearn.neighbors import KNeighborsClassifier 


digits = datasets.load_digits() 
x = digits.data 
y = digits.target 
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) 


best_score = 0.0 
best_k = -1 
for k in range(1, 11): 
  knn_clf = KNeighborsClassifier(n_neighbors=k) 
  knn_clf.fit(x_train, y_train) 
  score = knn_clf.score(x_test, y_test) 
  if score > best_score: 
    best_k = k 
    best_score = score 
print("best k=", best_k) print("best score=", best_score)

投票方式

da1d9f0c-0413-11ee-90ce-dac502259ad0.jpg

上面这张图,绿色的球最近的三颗球分别是红色的1号,紫色的3号和蓝色的4号。如果只考虑绿色的k个近邻中多数服从少数,目前来说就是平票。

即使不是平票,红色也是距离绿色最近。此时我们就可以考虑给他们加个权重。一般使用距离的倒数作为权重。假设距离分别为1、 3、 4

红球:1 紫+蓝:1/3 + 1/4 = 7/12

这两者加起来都没有红色的权重大,因此最终将这颗绿球归为红色类别。这样能有效解决平票问题。 因此,这也算knn的一个超参数。

其实这个在sklearn封装的knn中已经考虑到了这个问题。在KNeighborsClassifier(n_neighbors=k,weights=?)

还有一个参数weights,一般有两种:uniform、distance。

from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier


digits = datasets.load_digits()
x = digits.data
y = digits.target


x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)


best_method = ""
best_score = 0.0
best_k = -1
for method in["uniform", "distance"]: 
  for k in range(1, 11):
    knn_clf = KNeighborsClassifier(n_neighbors=k, weights=method)
    knn_clf.fit(x_train, y_train)
    score = knn_clf.score(x_test, y_test)
    if score > best_score:
      best_method = method
      best_k = k
      best_score = score
print("best_method=", best_method)
print("best k=", best_k)
print("best score=", best_score)

p

如果使用距离,那么有很多种距离可以使用,欧氏距离、曼哈顿距离、明可夫斯基距离。

from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier


digits = datasets.load_digits()
x = digits.data
y = digits.target


x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)


best_p = -1
best_score = 0.0
best_k = -1
for p in range(1, 6):
  for k in range(1, 11):
    knn_clf = KNeighborsClassifier(n_neighbors=k, weights="distance", p=p)
    knn_clf.fit(x_train, y_train)
    score = knn_clf.score(x_test, y_test)
    if score > best_score:
      best_p = p
      best_k = k
      best_score = score
print("best_p=", best_p)
print("best k=", best_k)
print("best score=", best_score)

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4456

    浏览量

    90759
  • 代码
    +关注

    关注

    30

    文章

    4556

    浏览量

    66784
  • 机器学习
    +关注

    关注

    66

    文章

    8126

    浏览量

    130571
  • 数据集
    +关注

    关注

    4

    文章

    1179

    浏览量

    24356
收藏 人收藏

    评论

    相关推荐

    【下载】《机器学习》+《机器学习实战》

    、谋发展的决定性手段,这使得这一过去为分析师和数学家所专属的研究领域越来越为人们所瞩目。本书第一部分主要介绍机器学习基础,以及如何利用算法进行分类,并逐步介绍了多种经典的监督学习
    发表于 06-01 15:49

    Python实现k-近邻算法

    k-近邻算法简述k-近邻算法(kNN)采用测量不同特征值之间的距离方法进行分类。工作原理:首先存
    发表于 10-10 10:32

    基于Weka进行K-近邻算法K-均值算法

    使用Weka进行K-近邻算法K-均值算法的使用
    发表于 05-24 12:02

    机器学习的分类器

    各种机器学习的应用场景分别是什么?例如,k近邻,贝叶斯,决策树,svm,逻辑斯蒂回归和最大熵模型
    发表于 09-10 10:53

    斯坦福cs231n编程作业之k近邻算法

    深度学习斯坦福cs231n编程作业#1 --- k近邻算法(k-NN)
    发表于 05-07 12:03

    机器学习k-近邻算法(k-NN)

    机器学习机器学习100天(5) --- k-近邻算法(k
    发表于 05-15 15:06

    Python实现k-近邻算法

    k-近邻算法简述k-近邻算法(kNN)采用测量不同特征值之间的距离方法进行分类。工作原理:首先存
    发表于 01-04 14:03

    基于机器学习理论之图像辨识技术应用 – 传统水表附加远程抄表功能

    。 下图为智能数字辨识水表的架构示意图,新唐科技除了提供M48xxGCAE系列开发平台外,还提供了基于机器学习理论的数字辨识技术范例代码,可降低开发难度与节省客户大量的开发时间。 若您想对新唐M480
    发表于 03-01 14:21

    基于建构主义学习理论的藏文音素拼读法MCAI设计

    建构主义是符合人类认知规律的一种学习理论,而MCAI是广泛使用且行之有效的教学辅助工具。文章介绍基于建构主义学习理论的藏文音素拼读法多媒体教学软件的设计。
    发表于 03-01 15:08 13次下载

    机器学习理论基础介绍

    成为一名合格的开发工程师不是一件简单的事情,需要掌握从开发到调试到优化等一系列能力,这些能力中的每一项掌握起来都需要足够的努力和经验。而要成为一名合格的机器学习算法工程师(以下简称算法
    发表于 12-12 11:27 3643次阅读

    面向认知的多源数据学习理论算法研究进展

    多源数据学习在大数据时代具有极其重要的意义,目前,多源数据学习算法研究远远超前于多源数据学习理论研究,经典的机器
    发表于 12-26 16:10 0次下载

    人工智能机器学习之K近邻算法(KNN)

    K近邻KNN(k-Nearest Neighbor)算法,也叫K最近邻算法,1968年由 Cover 和 Hart 提出,是机器
    发表于 05-29 06:53 2456次阅读

    详解机器学习分类算法KNN

    本文主要介绍一个被广泛使用的机器学习分类算法,K-nearest neighbors(KNN),中文叫K近邻算法
    的头像 发表于 10-31 17:18 5721次阅读

    基于机器学习的效用和理论理解

    机器学习领域近年的发展非常迅速,然而我们对机器学习理论的理解还很有限,有些模型的实验效果甚至超出了我们对基础理论的理解。
    的头像 发表于 03-24 13:50 2130次阅读

    基于机器学习理论之图像辨识技术应用-传统水表附加远程抄表功能

    基于机器学习理论之图像辨识技术应用-传统水表附加远程抄表功能
    的头像 发表于 08-10 11:19 328次阅读
    基于<b class='flag-5'>机器</b><b class='flag-5'>学习理论</b>之图像辨识技术应用-传统水表附加远程抄表功能