KNN算法 0基础小白也能懂(附代码)

原文链接

1.K近邻是啥

1968年,Cover 和 Hart 提出了最初的近邻法,思路是——未知的豆离哪种豆最近,就认为未知豆和该豆是同一种类。

近邻算法的定义:为了判定未知样本的类别,以全部训练样本作为代表点计算未知样本与所有训练样本的距离,并以最近邻者的类别作为决策未知样本类别的唯一依据。

说人话就是,看这玩意离哪个东西距离最近,越近越像。

最近邻算法的缺陷是对噪声数据过于敏感。从图中可以得到,一个圈起来的蓝点和两个圈起来的红点到绿点的距离是相等的,根据最近邻算法,该点的形状无法判断。其实也就是东西太多太杂的话判断不清

为了解决这个问题,我们可以把位置样本周边的多个最近样本计算在内,扩大参与决策的样本量,以避免个别数据直接决定决策结果。也就是增大数据量减少误差。

引进K近邻算法——选择未知样本一定范围内确定个数的K个样本,该K个样本大多数属于某一类型,则未知样本判定为该类型。K近邻算法是最近邻算法的一个延伸。根据K近邻算法,离绿点最近的三个点中有两个是红点,一个是蓝点,红点的样本数量多于蓝点的样本数量,因此绿点的类别被判定为红点。

2.KNN算法步骤

一般来说,只选择样本数据集中前N个最相似的数据.K一般不大于20,最后,选择K个中出现次数最多的分类,作为新数据的分类。

那K值到底如何选择呢?

  1. 数据特性

    噪声与非相关特征:如果数据中存在较多噪声或非相关特征,较大的K值可以平滑分类结果,减小噪声的影响。然而,这也可能导致类别之间的界限变得模糊,特别是在数据分布复杂或类别间存在明显界限的情况下。

    特征选择与缩放:为减小噪声和非相关特征的影响,可以通过特征选择和特征缩放来优化输入数据。例如,利用进化算法或互信息进行特征选择,从而提高KNN算法的性能。

  2. 奇数K值

    避免平票:在二元分类问题中,选择奇数的K值有助于避免分类器投票时出现平票的情况,从而提高分类器的确定性。这一点在K值较小、数据分布相对均匀时尤为重要。

  3. 超参数优化

    启发式方法:K值的选择可以通过各种启发式技术来优化。交叉验证(Cross-validation)是一种常用的方法,它通过将数据集划分为训练集和验证集,尝试不同的K值,并选择在验证集上表现最佳的K值。

    自助法(Bootstrap):在二元分类问题中,自助法可以用于评估不同K值的性能,并帮助选择最佳的K值。自助法通过多次重复采样训练集,计算每次采样的分类准确率,从而估计K值的期望性能。(从原始数据集中随机有放回地抽样,生成多个新的子数据集。每个子数据集都与原始数据集大小相同,但是由于是有放回抽样,因此某些样本可能会在一个子数据集中出现多次,而另一些样本可能根本没有出现(OOB)。)

3.实战实现KNN算法

3.1 背景

假如一套房子打算出租,但不知道市场价格,可以根据房子的规格(面积、房间数量、厕所数量、容纳人数等),在已有数据集中查找相似(K近邻)规格的房子价格,看别人的相同或相似户型租了多少钱。

数据集在这,CardioGoodFitness 数据集 提取码:show

3.2数据分类

已知的数据集中,每个已出租住房都有房间数量、厕所数量、容纳人数等字段,并有对应出租价格。将预计出租房子数据与数据集中每条记录比较计算欧式距离(坐标系里的距离),取出距离最小的5条记录,将其价格取平均值,可以将其看做预计出租房子的市场平均价格。

import pandas as pd
import numpy as np
from scipy.spatial import distance#用于计算欧式距离
from sklearn.preprocessing import StandardScaler#用于对数据进行标准化操作
from sklearn.neighbors import KNeighborsRegressor#KNN算法
from sklearn.metrics import mean_squared_error#用于计算均方根误差

上面导入包的作用原理会在后面一一指出,先导入数据并提取目标字段

#导入数据并提取目标字段
path = r'rent_price.csv'
file = open(path, encoding = 'gb18030', errors = 'ignore')
dc_listings = pd.read_csv(file)
features = ['accommodates','bedrooms','bathrooms','beds','price','minimum_nights','maximum_nights','number_of_reviews']
dc_listings = dc_listings[features]

dc_listings长下面这样

3.3 初步数据清洗

数据集中非数值类型的字段需要转换,替换掉美元$符号和千分位逗号

#数据初步清洗
our_acc_value = 3
dc_listings['distance'] = np.abs(dc_listings.accommodates - our_acc_value)
dc_listings = dc_listings.sample(frac=1, random_state=0) #抽取 100% 的样本重排
dc_listings = dc_listings.sort_values('distance')
dc_listings['price'] = dc_listings['price'].str.replace(r'[\$,]', '', regex=True).astype(float)
dc_listings = dc_listings.dropna() #删除包含空值(NaN)的行

