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

news2024/11/16 18:05:00

本文结合实例详细讲解了如何使用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 KMedoids

class Cluster():

    def __init__(self, paths, std_method='feature') -> None:
        self.paths = paths
        self._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.RasterYSize
        gt = ds.GetGeoTransform()
        proj = ds.GetProjection()
        for i in range(1, len(paths)):
            ds = gdal.Open(paths[i])
            assert RasterXSize == ds.RasterXSize
            assert RasterYSize == ds.RasterYSize
            assert gt == ds.GetGeoTransform()
            assert proj == ds.GetProjection()
    
    def _get_valid_coors(self):
        data = rio.open(self.paths[0])
        nodata = data.nodata
        array = data.read(1).astype(np.float32)
        array[array==nodata] = np.NAN
        coors = np.where(~np.isnan(array))
        self.coors_x, self.coors_y = coors[0], coors[1]
        self.input_shape = array.shape

    def _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_x
        data[:, -1] = self.coors_y
        return data

    def _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 ValueError

    def _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_p
        d_p = np.mean(d_p)

        d_a = np.abs(a1-a2) * self.w_a
        d_a = np.mean(d_a)

        return d_p + d_a

    def cluster(self, centerNum, max_iter=300, w_p=1, w_a=1):
        self.centerNum = centerNum
        self.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_+1
        return 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 = 1
        height, width = arr.shape
    elif arr.ndim==3:
        count = arr.shape[0]
        _, height, width = arr.shape
    else:
        raise ValueError
    
    with 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.coloradmin.cn/o/656856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

English Learning - L3 作业打卡 Lesson6 Day43 2023.6.16 周五

English Learning - L3 作业打卡 Lesson6 Day43 2023.6.16 周五 引言🍉句1: Thousands of lanterns slowly drift out to sea guiding the dead on their return journey to the other world.成分划分弱读连读爆破语调 🍉句2: This is a moving spectacl…

炎炎夏日!东南亚LazadaShopee泳衣品类热销榜单来袭

6月商机无限,趁热打铁!3大节庆即将来袭。小编特为卖家整理了6月最强爆单选品指南,揭秘东南亚泳衣市场。赶紧一睹为快吧! 炎炎夏日,马上即将迎来暑假,海边游玩肯定成了小朋友即家长们的首选之地&#xff0c…

js将json字符串转换为json对象的方法解析

