优化KNN算法

 前言

一、KNN重要的参数

二、使用步骤

1.优化KNN算法

2.数据预处理

3 sklearn调用KNeighborsClassifier

4 调用封装好的优化knn类

5 进行可视化

总结​​​​​​​


前言

读者可看此文章,为复现的knn算法

python实现KNN算法_AGuiRong的博客-CSDN博客

该文章为针对复现的knn算法进行优化。

一、KNN重要的参数

KNN(k-nearest neighbors)算法是一种基于实例的监督学习算法,其中最重要的参数包括:

  1. k 值:k 值表示在预测阶段选择的最近邻居的数量。较小的 k 值会使模型更加敏感,容易受到噪声的影响,而较大的 k 值则可能忽略类别之间的细微差异。选择合适的 k 值需要根据具体问题进行调优。

  2. 距离度量方法:KNN 根据实例之间的距离来计算最近邻。常用的距离度量方法包括欧式距离、曼哈顿距离、闵可夫斯基距离等。不同的距离度量方法对结果可能会有影响,因此需要根据数据特点和问题选择合适的距离度量方法。

  3. 特征权重:在计算距离时,可以为不同的特征赋予不同的权重。这个权重可以根据特征的重要性来设定,以便更好地区分样本。

  4. 决策规则:当确定了最近邻的标签后,需要决定最终的预测标签。常见的决策规则包括多数表决法、加权表决法等。在多数表决法中,选择最近邻中出现次数最多的类别作为预测结果;在加权表决法中,根据最近邻的距离,对每个样本赋予不同的权重来进行表决。

除了上述参数外,还有一些其他的参数可以调整,如数据预处理方法、特征选择方法等,这些也会对 KNN 算法的性能产生影响。

需要注意的是,KNN 算法对于异常值敏感,对数据集规模和维度要求较高。因此在使用 KNN 算法时,需要根据具体情况仔细选择参数,同时进行数据预处理和特征工程,以获得更好的性能。

在本文中考虑的参数为K值和距离度量方法。

二、使用步骤

1.优化KNN算法