理想情况下,数据集中每个字段取值范围都相同,但实际上这是几乎不可能的,如果计算时直接用原数数据计算,则会造成较大训练误差,所以需要对各列数据进行标准化或归一化操作,尽量减少不必要的训练误差。归一化的目的就是使得预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]),从而消除奇异样本数据导致的不良影响。

#数据标准化
dc_listings[features] = StandardScaler().fit_transform(dc_listings[features]) #都变成标准正态分布
normalized_listings = dc_listings

最好不要将所有数据全部拿来测试,需要分出训练集和测试集具体划分比例按数据集确定。

#取得训练集和测试集
norm_train_df = normalized_listings[:2792]
norm_test_df = normalized_listings[2792:]

3.4 计算欧式距离并预测房屋价格

#scipy包distance模块计算欧式距离
first_listings = normalized_listings.iloc[0][['accommodates', 'bathrooms']]
fifth_listings = normalized_listings.iloc[20][['accommodates', 'bathrooms']]
#用python方法做多变量KNN模型
def predict_price_multivariate(new_listing_value, feature_columns):
temp_df = norm_train_df
#distance.cdist计算两个集合的距离
temp_df['distance'] = distance.cdist(temp_df[feature_columns], [new_listing_value[feature_columns]])
temp_df = temp_df.sort_values('distance')#temp_df按distance排序
knn_5 = temp_df.price.iloc[:5] #选择距离最近的前5个样本
predicted_price = knn_5.mean()
return predicted_price
cols = ['accommodates', 'bathrooms']
norm_test_df['predicted_price'] = norm_test_df[cols].apply(predict_price_multivariate, feature_columns=cols, axis=1)
norm_test_df['squared_error'] = (norm_test_df['predicted_price'] - norm_test_df['price']) ** 2
mse = norm_test_df['squared_error'].mean()
rmse = mse ** (1/2)
print(rmse) #利用sklearn完成KNN
col = ['accommodates', 'bedrooms']
knn = KNeighborsRegressor()
#将自变量和因变量放入模型训练,并用测试数据测试
knn.fit(norm_train_df[cols], norm_train_df['price'])
two_features_predictions = knn.predict(norm_test_df[cols])
#计算预测值与实际值的均方根误差
two_features_mse = mean_squared_error(norm_test_df['price'], two_features_predictions)
two_features_rmse = two_features_mse ** (1/2)
print(two_features_rmse)

输出为

1.4667825805653032
......(一堆报错,表示你正在对一个可能是原 DataFrame 的切片的数据进行修改,不过不影响结果)
1.5356457412450537

总结:K近邻算法的核心要素

K的大小

在实际的应用中,一般采用一个比较小的K值。并采用交叉验证的方法,选取一个最优的K值。比如在之前的代码中,手动实现的K值选的就是5,同时sklearn包里K值默认也是5.

距离度量准则

  1. 欧氏距离(Euclidean Distance)

    欧氏距离是最常用的距离度量准则之一,适用于连续型变量。它表示两个点之间的“直线”距离。

    \(d(p,q)=\sqrt {\sum_{i=1}^{n}(p_i-q_i)^2}\)

    优点:简单易懂,计算方便。

    缺点:对特征尺度敏感,需要进行特征缩放(如标准化)。

  2. 曼哈顿距离(Manhattan Distance)

    曼哈顿距离,也称为“城市街区距离”或“L1距离”,表示两个点在各维度上的绝对差值的和。

    \(d(p,q)=\sum_{i=1}^{n}|p_i-q_i|\)

    优点:对特征缩放不太敏感,适用于高维空间。

    缺点:不能反映“直线”距离,可能导致某些情况下误差较大。

  3. 切比雪夫距离(Chebyshev Distance)

    切比雪夫距离,也称为L∞距离,表示两个点之间在所有坐标轴上最大差值的距离。

    \(d(p,q)=max_i|p_i-q_i|\)

    优点:适用于棋盘格状的网格空间,特别适合某些特殊情况下的度量。

    缺点:在某些应用中可能不够精确。

