文章目录
1.1 K-近邻算法简介
学习目标
- 目标
- 了解什么是KNN算法
- 知道KNN算法求解过程
1 什么是K-近邻算法
- 根据你的“邻居”来推断出你的类别
1.1 K-近邻算法(KNN)概念
K Nearest Neighbor算法又叫KNN算法,这个算法是机器学习里面一个比较经典的算法, 总体来说KNN算法是相对比较容易理解的算法
- 定义
如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
来源:KNN算法最早是由Cover和Hart提出的一种分类算法
- 距离公式
两个样本的距离可以通过如下公式计算,又叫欧式距离 ,关于距离公式会在后面进行讨论
1.2 电影类型分析
假设我们现在有几部电影
其中? 9号电影不知道类别,如何去预测?我们可以利用K近邻算法的思想
1.分别计算每个电影和被预测电影的距离,然后求解。
如计算9号电影<<唐人街探险>>与<<二次曝光>>的距离为:
d
=
(
23
−
2
)
2
+
(
3
−
3
)
2
+
(
17
−
55
)
2
=
43.42
d = \sqrt{(23-2)^2 + (3-3)^2 + (17-55)^2} = 43.42
d=(23−2)2+(3−3)2+(17−55)2=43.42
2.距离递增次序为:7,1,8,5,4,3,6,2
3.设定k值,假设k为5。前5个电影分别为7,1,8,5,4
4.喜剧3次,爱情2次
5.9的预测值为喜剧。
1.3 KNN算法流程总结
1)计算已知类别数据集中的点与当前点之间的距离
2)按距离递增次序排序
3)选取与当前点距离最小的k个点
4)统计前k个点所在的类别出现的频率
5)返回前k个点出现频率最高的类别作为当前点的预测分类
2 小结
- K-近邻算法简介【了解】
- 定义:就是通过你的"邻居"来判断你属于哪个类别
- 如何计算你到你的"邻居"的距离:一般时候,都是使用欧氏距离
1.2 k近邻算法api初步使用
学习目标
- 目标
- 了解sklearn工具的优点和包含内容
- 应用sklearn中的api实现KNN算法的简单使用
-
机器学习流程复习:
-
1.获取数据集
-
2.数据基本处理
-
3.特征工程
-
4.机器学习
-
5.模型评估
1 Scikit-learn工具介绍
- Python语言的机器学习工具
- Scikit-learn包括许多知名的机器学习算法的实现
- Scikit-learn文档完善,容易上手,丰富的API
- 目前稳定版本0.19.1
1.1 安装
pip3 install scikit-learn==0.19.1
安装好之后可以通过以下命令查看是否安装成功
import sklearn
- 注:安装scikit-learn需要Numpy, Scipy等库
1.2 Scikit-learn介绍
- 分类、聚类、回归、降维、模型选择、预处理
2 K-近邻算法API
- sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
- n_neighbors:int,可选(默认= 5),k_neighbors查询默认使用的邻居数
3 案例
3.1 步骤分析
- 1.获取数据集
- 2.数据基本处理(该案例中省略)
- 3.特征工程(该案例中省略)
- 4.机器学习
- 5.模型评估(该案例中省略)
3.2 代码过程
- 导入模块
from sklearn.neighbors import KNeighborsClassifier
- 构造数据集
x = [[0], [1], [2], [3]]
y = [0, 0, 1, 1]
- 机器学习 – 模型训练
# 实例化API
estimator = KNeighborsClassifier(n_neighbors=1)
# 使用fit方法进行训练
estimator.fit(x, y)
estimator.predict([[1]])
4 小结
- sklearn的优势:
- 文档多,且规范
- 包含的算法多
- 实现起来容易
- knn中的api
- sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
问题
1.距离公式,除了欧式距离,还有哪些距离公式可以使用?
2.选取K值的大小?
3.api中其他参数的具体含义?
1.3 距离度量
学习目标
- 目标
- 知道机器学习中常见的距离计算公式
1 常见的距离公式
1.1 欧式距离**(Euclidean Distance):
欧氏距离是最容易直观理解的距离度量方法,我们小学、初中和高中接触到的两个点在空间中的距离一般都是指欧氏距离。
举例:
X=[[1,1],[2,2],[3,3],[4,4]];
经计算得:
d = 1.4142 2.8284 4.2426 1.4142 2.8284 1.4142
1.2 曼哈顿距离(Manhattan Distance):
在曼哈顿街区要从一个十字路口开车到另一个十字路口,驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离”。曼哈顿距离也称为“城市街区距离”(City Block distance)。
举例:
X=[[1,1],[2,2],[3,3],[4,4]];
经计算得:
d = 2 4 6 2 4 2
1.3 切比雪夫距离 (Chebyshev Distance):
国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?这个距离就叫切比雪夫距离。
举例:
X=[[1,1],[2,2],[3,3],[4,4]];
经计算得:
d = 1 2 3 1 2 1
1.4 闵可夫斯基距离(Minkowski Distance):
闵氏距离不是一种距离,而是一组距离的定义,是对多个距离度量公式的概括性的表述。
两个n维变量a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:
其中p是一个变参数:
- 当p=1时,就是曼哈顿距离;
- 当p=2时,就是欧氏距离;
- 当p→∞时,就是切比雪夫距离。
根据p的不同,闵氏距离可以表示某一类/种的距离。
小结:
1 闵氏距离,包括曼哈顿距离、欧氏距离和切比雪夫距离,都存在明显的缺点:
e.g. 二维样本(身高[单位:cm],体重[单位:kg]),现有三个样本:a(180,50),b(190,50),c(180,60)。
a与b的闵氏距离(无论是曼哈顿距离、欧氏距离或切比雪夫距离)等于a与c的闵氏距离。但实际上身高的10cm并不能和体重的10kg划等号。
2 闵氏距离的缺点:
(1)将各个分量的量纲(scale),也就是“单位”相同的看待了;
(2)未考虑各个分量的分布(期望,方差等)可能是不同的。
[【拓展】其他距离公式]
2 “连续属性”和“离散属性”的距离计算
我们常将属性划分为"连续属性" (continuous attribute)和"离散属性" (categorical attribute),前者在定义域上有无穷多个可能的取值,后者在定义域上是有限个取值.
- 若属性值之间存在序关系,则可以将其转化为连续值,例如:身高属性“高”“中等”“矮”,可转化为{1, 0.5, 0}。
- 闵可夫斯基距离可以用于有序属性。
- 若属性值之间不存在序关系,则通常将其转化为向量的形式,例如:性别属性“男”“女”,可转化为{(1,0),(0,1)}。
3 小结
- 1 常见距离公式
- 2.1 欧式距离(Euclidean Distance)【知道】:
- 通过距离平方值进行计算
- 2.曼哈顿距离(Manhattan Distance)【知道】:
- 通过距离的绝对值进行计算
- 3.切比雪夫距离 (Chebyshev Distance)【知道】:
- 维度的最大值进行计算
- 4.闵可夫斯基距离(Minkowski Distance)【知道】:
- 当p=1时,就是曼哈顿距离;
- 当p=2时,就是欧氏距离;
- 当p→∞时,就是切比雪夫距离。
- 2.1 欧式距离(Euclidean Distance)【知道】:
- 2 属性【知道】
- 连续属性
- 离散属性,
- 存在序关系,可以将其转化为连续值
- 不存在序关系,通常将其转化为向量的形式
1.4 案例:鸢尾花种类预测–数据集介绍
学习目标
- 目标
- 知道sklearn中获取数据集的方法
- 知道sklearn中对数据集的划分方法
本实验介绍了使用Python进行机器学习的一些基本概念。 在本案例中,将使用K-Nearest Neighbor(KNN)算法对鸢尾花的种类进行分类,并测量花的特征。
本案例目的:
- 遵循并理解完整的机器学习过程
- 对机器学习原理和相关术语有基本的了解。
- 了解评估机器学习模型的基本过程。
1 案例:鸢尾花种类预测
Iris数据集是常用的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一类多重变量分析的数据集。关于数据集的具体介绍:
2 scikit-learn中数据集介绍
2.1 scikit-learn数据集API介绍
- sklearn.datasets
- 加载获取流行数据集
- datasets.load_*()
- 获取小规模数据集,数据包含在datasets里
- datasets.fetch_*(data_home=None)
- 获取大规模数据集,需要从网络上下载,函数的第一个参数是data_home,表示数据集下载的目录,默认是 ~/scikit_learn_data/
2.1.1 sklearn小数据集
-
sklearn.datasets.load_iris()
加载并返回鸢尾花数据集
2.1.2 sklearn大数据集
- sklearn.datasets.fetch_20newsgroups(data_home=None,subset=‘train’)
- subset:‘train’或者’test’,‘all’,可选,选择要加载的数据集。
- 训练集的“训练”,测试集的“测试”,两者的“全部”
2.2 sklearn数据集返回值介绍
- load和fetch返回的数据类型datasets.base.Bunch(字典格式)
- data:特征数据数组,是 [n_samples * n_features] 的二维 numpy.ndarray 数组
- target:标签数组,是 n_samples 的一维 numpy.ndarray 数组
- DESCR:数据描述
- feature_names:特征名,新闻数据,手写数字、回归数据集没有
- target_names:标签名
from sklearn.datasets import load_iris
# 获取鸢尾花数据集
iris = load_iris()
print("鸢尾花数据集的返回值:\n", iris)
# 返回值是一个继承自字典的Bench
print("鸢尾花的特征值:\n", iris["data"])#调用iris.data和iris["data"]效果一样
print("鸢尾花的目标值:\n", iris.target)
print("鸢尾花特征的名字:\n", iris.feature_names)
print("鸢尾花目标值的名字:\n", iris.target_names)
print("鸢尾花的描述:\n", iris.DESCR)
2.3 查看数据分布
通过创建一些图,以查看不同类别是如何通过特征来区分的。 在理想情况下,标签类将由一个或多个特征对完美分隔。 在现实世界中,这种理想情况很少会发生。
- seaborn介绍
- Seaborn 是基于 Matplotlib 核心库进行了更高级的 API 封装,可以让你轻松地画出更漂亮的图形。而 Seaborn 的漂亮主要体现在配色更加舒服、以及图形元素的样式更加细腻。
- 安装 pip3 install seaborn
- seaborn.lmplot() 是一个非常有用的方法,它会在绘制二维散点图时,自动完成回归拟合
- sns.lmplot() 里的 x, y 分别代表横纵坐标的列名,
- data= 是关联到数据集,
- hue=*代表按照 species即花的类别分类显示,
- fit_reg=是否进行线性拟合。
- 参考链接: api链接
%matplotlib inline
# 内嵌绘图
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 把数据转换成dataframe的格式
iris_d = pd.DataFrame(iris['data'], columns = ['Sepal_Length', 'Sepal_Width', 'Petal_Length', 'Petal_Width'])
iris_d['Species'] = iris.target
def plot_iris(iris, col1, col2):
sns.lmplot(x = col1, y = col2, data = iris, hue = "Species", fit_reg = False)
plt.xlabel(col1)
plt.ylabel(col2)
plt.title('鸢尾花种类分布图')
plt.show()
plot_iris(iris_d, 'Petal_Width', 'Sepal_Length')
2.4 数据集的划分
机器学习一般的数据集会划分为两个部分:
- 训练数据:用于训练,构建模型
- 测试数据:在模型检验时使用,用于评估模型是否有效
划分比例:
- 训练集:70% 80% 75%
- 测试集:30% 20% 25%
数据集划分api
- sklearn.model_selection.train_test_split(arrays, *options)
- 参数:
- x 数据集的特征值
- y 数据集的标签值
- test_size 测试集的大小,一般为float
- random_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。
- return
- x_train, x_test, y_train, y_test
- 参数:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 1、获取鸢尾花数据集
iris = load_iris()
# 对鸢尾花数据集进行分割
# 训练集的特征值x_train 测试集的特征值x_test 训练集的目标值y_train 测试集的目标值y_test
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
print("x_train:\n", x_train.shape)
# 随机数种子
x_train1, x_test1, y_train1, y_test1 = train_test_split(iris.data, iris.target, random_state=6)
x_train2, x_test2, y_train2, y_test2 = train_test_split(iris.data, iris.target, random_state=6)
print("如果随机数种子不一致:\n", x_train == x_train1)
print("如果随机数种子一致:\n", x_train1 == x_train2)
3 总结
- 获取数据集【知道】
- 小数据:
- sklearn.datasets.load_*
- 大数据集:
- sklearn.datasets.fetch_*
- 小数据:
- 数据集返回值介绍【知道】
- 返回值类型是bunch–是一个字典类型
- 返回值的属性:
- data:特征数据数组
- target:标签(目标)数组
- DESCR:数据描述
- feature_names:特征名,
- target_names:标签(目标值)名
- 数据集的划分【掌握】
- sklearn.model_selection.train_test_split(arrays, *options)
- 参数:
- x – 特征值
- y – 目标值
- test_size – 测试集大小
- ramdom_state – 随机数种子
- 返回值:
- x_train, x_test, y_train, y_test
1.5 特征工程-特征预处理
学习目标
- 目标
- 了解什么是特征预处理
- 知道归一化和标准化的原理及区别
1 什么是特征预处理
1.1 特征预处理定义
scikit-learn的解释
provides several common utility functions and transformer classes to change raw feature vectors into a representation that is more suitable for the downstream estimators.
翻译过来:通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程
我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格
1.2 包含内容(数值型数据的无量纲化)
- 归一化
- 标准化
1.3 特征预处理API
sklearn.preprocessing
2 归一化
2.1 定义
通过对原始数据进行变换把数据映射到(默认为[0,1])之间
2.2 公式
作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0
那么怎么理解这个过程呢?我们通过一个例子
2.3 API
- sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
- MinMaxScalar.fit_transform(X)
- X:numpy array格式的数据[n_samples,n_features]
- 返回值:转换后的形状相同的array
- MinMaxScalar.fit_transform(X)
2.4 数据计算
我们对以下数据进行运算,在dating.txt中。保存的就是之前的约会对象数据
milage,Liters,Consumtime,target
40920,8.326976,0.953952,3
14488,7.153469,1.673904,2
26052,1.441871,0.805124,1
75136,13.147394,0.428964,1
38344,1.669788,0.134296,1
- 分析
1、实例化MinMaxScalar
2、通过fit_transform转换
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
def minmax_demo():
"""
归一化演示
:return: None
"""
data = pd.read_csv("./data/dating.txt")
print(data)
# 1、实例化一个转换器类
transfer = MinMaxScaler(feature_range=(2, 3))
# 2、调用fit_transform
data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
print("最小值最大值归一化处理的结果:\n", data)
return None
minmax_demo()
返回结果:
milage Liters Consumtime target
0 40920 8.326976 0.953952 3
1 14488 7.153469 1.673904 2
2 26052 1.441871 0.805124 1
3 75136 13.147394 0.428964 1
.. ... ... ... ...
998 48111 9.134528 0.728045 3
999 43757 7.882601 1.332446 3
[1000 rows x 4 columns]
最小值最大值归一化处理的结果:
[[ 2.44832535 2.39805139 2.56233353]
[ 2.15873259 2.34195467 2.98724416]
[ 2.28542943 2.06892523 2.47449629]
...,
[ 2.29115949 2.50910294 2.51079493]
[ 2.52711097 2.43665451 2.4290048 ]
[ 2.47940793 2.3768091 2.78571804]]
问题:如果数据中异常点较多,会有什么影响?
2.5 归一化总结
注意最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。
怎么办?
3 标准化
3.1 定义
通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内
3.2 公式
作用于每一列,mean为平均值,σ为标准差
所以回到刚才异常点的地方,我们再来看看标准化
- 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
- 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。
3.3 API
- sklearn.preprocessing.StandardScaler( )
- 处理之后每列来说所有数据都聚集在均值0附近标准差差为1
- StandardScaler.fit_transform(X)
- X:numpy array格式的数据[n_samples,n_features]
- 返回值:转换后的形状相同的array
3.4 数据计算
同样对上面的数据进行处理
- 分析
1、实例化StandardScaler
2、通过fit_transform转换
import pandas as pd
from sklearn.preprocessing import StandardScaler
def stand_demo():
"""
标准化演示
:return: None
"""
data = pd.read_csv("./data/dating.txt")
print(data)
# 1、实例化一个转换器类
transfer = StandardScaler()
# 2、调用fit_transform
data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
print("标准化的结果:\n", data)
print("每一列特征的平均值:\n", transfer.mean_)
print("每一列特征的方差:\n", transfer.var_)
return None
返回结果:
milage Liters Consumtime target
0 40920 8.326976 0.953952 3
1 14488 7.153469 1.673904 2
2 26052 1.441871 0.805124 1
.. ... ... ... ...
997 26575 10.650102 0.866627 3
998 48111 9.134528 0.728045 3
999 43757 7.882601 1.332446 3
[1000 rows x 4 columns]
标准化的结果:
[[ 0.33193158 0.41660188 0.24523407]
[-0.87247784 0.13992897 1.69385734]
[-0.34554872 -1.20667094 -0.05422437]
...,
[-0.32171752 0.96431572 0.06952649]
[ 0.65959911 0.60699509 -0.20931587]
[ 0.46120328 0.31183342 1.00680598]]
每一列特征的平均值:
[ 3.36354210e+04 6.55996083e+00 8.32072997e-01]
每一列特征的方差:
[ 4.81628039e+08 1.79902874e+01 2.46999554e-01]
3.5 标准化总结
在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。
4 总结
- 什么是特征工程【知道】
- 定义
- 通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程
- 包含内容:
- 归一化
- 标准化
- 定义
- 归一化【知道】
- 定义:
- 对原始数据进行变换把数据映射到(默认为[0,1])之间
- api:
- sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
- 参数:feature_range – 自己指定范围,默认0-1
- 总结:
- 鲁棒性比较差(容易受到异常点的影响)
- 只适合传统精确小数据场景(以后不会用你了)
- 定义:
- 标准化【掌握】
- 定义:
- 对原始数据进行变换把数据变换到均值为0,标准差为1范围内
- api:
- sklearn.preprocessing.StandardScaler( )
- 总结:
- 异常值对我影响小
- 适合现代嘈杂大数据场景(以后就是用你了)
- 定义:
1.6 案例:鸢尾花种类预测—流程实现
学习目标
- 目标
- 知道KNeighborsClassifier的用法
1 再识K-近邻算法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分割样本空间,每个节点是一个超球体。
- 快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,
- n_neighbors:
2 案例:鸢尾花种类预测
2.1 数据集介绍
Iris数据集是常用的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一类多重变量分析的数据集。关于数据集的具体介绍:
2.2 步骤分析
- 1.获取数据集
- 2.数据基本处理
- 3.特征工程
- 4.机器学习(模型训练)
- 5.模型评估
2.3 代码过程
- 导入模块
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
- 先从sklearn当中获取数据集,然后进行数据集的分割
# 1.获取数据集
iris = load_iris()
# 2.数据基本处理
# x_train,x_test,y_train,y_test为训练集特征值、测试集特征值、训练集目标值、测试集目标值
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
- 进行数据标准化
- 特征值的标准化
# 3、特征工程:标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
- 模型进行训练预测
# 4、机器学习(模型训练)
estimator = KNeighborsClassifier(n_neighbors=9)
estimator.fit(x_train, y_train)
# 5、模型评估
# 方法1:比对真实值和预测值
y_predict = estimator.predict(x_test)
print("预测结果为:\n", y_predict)
print("比对真实值和预测值:\n", y_predict == y_test)
# 方法2:直接计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)
3 案例小结
在本案例中,具体完成内容有:
- 使用可视化加载和探索数据,以确定特征是否能将不同类别分开。
- 通过标准化数字特征并随机抽样到训练集和测试集来准备数据。
- 通过统计学,精确度度量进行构建和评估机器学习模型。
同学之间讨论刚才完成的机器学习代码,并且确保在自己的电脑运行成功
4 总结
- KNeighborsClassifier的使用【知道】
- sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm=‘auto’)
- algorithm(auto,ball_tree, kd_tree, brute) – 选择什么样的算法进行计算
- sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm=‘auto’)
1.7 KNN算法总结
k近邻算法优缺点汇总
-
优点:
- 简单有效
- k近邻算法是一种在线技术,新数据可以直接加入数据集而不必进行重新训练
- 对异常值和噪声有较高的容忍度。
- k近邻算法天生就支持多分类,区别与感知机、逻辑回归、SVM。
- 适合类域交叉样本
- KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
-
缺点:
- 惰性学习
- KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多
- 占内存
- KD树,球树之类的模型建立需要大量的内存
- 输出可解释性不强
- 例如决策树的输出可解释性就较强
- 对不均衡的样本不擅长
- 当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
- 计算量较大
- 目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。
- 惰性学习
1.8 交叉验证,网格搜索
学习目标
- 目标
- 知道为什么需要验证集
- 知道交叉验证、网格搜索的概念
- 会使用交叉验证、网格搜索优化训练模型
1 什么是交叉验证(cross validation)
交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成4份,其中一份作为验证集。然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。
1.1 分析
我们之前知道数据分为训练集和测试集,但是**为了让从训练得到模型结果更加准确。**做以下处理
- 训练集:训练集+验证集
- 测试集:测试集
1.2 为什么需要交叉验证
验证集的目的:为了调节超参数
交叉验证目的:为了让被评估的模型更加准确可信
问题:这个只是让被评估的模型更加准确可信,那么怎么选择或者调优参数呢?
2 什么是网格搜索(Grid Search)
通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
3 交叉验证,网格搜索(模型选择与调优)API:
- sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
- 对估计器的指定参数值进行详尽搜索
- estimator:估计器对象
- param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
- cv:指定几折交叉验证
- fit:输入训练数据
- score:准确率
- 结果分析:
- bestscore__:在交叉验证中验证的最好结果
- bestestimator:最好的参数模型
- cvresults:每次交叉验证后的验证集准确率结果和训练集准确率结果
4 鸢尾花案例增加K值调优
- 使用GridSearchCV构建估计器
from sklearn.model_selection import GridSearchCV
# 1、获取数据集
iris = load_iris()
# 2、数据基本处理 -- 划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
# 3、特征工程:标准化
# 实例化一个转换器类
transfer = StandardScaler()
# 调用fit_transform
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4、KNN预估器流程
# 4.1 实例化预估器类
estimator = KNeighborsClassifier()
# 4.2 模型选择与调优——网格搜索和交叉验证
# 准备要调的超参数
param_dict = {"n_neighbors": [1, 3, 5]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
# 4.3 fit数据进行训练
estimator.fit(x_train, y_train)
# 5、评估模型效果
# 方法a:比对预测结果和真实值
y_predict = estimator.predict(x_test)
print("比对预测结果和真实值:\n", y_predict == y_test)
# 方法b:直接计算准确率
score = estimator.score(x_test, y_test)
print("直接计算准确率:\n", score)
- 然后进行评估查看最终选择的结果和交叉验证的结果
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的模型:\n", estimator.best_estimator_)
print("最好模型的参数:\n",estimator.best_params_)
print("每次交叉验证后的准确率结果:\n", estimator.cv_results_)
5 总结
- 交叉验证【知道】
- 定义:
- 将拿到的训练数据,分为训练和验证集
- *折交叉验证
- 分割方式:
- 训练集:训练集+验证集
- 测试集:测试集
- 为什么需要交叉验证
- 为了让被评估的模型更加准确可信
- 注意:交叉验证不能提高模型的准确率
- 定义:
- 网格搜索【知道】
- 超参数:
- sklearn中,需要手动指定的参数,叫做超参数
- 网格搜索就是把这些超参数的值,通过字典的形式传递进去,然后进行选择最优值
- 超参数:
- api【知道】
- sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
- estimator – 选择了哪个训练模型
- param_grid – 需要传递的超参数
- cv – 几折交叉验证
- sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
知识拓展:其他距离公式
1 标准化欧氏距离 (Standardized EuclideanDistance):
标准化欧氏距离是针对欧氏距离的缺点而作的一种改进。
思路:既然数据各维分量的分布不一样,那先将各个分量都“标准化”到均值、方差相等。
S_kS**k表示各个维度的标准差
如果将方差的倒数看成一个权重,也可称之为加权欧氏距离(Weighted Euclidean distance)。
举例:
X=[[1,1],[2,2],[3,3],[4,4]];(假设两个分量的标准差分别为0.5和1)
经计算得:
d = 2.2361 4.4721 6.7082 2.2361 4.4721 2.2361
2 余弦距离(Cosine Distance)
几何中,夹角余弦可用来衡量两个向量方向的差异;机器学习中,借用这一概念来衡量样本向量之间的差异。
- 二维空间中向量A(x1,y1)与向量B(x2,y2)的夹角余弦公式:
- 两个n维样本点a(x11,x12,…,x1n)和b(x21,x22,…,x2n)的夹角余弦为:
即:
夹角余弦取值范围为[-1,1]。余弦越大表示两个向量的夹角越小,余弦越小表示两向量的夹角越大。当两个向量的方向重合时余弦取最大值1,当两个向量的方向完全相反余弦取最小值-1。
举例:
X=[[1,1],[1,2],[2,5],[1,-4]]
经计算得:
d = 0.9487 0.9191 -0.5145 0.9965 -0.7593 -0.8107
3 汉明距离(Hamming Distance)【了解】:
两个等长字符串s1与s2的汉明距离为:将其中一个变为另外一个所需要作的最小字符替换次数。
例如:
The Hamming distance between "1011101" and "1001001" is 2.
The Hamming distance between "2143896" and "2233796" is 3.
The Hamming distance between "toned" and "roses" is 3.
随堂练习:
求下列字符串的汉明距离:
1011101与 1001001
2143896与 2233796
irie与 rise
汉明重量:是字符串相对于同样长度的零字符串的汉明距离,也就是说,它是字符串中非零的元素个数:对于二进制字符串来说,就是 1 的个数,所以 11101 的汉明重量是 4。因此,如果向量空间中的元素a和b之间的汉明距离等于它们汉明重量的差a-b。
应用:汉明重量分析在包括信息论、编码理论、密码学等领域都有应用。比如在信息编码过程中,为了增强容错性,应使得编码间的最小汉明距离尽可能大。但是,如果要比较两个不同长度的字符串,不仅要进行替换,而且要进行插入与删除的运算,在这种场合下,通常使用更加复杂的编辑距离等算法。
举例:
X=[[0,1,1],[1,1,2],[1,5,2]]
注:以下计算方式中,把2个向量之间的汉明距离定义为2个向量不同的分量所占的百分比。
经计算得:
d = 0.6667 1.0000 0.3333
4 杰卡德距离(Jaccard Distance)【了解】:
杰卡德相似系数(Jaccard similarity coefficient):两个集合A和B的交集元素在A,B的并集中所占的比例,称为两个集合的杰卡德相似系数,用符号J(A,B)表示:
杰卡德距离(Jaccard Distance):与杰卡德相似系数相反,用两个集合中不同元素占所有元素的比例来衡量两个集合的区分度:
举例:
X=[[1,1,0],[1,-1,0],[-1,1,0]]
注:以下计算中,把杰卡德距离定义为不同的维度的个数占“非全零维度”的比例
经计算得:
d = 0.5000 0.5000 1.0000
5 马氏距离(Mahalanobis Distance)【了解】
下图有两个正态分布图,它们的均值分别为a和b,但方差不一样,则图中的A点离哪个总体更近?或者说A有更大的概率属于谁?显然,A离左边的更近,A属于左边总体的概率更大,尽管A与a的欧式距离远一些。这就是马氏距离的直观解释。
马氏距离是基于样本分布的一种距离。
马氏距离是由印度统计学家马哈拉诺比斯提出的,表示数据的协方差距离。它是一种有效的计算两个位置样本集的相似度的方法。
与欧式距离不同的是,它考虑到各种特性之间的联系,即独立于测量尺度。
**马氏距离定义:**设总体G为m维总体(考察m个指标),均值向量为μ=(μ1,μ2,… …,μm,)`,协方差阵为∑=(σij),
则样本X=(X1,X2,… …,Xm,)`与总体G的马氏距离定义为:
马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为∑的随机变量的差异程度:如果协方差矩阵为单位矩阵,马氏距离就简化为欧式距离;如果协方差矩阵为对角矩阵,则其也可称为正规化的欧式距离。
马氏距离特性:
1.量纲无关,排除变量之间的相关性的干扰;
2.马氏距离的计算是建立在总体样本的基础上的,如果拿同样的两个样本,放入两个不同的总体中,最后计算得出的两个样本间的马氏距离通常是不相同的,除非这两个总体的协方差矩阵碰巧相同;
3 .计算马氏距离过程中,要求总体样本数大于样本的维数,否则得到的总体样本协方差矩阵逆矩阵不存在,这种情况下,用欧式距离计算即可。
4.还有一种情况,满足了条件总体样本数大于样本的维数,但是协方差矩阵的逆矩阵仍然不存在,比如三个样本点(3,4),(5,6),(7,8),这种情况是因为这三个样本在其所处的二维空间平面内共线。这种情况下,也采用欧式距离计算。
欧式距离&马氏距离:
举例:
已知有两个类G1和G2,比如G1是设备A生产的产品,G2是设备B生产的同类产品。设备A的产品质量高(如考察指标为耐磨度X),其平均耐磨度μ1=80,反映设备精度的方差σ2(1)=0.25;设备B的产品质量稍差,其平均耐磨损度μ2=75,反映设备精度的方差σ2(2)=4.
今有一产品G0,测的耐磨损度X0=78,试判断该产品是哪一台设备生产的?
直观地看,X0与μ1(设备A)的绝对距离近些,按距离最近的原则,是否应把该产品判断设备A生产的?
考虑一种相对于分散性的距离,记X0与G1,G2的相对距离为d1,d2,则:
因为d2=1.5 < d1=4,按这种距离准则,应判断X0为设备B生产的。
设备B生产的产品质量较分散,出现X0为78的可能性较大;而设备A生产的产品质量较集中,出现X0为78的可能性较小。
这种相对于分散性的距离判断就是马氏距离。
1.9 案例2:预测facebook签到位置
学习目标
- 目标
- 通过Facebook位置预测案例熟练掌握第一章学习内容
1 项目描述
本次比赛的目的是预测一个人将要签到的地方。 为了本次比赛,Facebook创建了一个虚拟世界,其中包括10公里*10公里共100平方公里的约10万个地方。 对于给定的坐标集,您的任务将根据用户的位置,准确性和时间戳等预测用户下一次的签到位置。 数据被制作成类似于来自移动设备的位置数据。 请注意:您只能使用提供的数据进行预测。
2 数据集介绍
数据介绍:
文件说明 train.csv, test.csv
row id:签入事件的id
x y:坐标
accuracy: 准确度,定位精度
time: 时间戳
place_id: 签到的位置,这也是你需要预测的内容
官网:https://www.kaggle.com/c/facebook-v-predicting-check-ins
3 步骤分析
- 对于数据做一些基本处理(这里所做的一些处理不一定达到很好的效果,我们只是简单尝试,有些特征我们可以根据一些特征选择的方式去做处理)
- 1 缩小数据集范围 DataFrame.query()
- 2 选取有用的时间特征
- 3 将签到位置少于n个用户的删除
- 分割数据集
- 标准化处理
- k-近邻预测
具体步骤:
# 1.获取数据集
# 2.基本数据处理
# 2.1 缩小数据范围(这个不是处理数据的技巧,只是因为我们的数据集太大了,我们使用了部分数据来做演示)
# 2.2 选择时间特征
# 2.3 去掉签到较少的地方
# 2.4 确定特征值和目标值
# 2.5 分割数据集
# 3.特征工程 -- 特征预处理(标准化)
# 4.机器学习 -- knn+cv
# 5.模型评估
4 代码实现
- 1.获取数据集
# 1、获取数据集
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
facebook = pd.read_csv("./data/train.csv")
- 2.基本数据处理
# 2.基本数据处理
# 2.1 缩小数据范围
#(这个不是处理数据的技巧,只是因为我们的数据集太大了,我们使用了部分数据来做演示)
facebook_data = facebook.query("x>2.0 & x<2.5 & y>2.0 & y<2.5")
# 2.2 选择时间特征
time = pd.to_datetime(facebook_data["time"], unit="s")#将该列数据转换为时间类型
time = pd.DatetimeIndex(time)#将时间类型数据转换为索引格式
facebook_data = facebook_data.copy()
facebook_data["hour"] = time.hour
facebook_data["weekday"] = time.weekday
# 2.3 去掉签到较少的地方(我们可以认为签到少的地方是异常值)
place_count = facebook_data.groupby("place_id").count()
place_count = place_count[place_count["row_id"]>30]
facebook_data = facebook_data[facebook_data["place_id"].isin(place_count.index)]
# 2.4 确定特征值和目标值
x = facebook_data[["x", "y", "accuracy","hour", "weekday"]]
y = facebook_data["place_id"]
# 2.5 分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.1,random_state=22)
- 3.特征工程–特征预处理(标准化)
# 3.特征工程--特征预处理(标准化)
# 3.1 实例化一个转换器
transfer = StandardScaler()
# 3.2 调用fit_transform
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
- 4.机器学习–knn+cv
# 4.机器学习--knn+cv
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier()
# 4.2 调用gridsearchCV
param_grid = {"n_neighbors": [1, 3, 5]}
estimator = GridSearchCV(estimator, param_grid=param_grid, cv=3)
# 4.3 模型训练
estimator.fit(x_train, y_train)
- 5.模型评估
# 5.模型评估
# 5.1 基本评估方式
score = estimator.score(x_test, y_test)
print("最后预测的准确率为:\n", score)
y_predict = estimator.predict(x_test)
print("最后的预测值为:\n", y_predict)
print("预测值和真实值的对比情况:\n", y_predict == y_test)
# 5.2 使用交叉验证后的评估方式
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的验证集准确率结果和训练集准确率结果:\n",estimator.cv_results_)
meIndex(time)#将时间类型数据转换为索引格式
facebook_data = facebook_data.copy()
facebook_data[“hour”] = time.hour
facebook_data[“weekday”] = time.weekday
5 去掉签到较少的地方(我们可以认为签到少的地方是异常值)
place_count = facebook_data.groupby(“place_id”).count()
place_count = place_count[place_count[“row_id”]>30]
facebook_data = facebook_data[facebook_data[“place_id”].isin(place_count.index)]
6 确定特征值和目标值
x = facebook_data[[“x”, “y”, “accuracy”,“hour”, “weekday”]]
y = facebook_data[“place_id”]
7 分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.1,random_state=22)
- 3.特征工程--特征预处理(标准化)
```python
# 3.特征工程--特征预处理(标准化)
# 3.1 实例化一个转换器
transfer = StandardScaler()
# 3.2 调用fit_transform
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
- 4.机器学习–knn+cv
# 4.机器学习--knn+cv
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier()
# 4.2 调用gridsearchCV
param_grid = {"n_neighbors": [1, 3, 5]}
estimator = GridSearchCV(estimator, param_grid=param_grid, cv=3)
# 4.3 模型训练
estimator.fit(x_train, y_train)
- 5.模型评估
# 5.模型评估
# 5.1 基本评估方式
score = estimator.score(x_test, y_test)
print("最后预测的准确率为:\n", score)
y_predict = estimator.predict(x_test)
print("最后的预测值为:\n", y_predict)
print("预测值和真实值的对比情况:\n", y_predict == y_test)
# 5.2 使用交叉验证后的评估方式
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的验证集准确率结果和训练集准确率结果:\n",estimator.cv_results_)