本课程是中国大学慕课《机器学习》的“KNN”章节的课后代码。

课程地址:

https://www.icourse163.org/course/WZU-1464096179

课程完整代码:

https://github.com/fengdu78/WZU-machine-learning-course

代码修改并注释:黄海广,haiguang2000@wzu.edu.cn

1.近邻法是基本且简单的分类与回归方法。近邻法的基本做法是:对给定的训练实例点和输入实例点,首先确定输入实例点的个最近邻训练实例点,然后利用这个训练实例点的类的多数来预测输入实例点的类。

2.近邻模型对应于基于训练数据集对特征空间的一个划分。近邻法中,当训练集、距离度量、值及分类决策规则确定后,其结果唯一确定。

3.近邻法三要素:距离度量、值的选择和分类决策规则。常用的距离度量是欧氏距离及更一般的pL距离。值小时,近邻模型更复杂;值大时,近邻模型更简单。值的选择反映了对近似误差与估计误差之间的权衡,通常由交叉验证选择最优的。

常用的分类决策规则是多数表决,对应于经验风险最小化。

4.近邻法的实现需要考虑如何快速搜索k个最近邻点。kd树是一种便于对k维空间中的数据进行快速检索的数据结构。kd树是二叉树,表示对维空间的一个划分,其每个结点对应于维空间划分中的一个超矩形区域。利用kd树可以省去对大部分数据点的搜索, 从而减少搜索的计算量。

1.距离度量

在机器学习算法中,我们经常需要计算样本之间的相似度,通常的做法是计算样本之间的距离。

设和为两个向量,求它们之间的距离。

这里用Numpy实现,设和为ndarray <numpy.ndarray>,它们的shape都是(N,)

为所求的距离,是个浮点数(float)。

import numpy as np  #注意:运行代码时候需要导入NumPy库。

欧氏距离(Euclidean distance)

欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。

距离公式:

代码实现:

def euclidean(x, y):return np.sqrt(np.sum((x - y)**2))

曼哈顿距离(Manhattan distance)

想象你在城市道路里,要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。实际驾驶距离就是这个“曼哈顿距离”。而这也是曼哈顿距离名称的来源,曼哈顿距离也称为城市街区距离(City Block distance)。

距离公式:

代码实现:

def manhattan(x, y):return np.sum(np.abs(x - y))

切比雪夫距离(Chebyshev distance)

在数学中,切比雪夫距离(Chebyshev distance)或是L∞度量,是向量空间中的一种度量,二个点之间的距离定义是其各坐标数值差绝对值的最大值。以数学的观点来看,切比雪夫距离是由一致范数(uniform norm)(或称为上确界范数)所衍生的度量,也是超凸度量(injective metric space)的一种。

距离公式:

若将国际象棋棋盘放在二维直角座标系中,格子的边长定义为1,座标的轴及轴和棋盘方格平行,原点恰落在某一格的中心点,则王从一个位置走到其他位置需要的步数恰为二个位置的切比雪夫距离,因此切比雪夫距离也称为棋盘距离。例如位置F6和位置E2的切比雪夫距离为4。任何一个不在棋盘边缘的位置,和周围八个位置的切比雪夫距离都是1。

代码实现:

def chebyshev(x, y):return np.max(np.abs(x - y))

闵可夫斯基距离(Minkowski distance)

闵氏空间指狭义相对论中由一个时间维和三个空间维组成的时空,为俄裔德国数学家闵可夫斯基(H.Minkowski,1864-1909)最先表述。他的平坦空间(即假设没有重力,曲率为零的空间)的概念以及表示为特殊距离量的几何学是与狭义相对论的要求相一致的。闵可夫斯基空间不同于牛顿力学的平坦空间。取1或2时的闵氏距离是最为常用的,即为欧氏距离,而时则为曼哈顿距离。

当取无穷时的极限情况下,可以得到切比雪夫距离。

距离公式:

代码实现:

def minkowski(x, y, p):return np.sum(np.abs(x - y)**p)**(1 / p)

汉明距离(Hamming distance)

汉明距离是使用在数据传输差错控制编码里面的,汉明距离是一个概念,它表示两个(相同长度)字对应位不同的数量,我们以表示两个字,之间的汉明距离。对两个字符串进行异或运算,并统计结果为1的个数,那么这个数就是汉明距离。

距离公式:

代码实现:

def hamming(x, y):return np.sum(x != y) / len(x)

余弦相似度(Cosine Similarity)

