🎀个人主页: https://zhangxiaoshu.blog.csdn.net
📢欢迎大家:关注🔍+点赞👍+评论📝+收藏⭐️,如有错误敬请指正!
💕未来很长,值得我们全力奔赴更美好的生活!
前言
K-近邻(KNN)是一种简单但有效的机器学习算法,可用于图像分类。POLSAR(极化合成孔径雷达)是一种雷达成像技术,提供了极化信息,适用于地物分类和识别。将KNN应用于POLSAR图像分类具有简单易实现、多类别适用、无需假设数据分布、基于邻近性进行分类、对噪声鲁棒以及可用于增量学习等优点,本文为基于K-近邻实现PLOSAR图像分类的一个小实例。
文章目录
- 前言
- 一、数据预处理
- 二、基于K-近邻的PLOSAR图像分类
- 1. KNN简介
- 2. 分类实验
一、数据预处理
对于提供的原始数据ALLData.mat和标签数据label.mat来说,标签数据是包含背景0的,所以,在分类之前,我们首先需要将对应label为0的对于提供的原始数据删除。将原始数据ALLData.mat和标签数据label.mat读取并查看维度信息如下所示:
#读取mat数据
data_orginal = io.loadmat(r"D:/VSCode/Task_python/lab/homework/Image classification/PolSAR/ALLData.mat")["ALLData"]
label_original = io.loadmat(r"D:/VSCode/Task_python/lab/homework/Image classification/PolSAR/label.mat")["label"]
label = np.reshape(label_original, data_orginal.shape[0], order='F')
print("ALLData shape=",data_orginal.shape)
print("label shape=",label.shape)
输出为:
ALLData shape= (768000, 9)
label shape= (768000,)
可以看到ALLData和label共有768000条数据,其中ALLData的每一条数据是一个1*9的向量,label为一个数,为了后续清零操作的便利,我们将这两个数据拼接在一起,即使用:
data_o=torch.cat([torch.tensor(data_orginal),
torch.tensor(label).reshape(768000,1)],-1).numpy(),
这样我们便得到了一个768000*10的序列。
下面进行清零操作,首先,我们定义一个data数据,将第一个label不为0的数据赋值给data,之后遍历读取的原始拼接在一起的数据data_o,如果data_o[i][9]不等于0,我们就将data_o[i]拼接到data中,最后保存data,操作过程如下所示。
#数据清零
data=data_o[111135]
for i in range(111136,768000-1):
if data_o[i][9]!=0:
data=np.vstack((data,data_o[i]))
np.save('data.npy',data)
清零完成后,我们便得到了一个167712*10的数据,其中前9列是数据,后面一列为标签。
二、基于K-近邻的PLOSAR图像分类
1. KNN简介
K最近邻(KNN)算法是一种基本的机器学习算法,常用于分类和回归任务。它的工作原理非常简单直观:对于一个新的未知样本,根据其在特征空间中与已知样本的距离,找出距离最近的K个邻居,然后根据这K个邻居的标签来预测未知样本的标签。
KNN算法的基本步骤如下:
-
选择K值:首先选择一个合适的K值,它表示在预测时要考虑多少个最近邻居的标签。K值的选择可能会影响算法的性能。
-
计算距离:对于待预测的样本,计算它与所有已知样本之间的距离。通常使用的距离度量包括
欧式距离
、曼哈顿距离
、闵可夫斯基距离
等。 -
找出K个最近邻:根据计算得到的距离,找出与待预测样本最近的K个已知样本。
-
投票决策:对于分类任务,根据这K个最近邻的标签,采用
投票的方式
来确定待预测样本的标签。一般来说,可以选择多数票决定样本的分类标签。 -
回归预测:对于回归任务,根据这K个最近邻的标签,可以采用平均值或加权平均值来预测待预测样本的输出。
2. 分类实验
首先,我们将之前处理得到的data数据读入,然后按列分成1677129的数据和1677121的标签。其过程如下代码所示:
#加载清零后的数据
data=np.load("D:\VSCode\Task_pytorch\z_home_work\Image classification\data.npy")
print(data.shape)
#将数据和label分开
[data,label]=np.split(data,[9],axis=1)
print(data.shape)
print(label.shape)
然后定义一个KNN分类器,这里我们直接使用sklearn来实现,然后我们的实验分别测试了当训练数据集比例为[0.1,0.3,0.5]时的准确率,同时测试了k值为[10,20,30,40,50]的准确率,共九组实验,其中实验过程代码如下图4所示,实验数据如下表所示。从实验结果中我们可以看到,使用KNN分类器的分类效果比较好,基本达到了85%-87%的准确率,同时,我们可以看到,对于不同的训练数据集比例来说,较大的数据集更加能学习到更好的分类特征。对于不同的K值来说,我们可以看到无论过大或是过小都会对模型的准确度产生影响,所以K的取值往往需要一个合适的区间或值,另一方面,K的取值可以看到对最后的结果影响不大,即KNN分类器受K值的影响波动较小较稳定。
acc=[]
k=[10,20,30,40,50]
train_size=[0.1,0.3,0.5]
for i in range(5):
print("K=",k[i],"时:")
for j in range(3):
#划分训练集和测试集
X_train,X_test,y_train,y_test = train_test_split(data, label, train_size=train_size[j], stratify=label)
knn = KNeighborsClassifier(n_neighbors=k[i])
knn.fit(X_train, y_train.reshape((-1, 1)).ravel())
y_predict = knn.predict(X_test)
acc.append(accuracy_score(y_test, y_predict))
print("train_size=",train_size[j], "的分类准确率为: ", acc[i*3+j])
训练结果:
- K= 10 时:
train_size= 0.1 的分类准确率为: 0.8641323431009468
train_size= 0.3 的分类准确率为: 0.8803056244090666
train_size= 0.5 的分类准确率为: 0.8870444571646632 - K= 20 时:
train_size= 0.1 的分类准确率为: 0.8637812125267489
train_size= 0.3 的分类准确率为: 0.8780398470174363
train_size= 0.5 的分类准确率为: 0.8832999427590155 - K= 30 时:
train_size= 0.1 的分类准确率为: 0.8615154265573965
train_size= 0.3 的分类准确率为: 0.8762681113127029
train_size= 0.5 的分类准确率为: 0.8826440564777714 - K= 40 时:
train_size= 0.1 的分类准确率为: 0.8586202555965576
train_size= 0.3 的分类准确率为: 0.874624145009753
train_size= 0.5 的分类准确率为: 0.8810341537874451 - K= 50 时:
train_size= 0.1 的分类准确率为: 0.8551553255907938
train_size= 0.3 的分类准确率为: 0.8714980536461129
train_size= 0.5 的分类准确率为: 0.8786848883800802
train_size=0.1 | train_size=0.3 | train_size=0.5 |
---|---|---|
K=10 | 0.8641323431009468 | 0.8803056244090666 |
K=20 | 0.8637812125267489 | 0.8780398470174363 |
K=30 | 0.8615154265573965 | 0.8762681113127029 |
K=40 | 0.8586202555965576 | 0.874624145009753 |
K=50 | 0.8551553255907938 | 0.8714980536461129 |
最后,我们使用训练好的模型将原始数据读入,并将分类的结果绘制成图片的形式,其结果如下图所示。
结合SVM的实验结果从整体上两个分类器所表现的行性能来看,KNN相对来说更加稳定一些,在KNN实验中,无论K的取值如何,它的最终结果总是保持在85-87%之间,但是反观SVM来说,它受kernel函数取值的影响太多,例如,在kernel函数为rbf时,其最高准确率可以达到87%。但是在kernel函数为linear时,最高准确率仅仅只有达到22%。总的来说,SVM分类器受到kernel函数很大程度上的影响。
文中有不对的地方欢迎指正、补充。