一种栅格数据的空间聚类方法(ACA-Cluster)

news/2024/11/25 0:55:19/

本文结合实例详细讲解了如何使用Python对栅格数据进行空间聚类,关注公众号GeodataAnalysis,回复20230616获取示例数据和代码,包含整体的写作思路,上手运行一下代码更容易弄懂。

带有非空间属性的空间数据聚类分析是空间聚类研究的热点和难点 ,聚类结果的应用领域很广,典型的就比如公众号之前介绍过的地理探测器1

地理探测器擅长自变量为类型量、因变量为数值量的分析,当自变量为数值量时,要采用一定的离散化方法将其转化为类型量。但很多影响因子是空间上连续分布的数值型变量,既具有地理域上的连续性,又具有属性域上的相似性。因此在聚类方法的选择上不仅要考虑属性特征的相似性,还要考虑对象的空间邻近性。坐标与属性一体化的空间聚类方法在对空间对象进行空间相似性度量时,将属性特征和地理位置特征同时纳入到距离测度中,以提高空间聚类分析的质量。

本文介绍的ACA-Cluster方法2基于一体化法进行改进,一体化法是将空间要素的位置(即坐标)和非空间属性数据都视为空间要素的属性数据,并使用属性距离函数计算相似度,再结合k-means算法进行聚类的方法。

1 相似度距离定义

聚类分析中常用的距离有近10 种,最常采用的距离之一曼哈顿距离。

假设任意两个空间对象 P i P_i Pi P j P_j Pj的中心坐标分别为 ( x i y i ) (x_i \, y_i) (xiyi) ( x j y j ) (x_j \, y_j) (xjyj) a i k a_{ik} aik a j k a_{jk} ajk分别是 P i P_i Pi P j P_j Pj上的值第k维度的属性值,则对象 P i P_i Pi P j P_j Pj之间的位置曼哈顿距离( D p D_p Dp)和属性曼哈顿距离( D a D_a Da)可分别表示为:
D p = ∣ x i − x j ∣ + ∣ y i − y j ∣ 2 D a = 1 M ∑ k = 1 M ∣ a i k − a j k ∣ D_p = \frac{\lvert x_i - x_j \rvert + \lvert y_i - y_j \rvert}{2} \\ D_a = \frac{1}{M} \sum_{k=1}^M \lvert a_ik - a_jk \rvert Dp=2xixj+yiyjDa=M1k=1Maikajk

其中, D p D_p Dp表示位置距离,用以表达地物之间的邻近程度; D a D_a Da表示属性距离,用以刻画地物之间属性特征的相似性。此外,采用归一化方法去除位置距离和属性距离之间的单位限制。位置距离可以表达地物之间的邻近程度,属性距离则刻画地物之间属性特征的相似性。在聚类分析中,一般要求同类的地物既要在空间上邻近,又要在属性特征上相似。由此可见,单独采用位置距离或属性距离作为聚类分析的尺度,均不能很好地满足这一要求。为此,作者定义3种把位置距离和属性距离结合在一起的空间距离。

第一种定义方法是把空间坐标和属性特征同等对待:

D s = D p + D a D_s = D_p + D_a Ds=Dp+Da

第二种定义方法是对位置距离和属性距离进行加权,分别为 w p w_p wp w a w_a wa

D s = w p ⋅ D p + w a ⋅ D a D_s = w_p \cdot D_p + w_a \cdot D_a Ds=wpDp+waDa

事实上,坐标中的两个坐标值对聚类分析的作用可能是不同的,其重要性用向量 W ( p ) = ( w x , w y ) W(p) = (w_x, w_y) W(p)=(wx,wy)表示;同样,属性特征集中的m个特征对聚类分析的作用也可能是不一样的,其重要性可用权重向量 W ( a ) = ( w 1 , w 2 , w 3 , … , w m ) W(a) = (w_1, w_2, w_3, \dots, w_m) W(a)=(w1,w2,w3,,wm)来表示,于是有了不等加权空间距离:

D a = w x ⋅ ∣ x i − x j ∣ + w y ⋅ ∣ y i − y j ∣ + 1 M ∑ k = 1 M w k ⋅ ∣ a i k − a j k ∣ D_a = w_x \cdot \lvert x_i - x_j \rvert + w_y \cdot \lvert y_i - y_j \rvert + \frac{1}{M} \sum_{k=1}^M w_k \cdot \lvert a_ik - a_jk \rvert Da=wxxixj+wyyiyj+M1k=1Mwkaikajk

2 基于空间位置和属性特点的空间聚类算法

算法实现:ACA-Cluster

输入:簇的数目k和包含n个样品的数据集

输出:k个类别的矩阵

