Bootstrap

2024年机器学习算法(1)—— K-近邻算法_k近邻算法k的取值(3),2024京东最新大数据开发面试真题解析

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

print(“鸢尾花的描述:\n”, iris.DESCR)


### 6.2 查看数据分布


通过创建一些图,以查看不同类别是如何通过特征来区分的。 在理想情况下,标签类将由一个或多个特征对完美分隔。 在现实世界中,这种理想情况很少会发生。



from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from pylab import mpl
import seaborn as sns
import pandas as pd

设置显示中文字体

mpl.rcParams[“font.sans-serif”] = [“SimHei”]

iris = load_iris()
iris_data = pd.DataFrame(data=iris.data, columns=[‘Sepal_Length’, ‘Sepal_Width’, ‘Petal_Length’, ‘Petal_Width’])
iris_data[“Species”] = iris.target

def plot_iris(iris, feature_1, feature_2):
sns.lmplot(x=feature_1, y=feature_2, data=iris, hue=“Species”, fit_reg=False)
plt.xlabel(feature_1)
plt.ylabel(feature_2)
plt.title(‘鸢尾花种类分布图’)
plt.show()

plot_iris(iris_data, ‘Petal_Width’, ‘Sepal_Length’)


![在这里插入图片描述](https://img-blog.csdnimg.cn/5ad213c7ce5b4d85abe1e631f3cbff00.png)


### 6.3 划分数据集


机器学习一般的数据集会划分为两个部分:


* 训练数据:用于训练,构建模型
* 测试数据:在模型检验时使用,用于评估模型是否有效


划分比例:


* 训练集:70% 80% 75%
* 测试集:30% 20% 25%


`sklearn.model_selection.train_test_split(arrays, *options)`


* 参数:
	+ x 数据集的特征值
	+ y 数据集的标签值
	+ test\_size 测试集的大小,一般为float
	+ random\_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。类似于np.random.seed()
* 返回值
	+ 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)


## 7 特征工程—特征预处理


特征预处理是特征工程的内容之一,即通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/1dc749b6c0bf4c6d8ac744679a65f583.png)



> 
> 为什么我们要进行归一化/标准化?  
>  特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级,容易影响(支配)目标结果,使得一些算法无法学习到其它的特征。要保证每一个特征同等重要。
> 
> 
> 


特征预处理API`sklearn.preprocessing`


我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格


* 归一化
* 标准化


### 7.1 归一化


通过对原始数据进行变换把数据映射到(**默认为[0,1]**)之间。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/ed50a89573c5443881830219097d2323.png)



> 
> 作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0
> 
> 
> 


`sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )`


* MinMaxScalar.fit\_transform(X)
	+ X:numpy array格式的数据[n\_samples,n\_features]
* 返回值:转换后的形状相同的array


**归一化案例**


`dating.txt`数据有三个特征值:milage,Liters,Consumtime,一个目标值target



> 
> data.txt 数据集分享:https://pan.baidu.com/s/1NzzqTk2lZtpAh7cdvFoYSg?pwd=dx7t
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/40a20ef79a434ed3803686d36fccc7e0.png)



import pandas as pd
from sklearn.preprocessing import MinMaxScaler

def minmax_demo():
“”"
归一化演示
:return: None
“”"
data = pd.read_csv(“./dating.txt”)
print(data)
# 1、实例化一个转换器类MinMaxScaler
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
4 38344 1.669788 0.134296 1
… … … … …
995 11145 3.410627 0.631838 2
996 68846 9.974715 0.669787 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]
最小值最大值归一化处理的结果:
[[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]]
“”"


![在这里插入图片描述](https://img-blog.csdnimg.cn/5f51c74765174b729fe3bf354e127b8a.png)



> 
> 注意:最大值最小值是变化的,另外,最大值与最小值非常**容易受异常点影响**,所以这种方法**鲁棒性**(确定性、稳定性)较差,只适合**传统精确小数据**场景。
> 
> 
> 


### 7.2 标准化


通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/3c4752058d7440f098d23c6b66ef5912.png)



> 
> 作用于每一列,mean为平均值,σ为标准差
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/db539ef5fe734676b11c6af4de0e46ad.png)


* 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
* 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。


**标椎化案例**


`sklearn.preprocessing.StandardScaler( )`


* 处理之后每列来说所有数据都聚集在均值0附近标准差差为1
* StandardScaler.fit\_transform(X)
	+ X:numpy array格式的数据[n\_samples,n\_features]
* 返回值:转换后的形状相同的array



import pandas as pd
from sklearn.preprocessing import StandardScaler

def stand_demo():
“”"
标准化演示
:return: None
“”"
data = pd.read_csv(“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

stand_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
4 38344 1.669788 0.134296 1
… … … … …
995 11145 3.410627 0.631838 2
996 68846 9.974715 0.669787 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]

“”"



> 
> 在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。
> 
> 
> 


### 7.3 案例分析


**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分割样本空间,每个节点是一个超球体。



“”"
1.获取数据集
2.数据基本处理
3.特征工程
4.机器学习(模型训练)
5.模型评估
“”"
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

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) # 训练集使用fit_transform
x_test = transfer.transform(x_test) # 测试集使用transform

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)



> 
> 注意:
> 
> 
> * fit和transform没有任何关系,仅仅是数据处理的两个不同环节
> 	+ fit():简单来说,就是求得训练集X的均值,方差,最大值,最小值等
> 	+ transform():在fit的基础上,对数据进行标准化、降维、归一化等转换操作
> * 我们在训练集上调用fit\_transform(),其实找到了均值μ和方差σ^2,即我们已经找到了转换规则,我们把这个规则利用在训练集上,同样,我们可以直接将其运用到测试集上(甚至交叉验证集),所以在测试集上的处理,我们只需要标准化数据而不需要再次拟合数据。
> 
> 
> 


