01 K-近邻算法介绍与实现
关键词:人工智能, 算法
1. 算法简介1.1 距离公式1.2 K值的选择1.3 其它概念2. 实例:鸢尾花种类预测
1. 算法简介
核心理念:根据你的邻居来推断出你的类别。
定义: 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
简单讲就是定义一组变量描述一个类,定义一种距离计算公式描述各个实例之间的差异大小,如果被推测的实例与某些已知目标值的实例最近(距离公式最短等),那么则仍为被推测实例的目标值也是该值。
K 近邻算法使用的模型实际上对应于对特征空间的划分。距离度量、K 值的选择和分类决策规则是该算法的三个基本要素。
适用范围: 字符识别、文本分类、图像识别等领域。
实现流程:
计算已知类别数据集中点与当前点之间的距离。
按距离递增次序排序。
选取与当前点距离最小的k个点。
统计前k个点所在的类别出现的频率。
返回前k个点出现频率最高的类别作为当前点的预测分类。
1.1 距离公式
距离公式在k近邻算法中扮演着至关重要的角色,直接影响最终预测结果。常见的距离公式有:
欧式距离
曼哈顿距离
契比雪夫距离
闵可夫斯基距离
上述四种距离计算公式,都将各分量的量纲忽略了,也没有考虑各分量的分布。
标准化欧式距离
余弦距离
向量夹角的余弦值,越接近与+1表明夹角越小,越接近于-1表明夹角越大。汉明距离
两个等长字符串s1与s2的汉明距离为:将其中一个变为另外一个所需要做的最小字符替换次数。
字符串或变量在计算集中表示为二进制后,非零位个数的差值。Jaccard Distance
距离算法简介Mahalanobis Distance
距离算法简介
1.2 K值的选择
k值的作用:少数服从多数,k值决定选民多少
如果K=3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
如果K=5,绿色圆点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。
K 值的选择会对算法的结果产生重大影响。K值较小意味着只有与输入实例较近的训练实例才会对预测结果起作用,但容易发生过拟合;如果 K 值较大,优点是可以减少学习的估计误差,但缺点是学习的近似误差增大,这时与输入实例较远的训练实例也会对预测起作用,使预测发生错误。在实际应用中,K 值一般选择一个较小的数值,通常采用交叉验证的方法来选择最优的 K 值。随着训练实例数目趋向于无穷和 K=1 时,误差率不会超过贝叶斯误差率的2倍,如果K也趋向于无穷,则误差率趋向于贝叶斯误差率。
总结:k值过小容易收到异常点影响;k值过大收到样本均衡的问题。
k值一般选择个位的奇数,如 3、5、7、9。
近似误差: 过拟合,在训练集上表现好,测试集表现不好。
估计误差: 估计误差好才是真的好
1.3 其它概念
kd树:
用于在模型中快速找到预测点的近邻。
原理:A和B的距离很近,B和C的距离很远,那么A和C的距离也很远。
树的建立:先选择方差大维度进行分隔,然后选另一维度,循环往复
交叉验证:
首先将数据集分成训练集、验证集
训练集再分为训练集、测试集
首先用训练集进行训练、然后用测试集测试准确率。
作用:保证准确率更加可信,但不能提高模型的准确性。
特征预处理的常用方法
归一化法:通过对原始数据进行变换把数据映射到(默认为[0,1])之间。
最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。标准化:通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内。
如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。
标准化在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。
2. 实例:鸢尾花种类预测
鸢尾花案例
鸢尾花数据集:特征值4个:萼片长度、萼片宽度、花瓣长度、花瓣宽度;目标值1个:莺尾花的种类(共计3类)
数据集:
实例数150个,三类各有50个
第一步:从sklearn中获取数据集
1import seaborn as sns
2import matplotlib.pyplot as plt
3import pandas as pd
4from sklearn.datasets import load_iris
5# 获取鸢尾花数据集
6iris = load_iris()
7# 可视化数据,判断特征值是否可以将类别分开
8# 把数据转换成dataframe的格式
9iris_d = pd.DataFrame(iris["data"], columns=iris.feature_names)
10iris_d["Species"] = iris.target
11
12%matplotlib inline
13
14
15def plot_iris(iris, col1, col2):
16 sns.lmplot(x=col1, y=col2, data=iris, hue="Species", fit_reg=False)
17 plt.xlabel(col1)
18 plt.ylabel(col2)
19 plt.show()
20
21
22# 常看各个特征之间的关系
23plot_iris(iris_d, iris.feature_names[0], iris.feature_names[2])
24# plot_iris(iris_d,iris.feature_names[0],iris.feature_names[3])
25# plot_iris(iris_d,iris.feature_names[1],iris.feature_names[2])
26# plot_iris(iris_d,iris.feature_names[1],iris.feature_names[3])
27# plot_iris(iris_d,iris.feature_names[2],iris.feature_names[3])
第二步:数据集划分
1from sklearn.model_selection import train_test_split
2# random_state 是随机数种子;test_size 是测试集所占的比例
3x_train, x_test, y_train, y_test = train_test_split(
4 iris.data, iris.target, random_state=20, test_size=0.2)
第三步:特征工程,数据标准化
1from sklearn.preprocessing import StandardScaler
2transfer = StandardScaler()
3# 找出训练集数据的均值、方差,并保存在tansfer中,供后续标准化使用。
4x_train = transfer.fit_transform(x_train)
5print(f"训练数据集的均值是:{transfer.mean_}")
6print(f"训练数据集的标准差是:{transfer.var_}")
7# 使用训练数据集的均值、方差转换测试数据集
8x_test = transfer.transform(x_test)
1训练数据集的均值是:[5.82833333 3.1 3.71333333 1.19833333]
2训练数据集的标准差是:[0.67436389 0.19883333 3.13398889 0.59749722]
第四步:机器学习训练模型
1from sklearn.model_selection import GridSearchCV
2from sklearn.neiors import KNeiorsClassifier
3estimator_0 = KNeiorsClassifier()
4# 模型选择与调优——网格搜索和交叉验证
5# 定义要优化的参数可取值范围
6param_dict = {"n_neiors": [1, 3, 5, 7]}
7# 定义交叉验证的次数cv等
8estimator = GridSearchCV(estimator_0, param_grid=param_dict, cv=3)
9# 训练
10estimator.fit(x_train, y_train)
11# 输出交叉验证结果
12print("交叉验证中最好的结果:\n", estimator.best_score_)
13print("交叉验证中最好的参数:\n", estimator.best_estimator_)
14print("每次交叉验证的准确率结果:\n", estimator.cv_results_)
1交叉验证中最好的结果:
2 0.975
3交叉验证中最好的参数:
4 KNeiorsClassifier(n_neiors=7)
5每次交叉验证的准确率结果:
6 {'mean_fit_time': array([0.00099572, 0.00066511, 0.00033236, 0.00033259]), 'std_fit_time': array([3.64363778e-06, 4.70304900e-04, 4.70021655e-04, 4.70358829e-04]), 'mean_score_time': array([0.00299184, 0.0020051 , 0.00198833, 0.0033323 ]), 'std_score_time': array([8.14490846e-04, 1.41827329e-05, 8.06420792e-04, 1.23373824e-03]), 'param_n_neiors': masked_array(data=[1, 3, 5, 7],
7 mask=[False, False, False, False],
8 fill_value='?',
9 dtype=object), 'params': [{'n_neiors': 1}, {'n_neiors': 3}, {'n_neiors': 5}, {'n_neiors': 7}], 'split0_test_score': array([0.95, 0.95, 0.95, 0.95]), 'split1_test_score': array([0.925, 0.975, 0.975, 1. ]), 'split2_test_score': array([0.975, 0.975, 0.975, 0.975]), 'mean_test_score': array([0.95 , 0.96666667, 0.96666667, 0.975 ]), 'std_test_score': array([0.02041241, 0.01178511, 0.01178511, 0.02041241]), 'rank_test_score': array([4, 2, 2, 1])}
第五步:模型评估
1# 方法一:对比真实值和预测值
2print("对比结果为:\n", y_test == estimator.predict(x_test))
3
4# 方法二:直接计算准确率
5score = estimator.score(x_test, y_test)
6print("准确率为:", score)
1对比结果为:
2 [ True True True True True True True True True True True True
3 False True True True True True True True True True True True
4 True True True True True False]
5准确率为: 0.9333333333333333
查看更多评论 >