引言
最邻近方法(KNN)是一种可用于回归与分类问题的方法,其核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
与其他参数相比,无论是分类还是预测,K值对于KNN结果精度的影响比较大,现有的KNN算法多是针对RGB图像进行分类,所以分类得到的图像没有坐标,另外基于ROI的分类并不能很好地兼容此类代码,对于K值的确定研究较少,大部分使用默认参数。针对上述问题,笔者将带代价首先实现最优K值的确定,然后利用训练好的KNN模型对4波段的遥感图像中的植被进行分类。
数据介绍
遥感图像与该文相同:
上官:基于Python的遥感图像NDVI批处理zhuanlan.zhihu.com模型训练的txt文本下载地址:
python代码实现(最优参数K确定)
from sklearn import neighbors
import numpy as np
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
#定义字典,便于来解析样本数据集txt
def Iris_label(s):
it={b'no-lodging':0, b'Lodging':1}
return it[s]
Path = r"E:yynctryedatadata.txt"
#读取数据集
data = np.loadtxt(Path, dtype=float, delimiter=',', converters={4:Iris_label} )
# converters={4:Iris_label}中“4”指的是第5列:将第5列的str转化为label(number)
#划分数据与标签
x,y=np.split(data,indices_or_sections=(4,),axis=1) #x为数据,y为标签
#利用十折交叉验证,搜索K值于1至30处的误差
K_range = range(1, 30)
K_error = []
for i in K_range:
KNN = neighbors.KNeighborsClassifier(n_neighbors=i)
scores = cross_val_score(KNN, x, y.ravel(), cv=10, scoring="accuracy")
K_error.append(scores.mean())
#绘制不同K值的误差曲线图
plt.plot(K_range, K_error, color="pink")
plt.xlabel("K value")
plt.ylabel("Accuracy")
plt.grid(ls="--", c="gainsboro")
plt.show()
python代码实现(模型训练)
from sklearn import neighbors
import numpy as np
from sklearn import model_selection
import pickle
#定义字典,便于来解析样本数据集txt
def Iris_label(s):
it={b'no-lodging':0, b'Lodging':1}
return it[s]
path = r"E:yynctryedatadata.txt"
SavePath = r"E:yynctryedatamodel1.pickle"
#读取数据集
data=np.loadtxt(path, dtype=float, delimiter=',', converters={4:Iris_label} )
# converters={4:Iris_label}中“4”指的是第5列:将第5列的str转化为label(number)
#划分数据与标签
x,y=np.split(data,indices_or_sections=(4,),axis=1) #x为数据,y为标签
x=x[:,0:4] #选取前4个波段作为特征
train_data,test_data,train_label,test_label = model_selection.train_test_split(x,y, random_state=1, train_size=0.9, test_size=0.1)
#用K=1的参数,训练KNN模型(调参)
classifier = neighbors.KNeighborsClassifier(n_neighbors=1)
classifier.fit(train_data, train_label.ravel())#ravel函数拉伸到一维
#计算随机森林的准确率
print("训练集:",classifier.score(train_data,train_label))
print("测试集:",classifier.score(test_data,test_label))
#保存模型
#以二进制的方式打开文件:
file = open(SavePath, "wb")
#将模型写入文件:
pickle.dump(classifier, file)
#最后关闭文件:
file.close()
python代码实现(图像分类)
import numpy as np
import gdal
import pickle
#定义图像打开方式
def image_open(image):
data1 = gdal.Open(image)
if data1 == "None":
print("数据无法打开")
return data1
#定义模型打开方式
def model_open(model):
data1 = open(model, "rb")
data2 = pickle.load(data1)
data1.close()
return data2
#定义图像保存
def writeTiff(im_data, im_geotrans, im_proj, path):
if 'int8' in im_data.dtype.name:
datatype = gdal.GDT_Byte
elif 'int16' in im_data.dtype.name:
datatype = gdal.GDT_UInt16
else:
datatype = gdal.GDT_Float32
if len(im_data.shape) == 3:
im_bands, im_height, im_width = im_data.shape
elif len(im_data.shape) == 2:
im_data = np.array([im_data])
im_bands, im_height, im_width = im_data.shape
# 创建文件
driver = gdal.GetDriverByName("GTiff")
dataset = driver.Create(path, int(im_width), int(im_height), int(im_bands), datatype)
if (dataset != None):
dataset.SetGeoTransform(im_geotrans) # 写入仿射变换参数
dataset.SetProjection(im_proj) # 写入投影
for i in range(im_bands):
dataset.GetRasterBand(i + 1).WriteArray(im_data[i])
del dataset
#定义相关参数
Image_FilePath = r"E:yynctryedata20180911_yync(DA).tif"
Model_FiLePath = r"E:yynctryedatamodel1.pickle"
Save_FilePath = r"E:yynctryedataresult_KNN.tif"
image1 = image_open(Image_FilePath)
width = image1.RasterXSize
height = image1.RasterYSize
Projection = image1.GetProjection()
Transform = image1.GetGeoTransform()
image2 = image1.ReadAsArray()
#打开模型
model1 = model_open(Model_FiLePath)
#在与测试前要调整一下数据的格式
data = np.zeros((image2.shape[0], image2.shape[1] * image2.shape[2]))
for i in range(image2.shape[0]):
data[i] = image2[i].flatten()
data = data.swapaxes(0, 1)
#对调整好格式的数据进行预测
pred = model1.predict(data)
#同样地,我们对预测好的数据调整为我们图像的格式
pred = pred.reshape(image2.shape[1], image2.shape[2]) * 255
pred = pred.astype(np.uint8)
#将结果写到tif图像里
writeTiff(pred, Transform, Projection, Save_FilePath)
处理结果
1.运行“python代码实现(最优参数K确定)”后得到以下结果:
K=1,ACC最优,所以讲K=1输入预测模型中。
2.运行“python代码实现(图像分类)”后得到以下结果:
得到不同形态的植被分类状况
图像分类结果参考文献
馨意:python实现随机森林遥感图像分类zhuanlan.zhihu.com KNNwww.jianshu.com 机器学习之KNN(k近邻)算法详解_平原的博客-CSDN博客_knnblog.csdn.net 阙赞:Python—KNN分类算法(详解)zhuanlan.zhihu.com