计算步骤:

  1. 设置最大迭代次数iternum。
  2. 随机取k个样品作为聚类中心。
  3. 计算其余样本到这k类的距离,将它们归为距离最近的类。至此,所有的样本都归类完毕。
  4. 计算各个类中心所有样品特征值的平均值作为该聚类中心的特征值。随着聚类中心的改变,样本的类号也在改变。
  5. 循环第3和第4步,直至不再有样本类号发生变化或达到了最大迭代次数。

3 代码实现

import numpy as np
import rasterio as rio
from osgeo import gdal
from sklearn_extra.cluster import KMedoidsclass Cluster():def __init__(self, paths, std_method='feature') -> None:self.paths = pathsself._check_data(self.paths)self._get_valid_coors()self.data = self._get_data()self._std(std_method)def _check_data(self, paths):'''检查所有数据文件是否横列数和空间范围全部相同,同时返回其行列数'''ds = gdal.Open(paths[0])RasterXSize, RasterYSize = ds.RasterXSize, ds.RasterYSizegt = ds.GetGeoTransform()proj = ds.GetProjection()for i in range(1, len(paths)):ds = gdal.Open(paths[i])assert RasterXSize == ds.RasterXSizeassert RasterYSize == ds.RasterYSizeassert gt == ds.GetGeoTransform()assert proj == ds.GetProjection()def _get_valid_coors(self):data = rio.open(self.paths[0])nodata = data.nodataarray = data.read(1).astype(np.float32)array[array==nodata] = np.NANcoors = np.where(~np.isnan(array))self.coors_x, self.coors_y = coors[0], coors[1]self.input_shape = array.shapedef _get_data(self):data = np.zeros((self.coors_x.size, len(self.paths)+2), dtype=np.float32)for i, path in enumerate(self.paths):src = rio.open(path)array = src.read(1)data[:, i] = array[self.coors_x, self.coors_y]data[:, -2] = self.coors_xdata[:, -1] = self.coors_yreturn datadef _std(self, mode):if 'feature' == mode:self.data =  (self.data-np.min(self.data, axis=0))/(np.max(self.data, axis=0)-np.min(self.data, axis=0))elif 'mean' == mode:self.data =  (self.data-np.mean(self.data, axis=0))/np.std(self.data, axis=0)else:raise ValueErrordef _geo_distance(self, x, y):a1, a2 = x[:-2], y[:-2]d1, d2 = x[-2:], y[-2:]d_p = np.abs(d1-d2) * self.w_pd_p = np.mean(d_p)d_a = np.abs(a1-a2) * self.w_ad_a = np.mean(d_a)return d_p + d_adef cluster(self, centerNum, max_iter=300, w_p=1, w_a=1):self.centerNum = centerNumself.w_p = np.array(w_p)self.w_a = np.array(w_a)kmedoids_custom = KMedoids(n_clusters=centerNum, metric=self._geo_distance, max_iter=max_iter)self.k = kmedoids_custom.fit(self.data)matrix = np.zeros(self.input_shape, dtype=np.int32)matrix[self.coors_x, self.coors_y] = self.k.labels_+1return matrix

4 实战演示

实验数据为分辨率为0.25度的降雨栅格数据,2014-2017年。

4.1 一维数据聚类

import numpy as np
from glob import glob
import rasterio as rio
from cluster import Cluster
import matplotlib.pyplot as plt# 对2014年的降雨数据进行聚类
paths = [r'./pre/y2014.tif']
cluster = Cluster(paths, std_method='mean')# 展示降雨数据
src = rio.open('./pre/y2014.tif')
pre = src.read(1)
pre = np.ma.masked_array(pre, mask=pre==src.nodata)cluster_array1 = cluster.cluster(5, w_p=1, w_a=1)
cluster_array1 = np.ma.masked_array(cluster_array1, mask=cluster_array1==0)
cluster_array2 = cluster.cluster(5, w_p=2, w_a=1)
cluster_array2 = np.ma.masked_array(cluster_array2, mask=cluster_array2==0)fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(9, 4))
ax1.imshow(pre)
ax2.imshow(cluster_array1)
ax3.imshow(cluster_array2);

最左侧为2014年的降雨数据,右侧的两个分别为按照第一种和第二种距离定义的聚类结果。

4.2 二维数据聚类

# 读取四年的降雨数据
paths = glob(r'./pre/*.tif')
cluster = Cluster(paths, std_method='mean')
cluster_array = cluster.cluster(5)cluster_array1 = cluster.cluster(5, w_p=1, w_a=1)
cluster_array1 = np.ma.masked_array(cluster_array1, mask=cluster_array1==0)
cluster_array2 = cluster.cluster(5, w_p=2, w_a=1)
cluster_array2 = np.ma.masked_array(cluster_array2, mask=cluster_array2==0)
cluster_array3 = cluster.cluster(5, w_p=[1, 2], w_a=[1, 1, 2, 3])
cluster_array3 = np.ma.masked_array(cluster_array3, mask=cluster_array3==0)fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(9, 4))
ax1.imshow(cluster_array1)
ax2.imshow(cluster_array2)
ax3.imshow(cluster_array3);