将json字符串转换为json对象的方法。在数据传输过程中,json是以文本,即字符串的形式传递的,而JS操作的是JSON对象,所以,JSON对象和JSON字符串之间的相互转换是关键。 例如: JSON字符串: var str1 ‘{ “n…

MIT 6.S081 Lab Three

MIT 6.S081 Lab Three 引言page tablesPrint a page table (easy)代码解析 A kernel page table per process (hard)代码解析 Simplify copyin/copyinstr(hard)代码解析 可选的挑战练习 引言 本文为 MIT 6.S081 2020 操作系统 实验三解析。 MIT 6.S081…

shardingsphere第一课-前置课程-Mysql的集群搭建以及多数据源管理

一.Mysql的集群搭建(使用docker搭建省事) 1、关闭防火墙,重启docker** #关闭docker systemctl stop docker #关闭防火墙 systemctl stop firewalld #启动docker systemctl start docker2.1、准备主服务器 解释: 端口号是3306, 指定宿主机配…

FPGA基础知识-时序和延迟

目录 学习目标: 学习内容: 1.延迟模型的类型 2.路径延迟建模 3.时序检查 4.延迟反标注 学习时间: 学习总结 学习目标: 提示:这里可以添加学习目标 鉴别Verilog 仿真中用到的延迟模型的类型,分布延…

YOLOv5改进系列(10)——替换主干网络之GhostNet

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制

项目中还不会用SpringSecurity,看这篇文章就够了

安全管理是Java应用开发中无法避免的问题,随着Spring Boot和微服务的流行,Spring Security受到越来越多Java开发者的重视,究其原因,还是沾了微服务的光。作为Spring家族中的一员,其在和Spring家族中的其他产品如SpringBoot、Spring Cloud等进…

client-go的Indexer三部曲之而:性能测试

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是《client-go的Indexer》系列的第二篇,在前文咱们通过实例掌握了client-go的Indexer的基本功能,本篇咱们尝试对下面这…

6.pixi.js编写的塔防游戏(类似保卫萝卜)-游戏资源打包逻辑

游戏说明 一个用pixi.js编写的h5塔防游戏,可以用electron打包为exe,支持移动端,也可以用webview控件打包为app在移动端使用 环境说明 cnpm6.2.0 npm6.14.13 node12.22.7 npminstall3.28.0 yarn1.22.10 npm config list electron_mirr…

配置legacyUnhandledExceptionPolicy属性防止处理异常后程序崩溃退出(C#)

这是这篇文章后面遗留的问题: winform中的全局异常信息_winform全局异常捕获_zxy2847225301的博客-CSDN博客 就是线程抛出异常后,被AppDomain.CurrentDomain.UnhandledException注册的事件捕获后,程序依旧崩溃退出。 解决方案:在…

架构-嵌入式模块

章节架构 约三分,主要为选择题 #mermaid-svg-z6RGCDSEQT5AhE1p {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-z6RGCDSEQT5AhE1p .error-icon{fill:#552222;}#mermaid-svg-z6RGCDSEQT5AhE1p .error-text…

【产品经理】从用户体验五要素出发,谈如何设计与体验一款产品

用户体验五要素是产品人必备的知识技能,由于网络碎片化的了解,往往容易造成其高深莫测,晦涩难懂的形象,进而对其束之高阁。但实质不过是一种产品分析与设计的方法论,正确姿势去了解它能帮助我们更好地理解一款产品和从…

移动端小于12px的字体处理方法

今天在按设计稿坐页面时&#xff0c;遇到了下图的情况 ​​​​​ 由于浏览器对字体最小为12px的限制&#xff0c;所以我查阅资料后尝试使用transform:scale来处理 代码如下&#xff1a; <div class"icon"><span class"iconfont icon-a-xuexi3 icon-…

ZYNQ——PL端流水灯的实现

文章目录 一、介绍二、代码编写三、引脚分配四、仿真分析五、添加 ILA IP六、板上验证 一、介绍 本文介绍的是在ZYNQ 7020黑金开发板上实现PL端流水灯的例子&#xff0c;开发板上PL端的LED灯总共有4个&#xff0c;在原理图中找到 PL LED 如下图所示&#xff0c;通过看图可知&a…

【MarkDown】CSDN Markdown之四象限图quadrantChart详解

四象限图 四象限图是一种将数据分为四个象限的可视化方法。它用于在二维网格上绘制数据点&#xff0c;其中一个变量表示x轴&#xff0c;另一个变量表示y轴。根据针对正在分析的数据集的一组标准&#xff0c;将图表分成四个相等的部分来确定四个象限。经常使用四象限图来识别数…

父亲节|祝天下所有父亲节日快乐,长寿安康!

父亲节&#xff0c;是一个感谢父亲的节日。普遍认为的日期是每年6月的第三个星期日&#xff0c;在这一天世界上有52个国家和地区在过父亲节。同时注重孝道也是我们中华民族的传统文化。 在这个感恩的节日里 把最真诚美好的祝福 送给天下所有的父亲们 祝福他们 节日快乐&…

OpenAI 大模型生态

目录标题 1. 语言类大模型2. 图像多模态大模型3. 语音识别模型4. 文本向量化模型5. 审查模型6. 编程大模型1. 语言类大模型 包括GPT-3、GPT-3.5、GPT-4系列模型。并且,OpenAl在训练GPT-3的同时,训练了参数不同、复杂度各不相同的A、B、C、D四项大模型(基座模型),用于不同场景…

mysql 集群 MGR

mysql安装&#xff08;3台服务&#xff09; 1下载 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.11-linux-glibc2.12-x86_64.tar.gz 2解压mysql wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.11-linux-glibc2.12-x86_64.tar.gz tar -zxvf…

键盘按键事件 通过键盘上下左右按键移动界面上图标

#main.c文件 #include “keyevent.h” #include int main(int argc, char *argv[]) { QApplication a(argc, argv); KeyEvent w; w.show(); return a.exec();} #include “keyevent.h”//头文件 #ifndef KEYEVENT_H #define KEYEVENT_H #include #include #include cl…