KNN算法 0基础小白也能懂(附代码)的更多相关文章

  1. Docker_入门?只要这篇就够了!(纯干货适合0基础小白)

    与sgy一起开启你的Docker之路 关键词: Docker; mac; Docker中使用gdb无法进入断点,无法调试; 更新1: 看起来之前那一版博文中参考资料部分引用的外站链接太多,被系统自动屏 ...

  2. 0基础小白怎么学好Java?

    自身零基础,我们应该先学好Java,小编给大家介绍一下Java的特性: Java语言是简单的 Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用Java.Java丢弃了C+ ...

  3. 大一0基础小白用最基础C写哥德巴赫猜想

    #include <stdio.h>int main (){ int a,b,c,k,count1,count2; for(a=4;a<=1200;a=a+2){ for(b=2;b ...

  4. MySQL下载,安装,配置环境变量【0基础小白用】

    一,下载 选择社区版的,下载地址:https://dev.mysql.com/downloads/installer/  ,选择离线安装包 二,安装 1,双击安装包文件,这里选择服务模式,会安装在默认 ...

  5. (五)SpringBoot2.0基础篇- Mybatis与插件生成代码

    SpringBoot与Mybatis合并 一.创建SpringBoot项目,引入相关依赖包: <?xml version="1.0" encoding="UTF-8 ...

  6. (六)SpringBoot2.0基础篇- Redis整合(JedisCluster集群连接)

    一.环境 Redis:4.0.9 SpringBoot:2.0.1 Redis安装:Linux(Redhat)安装Redis 二.SpringBoot整合Redis 1.项目基本搭建: 我们基于(五) ...

  7. 【机器学习算法基础+实战系列】KNN算法

    k 近邻法(K-nearest neighbor)是一种基本的分类方法 基本思路: 给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,这k个实例多数属于某个类别,就把输 ...

  8. 0基础的小白怎么学习Java?

    自身零基础,那么我们应该先学好Java,首先我们来了解下Java的特性: Java语言是简单的 Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用Java.另一方面,Jav ...

  9. 0基础算法基础学算法 第八弹 递归进阶,dfs第一讲

    最近很有一段时间没有更新了,主要是因为我要去参加一个重要的考试----小升初!作为一个武汉的兢兢业业的小学生当然要去试一试我们那里最好的几个学校的考试了,总之因为很多的原因放了好久的鸽子,不过从今天开 ...

  10. 机器学习实战 之 KNN算法

    现在 机器学习 这么火,小编也忍不住想学习一把.注意,小编是零基础哦. 所以,第一步,推荐买一本机器学习的书,我选的是Peter harrigton 的<机器学习实战>.这本书是基于pyt ...

随机推荐

  1. Linux 特权 SUID/SGID 的详解

    导航 0 前言 1 权限匹配流程 2 五种身份变化 3 有效用户/组 4 特权对 Shell 脚本无效 5 Sudo 与 SUID/SGID 的优先级 6 SUID.SGID.Sticky 各自的功能 ...

  2. 新品来袭,全国产ARM+FPGA--"RK3568J+Logos-2"工业核心板,让您的硬件设计“更简单”!

    如需选购,请登录创龙科技天猫旗舰店: tronlong.tmall.com! 欢迎加入RK3568J技术交流群:567208221 欢迎加入Logos-2技术交流群:311416997 更多产品详情以 ...

  3. NXP i.MX 6ULL工业核心板规格书( ARM Cortex-A7,主频792MHz)

    1 核心板简介 创龙科技SOM-TLIMX6U是一款基于NXP i.MX 6ULL的ARM Cortex-A7高性能低功耗处理器设计的低成本工业级核心板,主频792MHz,通过邮票孔连接方式引出Eth ...

  4. github中的子模块(git submodule)

    git中支持引用另外一个开源库,并且可以指定依赖的分支或者提交记录号. 比如fltk-rs 库的fltk-sys模块依赖了库 cfltk 并指明了依赖的提交是 8a56507 甚至可以嵌套,毕竟库自身 ...

  5. FileZilia FATAL ERROR: Network error: Software caused connection abort

    使用FileZilia sftp传文件,对象服务器突然关闭,导致FileZilia传输中断. 等待对象服务器打开后,使用FileZilia想继续传输文件,结果一直显示: FATAL ERROR: Ne ...

  6. mac idea 配置Tomcat

    官网下载Tomcat 下载地址:点我直达 配置Idea 设置Application Servers 操作步骤:Intellij IDEA->Preferences->Application ...

  7. 在IDEA中找不到Mapper报错

    前言 相信大多数互联网公司的持久层框架都是使用 Mybatis 框架,而大家在 Service 层引入自己编写的 Mapper 接口时应该会遇到下面的情况: 我们可以看到,上面的红色警告在提示我们,找 ...

  8. 如何删除Git中缓存的用户名和密码

    昨天在上传代码的时候提示输入用户名密码,结果输错了3次就没有提示框了,就一直报错(身份验证失败),没办法提交代. 在使用git的过程中,我们也会经常遇到以前保存在git的用户名密码忘记了,或者不用了. ...

  9. [oeasy]python0120_英语的崛起_英文字符_小写字母的由来_不列颠帝国

    各语言字符编码 回忆上次内容 罗马 承袭了 希腊的文化 学习了 希腊的字符   拥有 罗马帝国的战力 基督教文化的影响     ​   添加图片注释,不超过 140 字(可选)   这个时候 不列颠 ...

  10. Odoo 菜单定义和修改学习总结

    odoo菜单定义和修改学习总结 环境 odoo-14.0.post20221212.tar 定义菜单 方式1: <?xml version="1.0"?> <od ...