一、KNN算法

一、KNN算法

1.1 概述

  • KNN(全称K Nearest Neighbors)可以说是最简单的分类算法之一,同时,它也是最常用的分类算法之一。

  • 原理是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别,如图:

    KNN原理1

绿色的点就是我们要预测的那个点,假设K=3。那么KNN算法就会找到与它距离最近的三个点(这里用圆圈把它圈起来了),看看哪种类别多一些,比如这个例子中是蓝色三角形多一些,新来的绿色点就归类到蓝三角了。

当K=5的时候,判定就变成不一样了。这次变成红圆多一些,所以新来的绿点被归类成红圆。从这个例子中,我们就能看得出K的取值是很重要的。

KNN原理2

1.2 细节

​ 影响以上算法的有三个因素:K值的选取距离的确定距离的权重

1.2.1 K值的选取

​ 根据上面的图可以知道K值的选取决定决策的结果,但是具体选哪个K值没有相应的理论。

​ 如果k值比较小,相当于我们在较小的领域内训练样本对实例进行预测。这时,算法的近似误差(Approximate Error)会比较小,因为只有与输入实例相近的训练样本才会对预测结果起作用。

​ 但是,它也有明显的缺点:算法的估计误差比较大,预测结果会对近邻点十分敏感,也就是说,如果近邻点是噪声点的话,预测就会出错。因此,k值过小容易导致KNN算法的过拟合。

​ 同理,如果k值选择较大的话,距离较远的训练样本也能够对实例预测结果产生影响。这时候,模型相对比较鲁棒,不会因为个别噪声点对最终预测结果产生影响。但是缺点也十分明显:算法的近邻误差会偏大,距离较远的点(与预测实例不相似)也会同样对预测结果产生影响,使得预测结果产生较大偏差,此时模型容易发生欠拟合。
​ 一般是采用交叉验证的方式选取一个比较理想的K值。

1.2.2 距离的确定

​ 样本空间内的两个点之间的距离量度表示两个样本点之间的相似程度:距离越短,表示相似程度越高;反之,相似程度越低。

闵可夫斯基距离

​ 对于n维空间中的两个点 x = ( x 1 , x 2 , … , x n ) T x=(x_1,x_2,…,x_n)^T x=(x1,x2,,xn)T y = ( y 1 , y 2 , ⋯   , y n ) T y=(y_1,y_2,\cdots,y_n)^T y=(y1,y2,,yn)T x x x y y y之间的闵可夫斯基距离可以表示为:
d x y = ( ∑ i = 1 n ( x i − y i ) p ) 1 p d_{xy}=(\sum_{i=1}^n (x_i-y_i)^p)^{\frac{1}{p}} dxy=(i=1n(xiyi)p)p1
​ 其中,p是一个可变参数:

  • 当p=1时,被称为曼哈顿距离;

  • 当p=2时,被称为欧氏距离;

  • 当p= ∞ \infty 时,被称为切比雪夫距离。

1.2.3 距离的权重

​ 当确定好距离后,要判断输入变量 x x x所属的类 y y y,就要找出距离 x x x最近的 k k k个点,用 N k ( x ) N_k(x) Nk(x)表示这 k k k个点,通常来说,这 k k k个点中哪一类的最多, x x x就属于哪一类。这种思考意味着不论远近, N k ( x ) N_k(x) Nk(x)中所有的点对判断 x x x属于哪一类的影响都一样。

​ 但实际中,距离的远近对 x x x的影响还是有区别的,又是距离更近的点更加重要。一般情况下设置权重和距离成反比,距离预测目标越近具有越高的权重。然后计算每一类所占的权重。

1.3 代码实现

接下来利用代码实现一个简单的KNN算法。

  • 生成数据:

    import numpy as np
    import matplotlib.pyplot as plt
    
    X_1=np.random.normal(0,2,(50,2))
    X_2=np.random.normal(0,4,(50,2))
    
    plt.scatter(X_1[:,0],X_1[:,1])
    plt.scatter(X_2[:,0],X_2[:,1])
    