余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1,而其他任何角度的余弦值都不大于1;并且其最小值是-1。从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。两个向量有相同的指向时,余弦相似度的值为1;两个向量夹角为90°时,余弦相似度的值为0;两个向量指向完全相反的方向时,余弦相似度的值为-1。这结果是与向量的长度无关的,仅仅与向量的指向方向相关。余弦相似度通常用于正空间,因此给出的值为0到1之间。

二维空间为例,上图的和是两个向量,我们要计算它们的夹角θ。余弦定理告诉我们,可以用下面的公式求得:

假定向量是

,向量是,两个向量间的余弦值可以通过使用欧几里得点积公式求出:

如果向量和不是二维而是维,上述余弦的计算法仍然正确。假定和是两个维向量,是

,是,则与的夹角余弦等于:

代码实现:

from math import *def square_rooted(x):return round(sqrt(sum([a*a for a in x])),3)
def cosine_similarity(x, y):numerator = sum(a * b for a, b in zip(x, y))denominator = square_rooted(x) * square_rooted(y)return round(numerator / float(denominator), 3)
print(cosine_similarity([3, 45, 7, 2], [2, 54, 13, 15]))
0.972

KNN算法

1.近邻法是基本且简单的分类与回归方法。近邻法的基本做法是:对给定的训练实例点和输入实例点,首先确定输入实例点的个最近邻训练实例点,然后利用这个训练实例点的类的多数来预测输入实例点的类。

2.近邻模型对应于基于训练数据集对特征空间的一个划分。近邻法中,当训练集、距离度量、值及分类决策规则确定后,其结果唯一确定。

3.近邻法三要素:距离度量、值的选择和分类决策规则。常用的距离度量是欧氏距离。值小时,近邻模型更复杂;值大时,近邻模型更简单。值的选择反映了对近似误差与估计误差之间的权衡,通常由交叉验证选择最优的。

常用的分类决策规则是多数表决,对应于经验风险最小化。

4.近邻法的实现需要考虑如何快速搜索k个最近邻点。kd树是一种便于对k维空间中的数据进行快速检索的数据结构。kd树是二叉树,表示对维空间的一个划分,其每个结点对应于维空间划分中的一个超矩形区域。利用kd树可以省去对大部分数据点的搜索, 从而减少搜索的计算量。

python实现,遍历所有数据点,找出个距离最近的点的分类情况,少数服从多数

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from collections import Counter

导入鸢尾花数据集

iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
df.head()
sepal length sepal width petal length petal width label
0 5.1 3.5 1.4 0.2 0
1 4.9 3.0 1.4 0.2 0
2 4.7 3.2 1.3 0.2 0
3 4.6 3.1 1.5 0.2 0
4 5.0 3.6 1.4 0.2 0

选择长和宽的数据进行可视化

plt.figure(figsize=(12, 8))
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.xlabel('sepal length', fontsize=18)
plt.ylabel('sepal width', fontsize=18)
plt.legend()
plt.show()

Numpy实现