class KNN(): 
    def __init__(self,k=2,ord=2):
        self.k = k 
        self.ord = ord 



    def plot_ord(self,ord=-1): # 固定参数ord,KNN 模型准确率随 k 值变化的曲线
        if ord==-1:
            ord=self.ord 

        plt.plot(self.k_range, self.accuracy_scores[ord,:])
        plt.xlabel('k')
        plt.ylabel('准确率')
        plt.title('ord={} k值变化的曲线'.format(ord))
        plt.show()
    
    def plot_k(self,k=-1): # 固定参数k,KNN 模型准确率随 ord 值变化的曲线
        if k==-1:
            k=self.k

        plt.plot(self.ord_range, self.accuracy_scores[:,k])
        plt.xlabel('ord')
        plt.ylabel('准确率')
        plt.title('k={} 准确率随ord 值变化的曲线'.format(k))
        plt.show()

    def sub_train_test(self,train_index,test_index):
        sub_x_train = self.x_train[train_index,:]
        sub_y_train = self.y_train[train_index,:]
        sub_x_test = self.x_train[test_index,:]
        sub_y_test = self.y_train[test_index,:]
        return sub_x_train,sub_y_train,sub_x_test,sub_y_test

    def get_Optimal_k_ord(self):

        self.accuracy_scores = np.zeros((len(self.ord_range),len(self.k_range)))
        skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=3220822)


        for i,ord in enumerate(self.ord_range):
            self.ord = ord 
            for j,k in enumerate(self.k_range):
                self.k = k 
                scores = []
                for indexk,(train_index, test_index) in enumerate(skf.split(self.x_train, self.y_train)):
                    sub_x_train,sub_y_train,sub_x_test,sub_y_test = self.sub_train_test(train_index, test_index)
                    sub_predict = self.predict(sub_x_test,sub_x_train,sub_y_train)
                    accuracy = accuracy_score(sub_y_test, sub_predict)
                    scores.append(accuracy)
                self.accuracy_scores[i][j] = np.mean(scores)
        max_index = np.argmax(self.accuracy_scores)
        row_index, col_index = np.unravel_index(max_index, self.accuracy_scores.shape)

        self.ord = self.ord_range[row_index]
        self.k   = self.k_range[col_index]

    def fit(self,x_train,y_train,k_range=[1,2,3, 5, 7, 9, 11],ord_range=[1,2,3,4,5,10]):
        self.x_train = x_train
        self.y_train = y_train
        self.k_range = k_range
        self.ord_range = ord_range

        # 涉及到的操作都是numpy类型
        if type(self.x_train) != np.ndarray:
            self.x_train = np.array(self.x_train)
        if type(self.y_train) != np.ndarray:
            self.y_train = np.array(self.y_train)
        if len(self.y_train.shape)==1:  # 维度进行延伸
            self.y_train = np.expand_dims(self.y_train, axis=1)
        
        # 采用方法,确定最优k值,ord值
        self.get_Optimal_k_ord()


    # 计算的是data2中每一行数据与data1所有数据之间的各种距离,且用distances保存
    # data2:k行m列
    # data1:n行m列
    # distances:k行n列
    def calculate_distances(self,dataset1,dataset2,ord):        # 默认使用欧式距离
        distances = np.zeros((len(dataset2), len(dataset1)))       # 初始化距离矩阵
        for i in range(len(dataset2)):
            distances[i] = np.linalg.norm(dataset1 - dataset2[i], axis=1,ord=ord)
        return distances
    

    def predict(self,x_test,x_train="",y_train=""):

        # 若是仅传递预测集,则采取的训练集的私有变量self.x_train
        if len(x_train) == 0:
            x_train = self.x_train
        if len(y_train) == 0:
            y_train = self.y_train

        if type(x_test) != np.ndarray:
            x_test = np.array(x_test)
        

        distances = self.calculate_distances(x_train,x_test,self.ord)                     # 获取距离矩阵
        partitioned_indexes = np.argpartition(distances, self.k, axis=1)[:, :self.k]      # 找到每行最小的前k个值的索引位置
                                                                                          # 即获取距离最近得前k个样本
        sub_labels = y_train[partitioned_indexes, -1]                                     # 获取选定得最近前k个样本对应的标签
        modes, counts = mode(sub_labels, axis=1,keepdims=False)                           # 获取每行的众数以及出现次数
        return modes                                                                      # 即为预测数

2.数据预处理

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 加载燕尾花数据集
iris = load_iris()

# 获取特征数据和标签数据
X = iris.data
y = iris.target

# 将数据集切分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=3220822)

# 打印切分后的数据集大小
print("训练集大小:", x_train.shape[0])
print("测试集大小:", x_test.shape[0])

3 sklearn调用KNeighborsClassifier

from sklearn.neighbors import KNeighborsClassifier

# 创建 KNN 模型对象
knn = KNeighborsClassifier(n_neighbors=3,)
# 训练模型
knn.fit(x_train, y_train)
# 进行预测
y_pred = knn.predict(x_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print("准确率:", accuracy)

 可以看到结果已经是很好的了

4 调用封装好的优化knn类

MYknn = KNN()
print("默认的k值与ord值:",MYknn.k,MYknn.ord)

# 训练模型
MYknn.fit(x_train, y_train,k_range=[1,2,3,4,5,6,7,8,9,10,11],ord_range=[1,2,3,4,5,6,7,8,9,10])
print("训练后选择的k值与ord值:",MYknn.k,MYknn.ord)


# 进行预测
y_pred = MYknn.predict(x_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print("准确率:", accuracy)

可以通过注释知道,在训练模型的时候,我们可以传入参数k和ord的范围。之后会基于给定的训练集进行10折运算,选取最优的k与ord值。其结果输出如下

5 进行可视化

我们可以通过封装好类中的内置函数plot_k和plot_ord进行可视化。

其中plot_k(k="默认为训练后最优k值"),表示k值固定后,可视化准确率随ord 值变化的曲线。

并且plot_k(k="可选取k_range中任意值"),进行可视化

plot_ord是一样的使用方法

总结

对KNN算法采取了10折运算原理,在给定的参数范围内选取最优参数值,并给出了可视化效果。

  • 12
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值