在这里插入图片描述

  • 整合数据,划分训练集和测试集

    #整合数据
    y=np.repeat([0,1],50)
    X=np.vstack([X_1,X_2])
    #划分训练集和测试集
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test =train_test_split(X, y, random_state=2022,test_size=0.2, shuffle=True)
    

    关于train_test_split文档

  • 根据训练集中的数据预测测试集中的标签,并和真实标签进行比较。

    #定义距离函数,仅用简单的欧式距离
    def getDistance(x,y):
        
        return np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)
    
    def kNN(X_train,y_train,X_test,y_test,K):
        indexs=[]
        distances=[]
        y_test_hats=[]
        for i in np.arange(len(X_test)):
            for j in np.arange(len(X_train)):
                d=getDistance(X_test[i],X_train[j])
                if(len(indexs)==7):
                    if(d<np.argmax(distances)):
                        index=np.argmax(distances)
                        indexs[index]=j
                        distances[index]=d
                else:
                    indexs.append(j)
                    distances.append(d)
            y_s=y_train[index]
            #投票表决
            y_test_hat=0 if np.sum(y_s==0)>np.sum(y_s==1) else 1 
            y_test_hats.append(y_test_hat)
        accuracy=np.sum(y_test_hats==y_test)/len(y_test_hats)
        return (accuracy,y_test_hats)
    accuracy,y_test_hats=kNN(X_train,y_train,X_test,y_test,3)
    print(accuracy)#0.65
    

1.4 sklearn包中的KNN算法

​ 在sklearn库中,KNeighborsClassifier是实现K近邻算法的一个类。

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, *, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', metric_params=None, n_jobs=None, **kwargs)