三个图分别为三种不同距离定义的聚类结果。

4.3 保存聚类结果

# numpy数组转tif
def array_to_tif(out_path, arr, crs, transform, nodata=None):# 获取数组的形状if arr.ndim==2:count = 1height, width = arr.shapeelif arr.ndim==3:count = arr.shape[0]_, height, width = arr.shapeelse:raise ValueErrorwith rio.open(out_path, 'w', driver='GTiff', height=height, width=width, count=count, dtype=arr.dtype, crs=crs, transform=transform, nodata=nodata) as dst:# 写入数据到输出文件if count==1:dst.write(arr, 1)else:for i in range(count):dst.write(arr[i, ...], i+1)array_to_tif('./cluster.tif', cluster_array3.data, src.crs, src.transform, nodata=0)

参考文献:

[1]: 石亚冰,黄予。一种基于位置距离和属性特征结合的聚类方法。软件导刊,2013,12(3): 51-54.

[2]: Junwu Dong, Pengfei Liu, et al. Effects of anthropogenic precursor emissions and meteorological conditions on PM2.5 concentrations over the “2+26” cities of northern China. Environmental Pollution, 2022, 315: 120392.


  1. 1 ↩︎

  2. 2 ↩︎


http://www.ppmy.cn/news/436958.html

相关文章

android 自动更换壁纸,安卓壁纸如何设置自动更换壁纸-手机天堂

安卓壁纸是一款非常实用的手机壁纸更换软件,平台中有非常丰富的静态壁纸和视频动态壁纸,可以说是每天换一张都不会重样的,这就让手机变的更加的丰富多彩。相信有不少的朋友会认为老使用一张壁纸太单调,每天都换成不同的才好。那么…

安卓中改变手机壁纸

布局文件如下: XML文件如下所示:<LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:layout_height"match_parent&qu…

android 壁纸制作教程,教你如何自己制作安卓手机壁纸的方法教程

谷歌的Android手机操作系统正在迅速成为最流行的手机平台之一。这是非常容易自定义的&#xff0c;包括更改墙纸&#xff0c;只是可自定义的其中一部分。 这篇文章可以教你如何DIY制作属于自己的手机壁纸&#xff0c;下面直接进入主题。 准备工作&#xff1a; 1.图片 2.图片编辑…

有没有不限制群发数量的软件?

父亲节的由来 父亲节&#xff08;Fathers Day&#xff09;&#xff0c;顾名思义是感恩父亲的节日。 世界上第一个父亲节&#xff0c;1910年诞生于美国。 而中国的父亲节起源要追溯到民国时代。民国三十四年的八月八日&#xff08;1945.8.8&#xff09;&#xff0c;上海文人所…

【22AP20 解码处理器(Hi3536AV100)】

22AP20 解码处理器(Hi3536AV100) 一、产品简介 22AP20 是针对多路高清/超高清&#xff08;1080p/4M/5M/4K&#xff09;智能 NVR 产品应用开发的新一代专业高端 SoC 芯片。22AP20 集成了 ARM Cortex-A55 八核处理器和性能强大的图像分析工具处理器&#xff0c;支持多种智能算法…

【栈与队列part02】| 20.有效的括号、1047.删除字符串中所有相邻重复项、150.逆波兰表达式求值

目录 ✿LeetCode20. 有效的括号❀ ✿LeetCode1047.删除字符串中的所有相邻重复项❀ ✿LeetCode150. 逆波兰表达式求值❀ ✿LeetCode20. 有效的括号❀ 链接&#xff1a;20.有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;]…

Failed to load ApplicationContext

问题如下 找了一个多小时&#xff0c;最终发现问题所在&#xff1a; 用的数据库时MongoDB&#xff0c;在写分页查询的时候 用的mysql的分页查询的jar包&#xff0c;会引入mysql相关的包。导致jar包冲突 <dependency><groupId>com.github.pagehelper</groupId&g…

C51单片机简易密码锁(课程设计)

已经过测试&#xff0c;全部可用。手机好像不能发博客&#xff0c;相册提取图片代码粘黏复制可用。 本密码锁用于开门关门。绿灯保持常亮状态&#xff0c;表示一直通电状态。如果处于开门状态&#xff0c;则红灯也会亮起。&#xff08;单片机上无法显示红绿灯&#xff0c;仿真…