
K-近邻算法
-
已知《战狼》《红海行动》《碟中谍 6》是动作片,而《前任 3》《春娇救志明》《泰坦尼克号》是爱情片。但是如果一旦现在有一部新的电影《美人鱼》,有没有一种方法让机器也可以掌握一个分类的规则,自动的将新电影进行分类?
截屏2020-10-27 下午2.53.11.png - 将数据可视化。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 步骤一(替换sans-serif字体)
plt.rcParams['axes.unicode_minus'] = False # 步骤二(解决坐标轴负数的负号显示问题)
x = [5,3,31,59,60,80]
y = [100,95,105,2,3,10]
labels = ["《战狼》","《红海行动》","《碟中谍6》","《前任3》","《春娇与志明》","《泰坦尼克号》"]
plt.scatter(x,y,s=120)
plt.xlabel("亲吻次数")
plt.ylabel("打斗次数")
plt.xticks(range(0,150,10))
plt.yticks(range(0,150,10))
count = 0
for x_i,y_i in zip(x,y):
plt.annotate(f"{labels[count]}",xy=(x_i,y_i),xytext=(x_i,y_i))
count+=1
#############################################
-
怎么知道《美人鱼》这个点离哪类点的距离最近?——两点距离
截屏2020-10-27 下午4.20.26.png
截屏2020-10-27 下午4.21.23.png - 类实现
class MyKnn(object):
def __init__(self,train_df,k=3):
self.k =k
self.train_df = train_df
def predict(self,x_new_test):
self.train_df['dis'] = np.sqrt((df['打斗次数']-df.loc[6,'打斗次数'])**2 + (df['接吻次数']-df.loc[6,'接吻次数'])**2)
my_types=self.train_df.sort_values(by='dis').iloc[:self.k]['电影类型']
my_types.value_counts().index
########################
from sklearn.neighbors import KNeighborsClassifier
df= pd.read_excel(r'/Users/tianshan/Documents/learn/上课代码及资料/02-k近邻算法/电影数据.xlsx')
x =df.loc[:5,'打斗次数':'接吻次数'].values
y=df.loc[:5,'电影类型'].values
knn=KNeighborsClassifier(n_neighbors=4)
knn.fit(x,y)
knn.predict([[5,29]])
总结KNN工作流程
- 1.计算待分类物体与其他物体之间的距离
- 2.统计距离最近的k个邻居
- 3.对于K个最近的邻居,他们属于哪个分类最多,待分类物体就属于哪一类
K-近邻算法api介绍
- scikit-learn 是基于Python语言的机器学习工具
- 是Python语言简单高效的数据挖掘和数据分析工具
- Scikit-learn包括许多知名的机器学习算法的实现
- Scikit-learn 文档完善,容易上手,丰富的API
分类问题
from sklearn.neighbors import KNeighborsClassifier
x=[[-1],[-2],[2],[3]]
y=[0,0,1,1]
tj = KNeighborsClassifier(n_neighbors=2)
tj.fit(x,y)
tj.predict([[5]]
- 输出:array([1])
总结
- 构建特征数据与目标数据
- 构建k个近邻的分类器
- 使用fit进行训练
- 预测数据
K值选择
- 在文章开始的电影分类这个实例中,k值选择应该是个实践出来的结果,并不是我们实现而定的。在工程上,我们一般采用交叉验证的方式选取K值。
- 交叉验证的思路就是:把样本集中的大部分样本作为训练集,剩下的小部分样本用于预测,来验证分类的模型的准确性。所以在KNN算法中,我们一般会把K值选取在较小的范围内,同时在验证集上准确率最高的那一个最终确定为K值。
- 当K值过小,容易受到异常点的影响
- 当K值过大,受到样本均衡的问题
距离计算
- 欧式距离(欧几里得距离)
- 曼哈顿距离
- 闵可夫斯基距离
- 切比雪夫距离
- 余弦距离
欧氏距离
欧氏距离是我们最常用的距离公式,也叫作欧几里得距离。在二维空间中,两点的欧氏距离是:

同理,我们也可以求得两点在n维空间中的距离:

曼哈顿距离
曼哈顿距离在几何空间中用的比较多。

二维平面两点a(x1,y1)与b(x2,y2)间的曼哈顿距离:

n维空间点(x11,x12,...,x1n)与b(x21,x22,...,x2n)的曼哈顿距离:

切比雪夫距离
在国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?这个距离就叫切比雪夫距离。

二维平面两点a(x1,x2)与b(x2,y2)间的切比雪夫距离:

n维空间点a(x11,x12,...,x1n)与b(x21,x22,...,x2n)的切比雪夫距离:

闵可夫斯基距离
闵式距离是一类距离的统称,是对多个距离度量公式的概括性的表述。
两个n维变量a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:

其中p是一个变参数:
- 当p=1时,就是曼哈顿距离;
- 当p=2时,就是欧氏距离;
- 当p→∞时,就是切比雪夫距离。
余弦距离
余弦距离实际上计算的是两个向量的夹角,是在方向上计算两者之间的差异,对绝对数值不敏感。
二维空间中向量A(x1,y1)与向量B(x2,y2)的夹角余弦公式:

两个n维样本点a(x11,x12,…,x1n)和b(x21,x22,…,x2n)的夹角余弦为:


KD树
KNN 的计算过程是大量计算样本点之间的距离。为了减少计算距离次数,提升 KNN 的搜索效率,人们提出了 KD 树(K-Dimensional 的缩写)。KD 树是对数据点在 K 维空间中划分的一种数据结构。在 KD 树的构造中,每个节点都是 k 维数值点的二叉树。既然是二叉树,就可以采用二叉树的增删改查操作,这样就大大提升了搜索效率。
数据集获取
获取函数
sklearn.datasets 加载获取流行数据集
- datasets.load_***() 获取小规模数据集,数据包含在datasets里
- datasets.fetch_***(data_home=None) 获取大规模数据集,需要从网络上下载,函数的第一个参数是data_home,表示数据集下载的目录,默认是 ~/scikit_learn_data/
<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">from sklearn.datasets import load_iris,fetch_20newsgroups iris = load_iris() iris news = fetch_20newsgroups() news</pre>
返回集
load和fetch返回的数据类型(字典格式)
- data:特征数据数组
- target:标签数组
- DESCR:数据描述
- feature_names:特征名
- target_names:标签名
<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">from sklearn.datasets import load_iris iris = load_iris() print("鸢尾花数据集的返回值:\n", iris) print("鸢尾花的特征值:\n", iris["data"]) print("鸢尾花的目标值:\n", iris.target) print("鸢尾花特征的名字:\n", iris.feature_names) print("鸢尾花目标值的名字:\n", iris.target_names) print("鸢尾花的描述:\n", iris.DESCR)</pre>
数据分割
数据分割规则
- 训练数据:用于训练,构建模型
- 测试数据:在模型检验时使用,用于评估模型是否有效。
划分比例:
- 训练集:70% 80% 75%
- 测试集:30% 20% 25%
数据分割api
*sklearn.model_selection.train_test_split(arrays, options)
- x 数据集的特征值
- y 数据集的标签值
- test_size 测试集的大小,一般为float
- random_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。
- return 训练特征值,测试特征值,训练目标值,测试目标值
<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">from sklearn.model_selection import train_test_split x_train,x_test,y_train,y_test = train_test_split(iris.data,iris.target,test_size=0.2) print("训练集的特征值:",x_train) print("测试集的特征值:",x_test) print("训练集的目标值:",y_train) print("测试集的目标值:",y_test) </pre>
特征工程
归一化Min-Max
将原始数据映射到[0,1]之间

归一化api:
sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
MinMaxScalar.fit_transform(X)
X:numpy array格式的数据[n_samples,n_features]
但是归一化是有弊端的,比如有一个值错误,就会影响整体的数值,并且归一化是无法解决这个异常值。所以归一化只适合传统精确小数据场景
标准化
通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内。也就是服从正态分布的数据。

标准化api:
sklearn.preprocessing.StandardScaler( ) 处理之后每列来说所有数据都聚集在均值0附近标准差差为1
StandardScaler.fit_transform(X)
X:numpy array格式的数据[n_samples,n_features]
鸢尾花案例
分类算法api详解
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto')
n_neighbors:int,可选(默认= 5),k_neighbors查询默认使用的邻居数
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分割样本空间,每个节点是一个超球体。
鸢尾花案例——分类
实现步骤:
- 获取数据
- 数据基本处理
- 特征工程
- 机器学习(模型训练)
- 模型评估
数据集
- 特征值——4个:花瓣、花萼的长度、宽度
- 目标值——3个:setosa(山鸢尾),vericolor(虹膜锦囊),virginica(变色鸢尾)
交叉验证
交叉验证(Cross Validation),有的时候也称作循环估计(Rotation Estimation),是一种统计学上将数据样本切割成较小子集的实用方法。
在给定的建模样本中,拿出大部分样本进行建模型,留小部分样本用刚建立的模型进行预报,并求这小部分样本的预报误差,记录它们的平方加和。这个过程一直进行,直到所有的样本都被预报了一次而且仅被预报一次。把每个样本的预报误差平方加和。
交叉验证目的:为了得到可靠稳定的模型
网格搜索
网格搜索(Grid Search)名字非常大气,但是用简答的话来说就是你手动的给出一个模型中你想要改动的所用的参数,程序自动的帮你使用穷举法来将所用的参数都运行一遍。
交叉验证、网格搜索api
sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None) 对估计器的指定参数值进行详尽搜索
- estimator:估计器对象
- param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
- cv:指定几折交叉验证
- fit:输入训练数据
- score:准确率
K-近邻算法——回归
KNN 不仅可以做分类,还可以做回归。
获取数据
<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">import pandas as pd import numpy as np import matplotlib.pyplot as plt features = ['accommodates','bedrooms','bathrooms','beds','price','minimum_nights','maximum_nights','number_of_reviews'] air_df = pd.read_csv("listings.csv",usecols=features) air_df.info()</pre>
- accommodates:可以容纳的旅客
- bedrooms:卧室的数量
- bathrooms:厕所的数量
- beds:床的数量
- price:每晚的费用
- minimum_nights:客人最少租了几天
- maximum_nights:客人最多租了几天
- number_of_reviews:评论的数量
问题:假如我有一个1室的房子,可以租多少钱?


数据分割

模型评估
使用RMSE