class KNN:def __init__(self, X_train, y_train, n_neighbors=3, p=2):"""parameter: n_neighbors 临近点个数parameter: p 距离度量"""self.n = n_neighborsself.p = pself.X_train = X_trainself.y_train = y_traindef predict(self, X):# 取出n个点knn_list = []for i in range(self.n):dist = np.linalg.norm(X - self.X_train[i], ord=self.p)knn_list.append((dist, self.y_train[i]))for i in range(self.n, len(self.X_train)):max_index = knn_list.index(max(knn_list, key=lambda x: x[0]))dist = np.linalg.norm(X - self.X_train[i], ord=self.p)if knn_list[max_index][0] > dist:knn_list[max_index] = (dist, self.y_train[i])# 统计knn = [k[-1] for k in knn_list]count_pairs = Counter(knn)#         max_count = sorted(count_pairs, key=lambda x: x)[-1]max_count = sorted(count_pairs.items(), key=lambda x: x[1])[-1][0]return max_countdef score(self, X_test, y_test):right_count = 0n = 10for X, y in zip(X_test, y_test):label = self.predict(X)if label == y:right_count += 1return right_count / len(X_test)
data = np.array(df.iloc[:150, [0, 1, -1]])
X, y = data[:,:-1], data[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
clf = KNN(X_train, y_train)
clf.score(X_test, y_test)
0.7777777777777778
test_point = [6.0, 3.0]
print('Test Point: {}'.format(clf.predict(test_point)))
Test Point: 2.0

Scikit-learn实例

sklearn.neighbors.KNeighborsClassifier

  • n_neighbors: 临近点个数,即k的个数,默认是5

  • p: 距离度量,默认

  • algorithm: 近邻算法,可选{'auto', 'ball_tree', 'kd_tree', 'brute'}

  • weights: 确定近邻的权重

  • n_neighbors :int,optional(default = 5) 默认情况下kneighbors查询使用的邻居数。就是k-NN的k的值,选取最近的k个点。

  • weights :str或callable,可选(默认=‘uniform’) 默认是uniform,参数可以是uniform、distance,也可以是用户自己定义的函数。uniform是均等的权重,就说所有的邻近点的权重都是相等的。distance是不均等的权重,距离近的点比距离远的点的影响大。用户自定义的函数,接收距离的数组,返回一组维数相同的权重。

  • algorithm :{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’},可选 快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,brute是蛮力搜索,也就是线性扫描,当训练集很大时,计算非常耗时。kd_tree,构造kd树存储数据以便对其进行快速检索的树形数据结构,kd树也就是数据结构中的二叉树。以中值切分构造的树,每个结点是一个超矩形,在维数小于20时效率高。ball tree是为了克服kd树高纬失效而发明的,其构造过程是以质心C和半径r分割样本空间,每个节点是一个超球体。

  • leaf_size :int,optional(默认值= 30) 默认是30,这个是构造的kd树和ball树的大小。这个值的设置会影响树构建的速度和搜索速度,同样也影响着存储树所需的内存大小。需要根据问题的性质选择最优的大小。

  • p :整数,可选(默认= 2) 距离度量公式。在上小结,我们使用欧氏距离公式进行距离度量。除此之外,还有其他的度量方法,例如曼哈顿距离。这个参数默认为2,也就是默认使用欧式距离公式进行距离度量。也可以设置为1,使用曼哈顿距离公式进行距离度量。

  • metric :字符串或可调用,默认为’minkowski’ 用于距离度量,默认度量是minkowski,也就是p=2的欧氏距离(欧几里德度量)。

  • metric_params :dict,optional(默认=None) 距离公式的其他关键参数,这个可以不管,使用默认的None即可。

  • n_jobs :int或None,可选(默认=None) 并行处理设置。默认为1,临近点搜索并行工作数。如果为-1,那么CPU的所有cores都用于并行工作。

from sklearn.neighbors import KNeighborsClassifier

不同k(n_neighbors)值下的结果:

clf_sk = KNeighborsClassifier(n_neighbors=3)
clf_sk.fit(X_train, y_train)
KNeighborsClassifier(n_neighbors=3)
clf_sk.score(X_test, y_test)
0.7777777777777778
clf_sk = KNeighborsClassifier(n_neighbors=4)
clf_sk.fit(X_train, y_train)
clf_sk.score(X_test, y_test)
0.8
clf_sk = KNeighborsClassifier(n_neighbors=5)
clf_sk.fit(X_train, y_train)
clf_sk.score(X_test, y_test)
0.7555555555555555

自动调参吧,试试循环,找到最优的k值

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 = kbest_score = scoreprint("best_k = " + str(best_k))
print("best_score = " + str(best_score))
best_k = 2
best_score = 0.8

KD树的划分和搜索

KD树

KD树(K-Dimension Tree),,也可称之为维树,可以用更高的效率来对空间进行划分,并且其结构非常适合寻找最近邻居和碰撞检测。KD树是一种便于对维空间中的数据进行快速检索的数据结构。KD树是二叉树,表示对维空间的一个划分,其每个结点对应于维空间划分中的一个超矩形区域。利用KD树可以省去对大部分数据点的搜索,从而减少搜索的计算量。

KD树是二叉树,表示对

【机器学习】KNN算法代码练习相关推荐

  1. 机器学习knn算法学习笔记使用sklearn库 ,莺尾花实例

    ** 机器学习knn算法学习笔记使用sklearn库 ,莺尾花实例. 具体knn算法是怎样的我这里就不再详细论述.在这里我注意总结我使用knn算法进行一个分类的分析 ** 分析过程 1.前期准备 引入 ...

  2. 课程设计(毕业设计)—基于机器学习KNN算法手写数字识别系统—计算机专业课程设计(毕业设计)

    机器学习KNN算法手写数字识别系统 下载本文手写数字识别系统完整的代码和课设报告的链接(或者可以联系博主koukou(壹壹23七2五六98),获取源码和报告):https://download.csd ...

  3. 机器学习 —— KNN算法简单入门

    机器学习 -- KNN算法简单入门 第1关:手动实现简单kNN算法 1 KNN算法简介 1.1 kNN 算法的算法流程 1.2 kNN 算法的优缺点 1.3 编程要求+参数解释 2. 代码实现 3. ...

  4. 机器学习——KNN算法

    机器学习--KNN算法 文章目录 机器学习--KNN算法 前言 一.KNN原理基础 二.sklearn的基本建模流程 三.KNN算法调优:选取最优的K值 四.KNN中距离的相关讨论 1. KNN使用的 ...

  5. 机器学习KNN算法实践:预测城市空气质量

    出品:Python数据之道 作者:叶庭云 整理:Lemon 机器学习KNN算法实践 预测城市空气质量 「Python数据之道」导读: 之前在公众号上分享过 "图解KNN算法" 的内 ...

  6. 开根号的笔算算法图解_机器学习KNN算法之手写数字识别

    1.算法简介 手写数字识别是KNN算法一个特别经典的实例,其数据源获取方式有两种,一种是来自MNIST数据集,另一种是从UCI欧文大学机器学习存储库中下载,本文基于后者讲解该例. 基本思想就是利用KN ...

  7. 经典实战案例:用机器学习 KNN 算法实现手写数字识别 | 原力计划

    作者 | 奶糖猫 来源 | CSDN 博客,责编 | 夕颜 头图 | CSDN 下载自视觉中国 出品 | CSDN(ID:CSDNnews) 算法简介 手写数字识别是KNN算法一个特别经典的实例,其数 ...

  8. python手写字母识别_机器学习--kNN算法识别手写字母

    本文主要是用kNN算法对字母图片进行特征提取,分类识别.内容如下: kNN算法及相关Python模块介绍 对字母图片进行特征提取 kNN算法实现 kNN算法分析 一.kNN算法介绍 K近邻(kNN,k ...

  9. 机器学习——K-NN算法

    目录 一.  KNN的原理 二.  K-NN算法的注意事项 1. 如何选取K值 2. K-NN算法的优点 3. K-NN算法的缺点 三.  算法的Python实现 (1)用原理实现K-NN (2)调用 ...

最新文章

  1. 本周日,王海峰、黄铁军、朱军、李宏毅等大咖邀你加入这场AI开发者盛宴!...
  2. PHP输出中文乱码的解决方法
  3. QQ互联OAuth2.0 .NET SDK 发布以及网站QQ登陆示例代码
  4. php百合网,来百合网直播,做最真实的自己
  5. python argparse理解与实例
  6. 合并DateFrame之—— append()
  7. Codeforces Round #662 (Div. 2)
  8. pytorch 实现 LSTM AutoEncoder 与案例
  9. MySql update inner join!MySql跨表更新 多表update sql语句?如何将select出来的部分数据update到另一个表里面?...
  10. imsdroid启动Activity的方式很独特
  11. 缩短bch码能用matlab,BCH码编译码matlab仿真.doc
  12. Unity插件 - MeshEditor(九) 模型涡流扭曲特效(黑洞吸引特效)
  13. 【zblog】模板怎么安装?zblog主题安装教程
  14. 土木工程计算机设计考试科目一模拟试题,科目一电脑模拟考试,原来这么简单,看完这个科一不用愁!...
  15. php 表情,PHP处理emoji表情
  16. 网易云音乐的亏损,是社区经济的通病?
  17. 谈古论津丨天津杨柳青年画为何要用娃娃作主题?
  18. IEEE-754标准与浮点数运算
  19. 利用计算思维解决问题人和计算机都能完成,对计算思维能力养成与大学计算机基础课程改革的思考...
  20. Rasa课程、Rasa培训、Rasa面试、Rasa实战系列之Understanding Rasa Deployments Premade Rasa Containers

热门文章

  1. [CareerCup] 4.5 Validate Binary Search Tree 验证二叉搜索树
  2. 获取本地的json并展示
  3. Android 开发笔记___初级控件之实战__计算器
  4. Individual Project
  5. 【牢骚】360,你怎么对待别人,别人就怎么对待你。
  6. 验证视图状态MAC失败问题正确的解决办法
  7. python股票数据预处理_Python股票处理之六_数据预处理A
  8. 手机pdf文件转语音_职场小白不懂PDF文件转Word文档?试试微软的这款APP吧
  9. Stata 17 for Win 最新中文附详细安装教程
  10. android 得到毫秒时间戳,android – Location.getTime()总是返回没有毫秒的时间戳