参数说明
n_neighborsint, default=5 默认情况下用于kneighbors查询的近邻数
weights{‘uniform’, ‘distance’} or callable, default=’uniform’ 预测中使用的权重函数。 可能的值: “uniform”:统一权重。 每个邻域中的所有点均被加权。 “distance”:权重点与其距离的倒数。 在这种情况下,查询点的近邻比远处的近邻具有更大的影响力。 [callable]:用户定义的函数,该函数接受距离数组,并返回包含权重的相同形状的数组。
algorithm{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’ 用于计算最近临近点的算法: “ ball_tree”将使用BallTree kd_tree”将使用KDTree “brute”将使用暴力搜索。 “auto”将尝试根据传递给fit方法的值来决定最合适的算法。 注意:在稀疏输入上进行拟合将使用蛮力覆盖此参数的设置。
leaf_sizeint, default=30 叶大小传递给BallTree或KDTree。 这会影响构造和查询的速度,以及存储树所需的内存。 最佳值取决于问题的性质。
pint, default=2 Minkowski指标的功率参数。 当p = 1时,这等效于对p = 2使用manhattan_distance(l1)和euclidean_distance(l2)。对于任意p,使用minkowski_distance(l_p)。
metricstr or callable, default=’minkowski’ 树使用的距离度量。 默认度量标准为minkowski,p = 2等于标准欧几里德度量标准。 有关可用度量的列表,请参见DistanceMetric的文档。 如果度量是“预先计算的”,则X被假定为距离矩阵,并且在拟合过程中必须为平方。 X可能是一个稀疏图,在这种情况下,只有“非零”元素可以被视为临近点。
metric_paramsdict, default=None 度量功能的其他关键字参数。
n_jobsint, default=None 为临近点搜索运行的并行作业数。 除非在joblib.parallel_backend上下文中,否则None表示1。 -1表示使用所有处理器。 有关更多详细信息,请参见词汇表。 不会影响拟合方法。

对象方法:

方法说明
fit(, X, y)使用X作为训练数据和y作为目标值拟合模型
get_params([, deep])获取此估计量的参数。
kneighbors([, X, n_neighbors, …])查找点的K临近点。
kneighbors_graph([, X, n_neighbors, mode])计算X中点的k临近点的(加权)图
predict(, X)预测提供的数据的类标签。
predict_proba(, X)测试数据X的返回概率估计。
score(, X, y[, sample_weight])返回给定测试数据和标签上的平均准确度。
set_params(, **params)设置此估算器的参数。

其他详见官方文档。

通过调用相关函数实现KNN算法:

from sklearn.datasets import load_iris
dataset=load_iris()
X=dataset.data
y=dataset.target
X_train, X_test, y_train, y_test =train_test_split(X, y, random_state=2022,test_size=0.2, shuffle=True)

from sklearn.neighbors import KNeighborsClassifier
knc=KNeighborsClassifier(n_neighbors=3)
knc.fit(X_train,y_train)
knc.score(X_test,y_test)#0.9666666666666667

1.5 交叉验证

  • 交叉验证(Cross Validation)用来验证分类器的性能一种统计分析方法,基本思想是把在某种意义下降原始数据(dataset)进行分组,一部分用来为训练集(train set),另一部分做为验证集(validation set)。利用训练集训练分类器,然后利用验证集验证模型,记录最后的分类准确率为此分类器的性能指标。
  • 使用交叉验证的方式可以防止在搜索最优参数的过程中在测试集也也发生了过拟合。通过交叉验证,测试集仅仅参与了最终的验证。
from sklearn.model_selection import cross_val_score
scores = cross_val_score(knc, X_train, X_test, cv=5)
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

1.6 网格搜索

​ 由于 K的不同,度量方式的不同,权重选择的不同,对KNN算法的准确度均有影响,如何选择一组最优的配置,sklearn提供了网格搜索的算法。

sklearn.model_selection.GridSearchCV(estimator, param_grid, *, scoring=None, n_jobs=None, iid='deprecated', refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score=nan, return_train_score=False)

常见参数:

参数说明
estimator提供一个基于scikit-learn的估计器接口。估计器需要提供score功能,或者必须通过scoring
param_griddict or list of dictionaries 以参数名称(str)作为键,将参数设置列表尝试作为值的字典,或此类字典的列表,在这种情况下,将探索列表中每个字典所跨越的网格。这样可以搜索任何顺序的参数设置。
scoringstr, callable, list/tuple or dict, default=None 估计器评分指标
n_jobsint, default=None 要并行运行的CPU内核数。 None除非在joblib.parallel_backend环境中,否则表示1 。 -1表示使用所有处理器。
pre_dispatchint, or str, default=n_jobs 控制在并行执行期间分派的CPU内核数。
cvint, cross-validation generator or an iterable, default=None 确定交叉验证切分策略。可以输入: -None,默认使用5折交叉验证 -integer,用于指定在(Stratified)KFold中的折叠次数 -CV splitter -一个输出训练集和测试集切分为索引数组的迭代。 对于integer或None,如果估计器是分类器,并且y是二分类或多分类,使用StratifiedKFold。在所有其他情况下,使用KFold。 有关可在此处使用的各种交叉验证策略,请参阅用户指南在0.22版本中:cv为“None”时,默认值从3折更改为5折
verboseinteger 打印的日志详细程度:值越高,消息越丰富。
from sklearn.model_selection import GridSearchCV
param_grid = [
    {
        'weights':['uniform'],
        'n_neighbors':[i for i in range(1, 11)]
    },
    {
        'weights':['distance'],
        'n_neighbors':[i for i in range(1, 11)],
        'p':[i for i in range(1, 6)]
    }
]
knc=KNeighborsClassifier()
grid_search = GridSearchCV(knc, param_grid, n_jobs = -1, verbose = 2)
grid_search.fit(X_train,y_train)

grid_search.best_score_#查看最佳分数
grid_search.best_params_#查看最优参数配置
best_knc=grid_search.best_estimator_#获取最加配置对应的估计器
best_knc.predict(X_test)
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 一种常见的 KNN 算法改进方法是采用加权 KNN 算法。在加权 KNN 算法中,预测的类别不仅取决于最近的 K 个邻居的类别,还取决于它们与测试点的距离。因此,距离测试点较近的邻居会对预测结果产生更大的影响。 另一种改进算法是采用基于核函数的 KNN 算法,其中使用核函数来计算邻居与测试点之间的相似度。核函数可以将原始数据映射到高维空间中,在高维空间中可能更容易分类。 还有一种改进算法是采用降维算法来减少数据的维数,从而加速 KNN 算法的运行。例如,使用主成分分析(PCA)算法可以将高维数据降到低维空间中。 总之,这些改进算法都是为了提高 KNN 算法的准确性和效率。 ### 回答2: 改进的KNN算法可以结合以下几个方面进行优化: 1. 特征选择:选择具有较高重要性的特征可以提高算法的准确性和效率。可以通过特征选择算法或领域知识来确定最相关的特征,减少冗余特征的影响。 2. 距离权重:传统的KNN算法中,所有邻居样本的权重都一样。改进的算法可以引入距离权重,根据距离远近来调整样本的权重。可以使用如反距离权重或高斯权重等方法,使得距离较近的样本对分类结果的贡献更大。 3. 近邻数量选择:选择合适的近邻数量可以影响算法的准确性。过少的近邻可能忽略了重要信息,而过多的近邻可能包含了冗余信息。可以通过交叉验证或网格搜索等方法来选择最优的近邻数量。 4. KD树:KD树是一种用于优化KNN算法的数据结构。它通过将数据点递归分割为高维空间中的超矩形,从而减少计算距离的次数。使用KD树可以加速KNN算法,特别是在高维数据集上。 5. 并行计算:KNN算法中的每个测试样本都需要计算其与训练样本的距离,这可以通过并行计算来加速。可以使用并行计算的技术,如多线程或分布式计算,来提高算法的效率。 总结起来,改进的KNN算法可以通过特征选择、距离权重、近邻数量选择、KD树和并行计算等方法来提高算法的准确性和效率,适用于更广泛的应用场景。 ### 回答3: KNN算法是一种常用的分类与回归的机器学习算法。该算法的改进主要集中在以下几个方面: 1. 距离度量方法改进:传统的KNN算法中,常用的距离度量方法是欧氏距离。改进算法中,可以采用其他更加适应具体问题的距离度量方法,如曼哈顿距离、切比雪夫距离等,以获得更准确的分类结果。 2. 特征选择和降维:对于高维特征空间的数据集,传统的KNN算法可能会受到特征冗余和维度灾难的困扰。改进算法中,可以借助特征选择或降维方法,选择最具有区分性的特征或通过主成分分析等方法减少特征的维度,提高算法效果和运行效率。 3. K值的选择:KNN算法中的K值是一个重要的参数,它决定了邻居样本的数量。传统的KNN算法中,K通常采用经验法则或交叉验证的方式进行选择。改进算法可以采用自适应的K值选择方法,根据不同的数据集自动选择最优的K值,提高算法的适应性。 4. 加权KNN算法:传统的KNN算法中,对于K个邻居样本,每个样本的权重都是相等的。改进算法中,可以引入加权KNN算法,根据邻居样本与待分类样本之间的距离远近对其进行权重分配,较近的邻居样本具有较大的权重,较远的邻居样本具有较小的权重,从而更加准确地进行分类。 5. 使用KD树或球树:当处理大规模数据集时,传统的KNN算法可能会面临高计算复杂度的问题。改进算法中,可以采用KD树或球树等数据结构来加速最近邻搜索过程,从而提高算法的效率。 综上所述,KNN算法的改进可从距离度量方法、特征选择和降维、K值的选择、加权KNN算法和使用KD树或球树等方面进行。这些改进方法能够提高KNN算法的准确性、适应性和效率,使其成为更加强大的机器学习算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bestwangyulu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值