## 8 交叉验证(选取最优k)


### 8.1 什么是交叉验证


交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成10份,其中一份作为验证集。然后经过10次(组)的测试,每次都更换不同的验证集。即得到10组模型的结果,取**平均值**作为最终结果。又称10折交叉验证。


交叉验证目的:为了让被评估的模型更加可信,但是无法提高模型的准确率



> 
> 我们之前知道数据分为训练集和测试集,但是为了让从训练得到模型结果更加准确。做以下处理
> 
> 
> * 训练集:训练集+验证集
> * 测试集:测试集
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/22aede9768cc41558f182d4664a8e24f.png)  
 问题:这个只是让被评估的模型更加准确可信,那么怎么选择或者调优参数呢?


### 8.2 模型选择与调优


**网格搜索**:通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。简单来说,网格搜索就是把超参数的值,通过字典的形式传递进去,然后进行选择最优值  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/320d117082504e9d918c0b507bab0386.png)


### 8.3 增加K值调优案例


`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:每次交叉验证后的验证集准确率结果和训练集准确率结果



from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

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) # a【0.9473684210526315】

print(“在交叉验证中验证的最好结果:\n”, estimator.best_score_) # b【0.9732100521574205】
print(“最好的参数模型:\n”, estimator.best_estimator_)
print(“每次交叉验证后的准确率结果:\n”, estimator.cv_results_)



> 
> 问:以上代码中a,b的值为什么不一样?  
>  答:交叉验证的数据都是训练集数据,而直接计算准确率用的是训练集+测试集数据
> 
> 
> 


## 9 综合案例


### 9.1 案例描述


本次比赛的目的是**预测一个人将要签到的地方**。 为了本次比赛,Facebook创建了一个虚拟世界,其中包括10公里\*10公里共100平方公里的约10万个地方。 对于给定的坐标集,您的任务将根据用户的位置,准确性和时间戳等预测用户下一次的签到位置。 数据被制作成类似于来自移动设备的位置数据。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/8cf6e7945ed745fdbc667cf4e1b487d7.png)


### 9.2 数据集介绍



> 
> 数据来源:https://www.kaggle.com/c/facebook-v-predicting-check-ins
> 
> 
> 注意:在点击以上网址获取数据集时,kaggle平台新用户注册出现“Captcha must be filled out”问题,解决办法参考:https://blog.csdn.net/m0\_45447650/article/details/125853986
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/0e1e1bc2aa3244fb861b5f6db0d7a9dd.png#pic_center)  
 文件说明 train.csv 训练集,包含特征值和签到位置的标签(目标值),test.csv 测试集,只包含特征值


* row id:签入事件的id,一条数据的唯一标识(无效特征值)
* x y:坐标,单位 km
* accuracy: 准确度,定位精度单位 m
* time: 时间戳,单位 s
* place\_id: 签到的位置,这也是你需要预测的内容


### 9.3 步骤分析


* 对于数据做一些基本处理(这里所做的一些处理不一定达到很好的效果,我们只是简单尝试,有些特征我们可以根据一些特征选择的方式去做处理)
	+ 缩小数据集范围 (这样会降低预测的准确性,这样做只是为了方便演示,实际开发不需要)
	+ 选取有用的时间特征
	+ 将签到位置少于n个用户的删除
* 分割数据集
* 标准化处理
* k-近邻预测


### 9.4 代码实现



from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

1.获取数据集

facebook = pd.read_csv(“./data/FBlocation/train.csv”)

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[“day”] = time.day
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”]>3]
facebook_data = facebook_data[facebook_data[“place_id”].isin(place_count.index)]

2.4 确定特征值和目标值

x = facebook_data[[“x”, “y”, “accuracy”, “day”, “hour”, “weekday”]]
y = facebook_data[“place_id”]

2.5 分割数据集

x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=22)

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.1 实例化一个估计器

estimator = KNeighborsClassifier()

4.2 调用gridsearchCV

param_grid = {“n_neighbors”: [1, 3, 5, 7, 9]}
estimator = GridSearchCV(estimator, param_grid=param_grid, cv=5)

4.3 模型训练

estimator.fit(x_train, y_train)

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_)


## 10 KNN算法总结


k近邻算法优缺点


1. 优点


* 简单有效
* 重新训练的代价低(不需要保存模型)
* 适合类域交叉样本
	+ KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
* 适合大样本自动分类
	+ 该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。


类域交叉举例:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/ad9b0e443c5d4d79a374f962dbc16efd.png)  
 2. 缺点


* 惰性学习
	+ KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多
* 类别评分不是规格化
	+ 不像一些通过概率评分的分类
* 输出可解释性不强
	+ 例如决策树的输出可解释性就较强
* 对不均衡的样本不擅长
	+ 当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
* 计算量较大
	+ 目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。



![img](https://img-blog.csdnimg.cn/img_convert/373adabdaa9f72563350b39576cf4925.png)
![img](https://img-blog.csdnimg.cn/img_convert/daee0d06671ae92ace2f985ee1e93a29.png)
![img](https://img-blog.csdnimg.cn/img_convert/24805bfa83ad94cea225bbd8234997ab.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

一些通过概率评分的分类
* 输出可解释性不强
	+ 例如决策树的输出可解释性就较强
* 对不均衡的样本不擅长
	+ 当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
* 计算量较大
	+ 目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。



[外链图片转存中...(img-zUuSFxHq-1715313546772)]
[外链图片转存中...(img-48SxeL6s-1715313546772)]
[外链图片转存中...(img-lckuprYi-1715313546772)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

;