在模仿中精进数据分析与可视化01——颗粒物浓度时空变化趋势(Mann–Kendall Test)

2023-10-27

本文是在模仿中精进数据分析与可视化系列的第一期——颗粒物浓度时空变化趋势(Mann–Kendall Test),主要目的是参考其他作品模仿学习进而提高数据分析与可视化的能力,如果有问题和建议,欢迎在评论区指出。若有其他想要看的作品,也欢迎在评论区留言或通过公众号发消息给出相关信息。

扫描下面的二维码,关注公众号GeodataAnalysis,搜索本篇文章获取文中示例数据与代码:

一、简介

本次要模仿的作品来自论文Investigating the Impacts of Urbanization on PM2.5 Pollution in the Yangtze River Delta of China: A Spatial Panel Data Approach,研究区域为上海、安徽、浙江和江苏,所用数据为 2002–2017该区域PM2.5浓度栅格数据,数据来源于 Dalhousie University Atmospheric Composition Analysis Group开发的年均PM2.5数据集V4.CH.03,空间分辨率为0.01°×0.01°(原论文采用数据的空间分辨率为1km×1km,但我在该网站上找不到,可能是不提供下载了)。

二、数据下载和处理

数据下载格式为.asc,使用gdal将其转为.tif格式,所用代码如下。

# -*- coding: utf-8 -*-

import os
from osgeo import gdal

inpath = "./ASCII" #待转换的栅格的存储路径,会转换该路径下的所有栅格
outpath = "./TIF" #输出栅格的路径,最好是空路径

def ASCII2TIF(filepath, outfilepath):
    ds = gdal.Open(filepath)
    tif = gdal.Translate(outfilepath, ds)
    tif = None

print("Starting Convert!")
for filename in os.listdir(inpath):
    if filename.endswith(".asc"):
        filepath = os.path.join(inpath, filename)
        outfilepath = os.path.join(outpath, filename.replace(".asc", ".tif"))
        ASCII2TIF(filepath, outfilepath)

print("Convert Over!")

三、Mann–Kendall趋势分析

Mann–Kendall趋势分析的具体计算方法这里不再赘述,原文作者采用R语言的trend package计算的,本文采用python的pymannkendall计算,github项目地址为https://github.com/mmhs013/pyMannKendall

原文的趋势分析包括两部分,一部分是计算slope值,slope值为正,则表明具有上升的趋势,反之亦然;另一部分是计算p值,p值越小趋势越显著,0.01<p<0.05说明趋势显著,p<0.01说明趋势非常显著。这两部分的结果都可以使用pymannkendalloriginal_test函数计算,pymannkendall的简单用法介绍如下。

A quick example of pyMannKendall usage is given below. Several more examples are provided here.

import numpy as np
import pymannkendall as mk

# Data generation for analysis
data = np.random.rand(360, 1)

result = mk.original_test(data)
print(result)

Output are like this:

Mann_Kendall_Test(trend='no trend', h=False, p=0.9507221701045581, z=0.06179991635055463, Tau=0.0021974620860414733, s=142.0, var_s=5205500.0, slope=1.0353584906597959e-05, intercept=0.5232692553379981)

Whereas, the output is a named tuple, so you can call by name for specific result:

print(result.slope)

or, you can directly unpack your results like this:

trend, h, p, z, Tau, s, var_s, slope, intercept = mk.original_test(data)

四、计算并保存结果

这里依然使用python作为分析计算的工具,所用代码如下所示。

由于 pymannkendall较为臃肿,计算速度很慢,并且暂不支持numba加速,有需要大量计算的可根据其源码重新编写函数,实现numba加速,如本文的get_slope函数,在使用numba加速后计算pvalues仅需4秒,使用pymannkendalloriginal_test则需要几分钟的时间。

# -*- coding: utf-8 -*-
import os
import numba
import numpy as np
from glob import glob
import rasterio as rio
import geopandas as gpd
import pymannkendall as mk
from rasterio.mask import mask

inpath = r"./TIF"  # .tif文件的保存路径
p_path = r"./pvalues.tif"  # p-values的输出路径
slope_path = r"./slopes.tif"  # slopes的输出路径
trend_path = r"./trends.tif"  # 原图左图中不同的趋势
border_path = r"./Shapefiles/border.shp"  # 研究区域

# 获取2002-2017年的栅格数据的路径
def get_raster_paths(inpath):
    paths = []
    for year in range(2002, 2018):
        year_path = glob(os.path.join(inpath, "*"+str(year)+"*.tif"))
        if year_path:
            paths.append(year_path[0])
        else:
            print("can't find raster of {} year!".format(year))
    return paths

# 裁剪栅格,并将结果转为numpy数组
def clip_raster_to_array(paths, border, dtype='float64'):
    src = rio.open(paths[0])
    gdf = gpd.read_file(border)
    array, gt = mask(src, [gdf.dissolve().geometry.__geo_interface__],
                     crop=True, nodata=src.nodata)
    array[array == src.nodata] = np.NAN
    arrays = np.full(shape=(len(paths), array.shape[0], array.shape[1]),
                     fill_value=np.NAN, dtype=dtype)
    arrays[0] = array

    for i in range(1, len(paths)):
        src = rio.open(paths[i])
        array, gt = mask(src, [gdf.dissolve().geometry.__geo_interface__],
                        crop=True, nodata=src.nodata)
        array[array == src.nodata] = np.NAN
        arrays[i] = array

    return arrays, src.crs, src.transform

# 使用rasterio将numpy数组转为tif
def array_to_raster(path, array, crs, transform, nodata=None):
    with rio.open(path, 'w', driver='GTiff', nodata=nodata,
                  height=array.shape[0], width=array.shape[1],
                  count=1, dtype=array.dtype, crs=crs,
                  transform=transform, compress='lzw') as dst:
        dst.write(array, 1)

# 计算slope值,使用numba加速
@numba.njit
def get_slope(x):
    if np.isnan(x).any():
        return np.NAN
    idx = 0
    n = len(x)
    d = np.ones(int(n*(n-1)/2))

    for i in range(n-1):
        j = np.arange(i+1, n)
        d[idx: idx + len(j)] = (x[j] - x[i]) / (j - i)
        idx = idx + len(j)

    return np.median(d)

# 计算slope和p值
def mk_(x):
    if np.isnan(x).any():
        return np.NAN
    result = mk.original_test(x.data)
    return result.slope, result.p


paths = get_raster_paths(inpath)
arrays, crs, gt = clip_raster_to_array(paths, border_path)
print("clip raster to array over!")

print("calculate slope and p-value over!")
slopes, pvalues = np.apply_along_axis(mk_, 0, arrays)
# 使用numba加速的示例
# slopes = np.apply_along_axis(get_slope, 0, arrays)

# 计算有显著和非常显著趋势的区域
trends = np.full(shape=slopes.shape, fill_value=0, dtype=np.int8)
trends[~np.isnan(slopes)] = 0  # nodata值及不显著区域设为0
# 比较显著增加的区域设为1
trends[(slopes > 0) & ((0.01 < pvalues) & (pvalues < 0.05))] = 1
# 显著增加的区域设为2
trends[(slopes > 0) & (pvalues < 0.01)] = 2
# 比较显著减少的区域设为3
trends[(slopes < 0) & ((0.01 < pvalues) & (pvalues < 0.05))] = 3
# 显著减少的区域设为4
trends[(slopes < 0) & (pvalues < 0.01)] = 4

# 保存栅格
array_to_raster(p_path, pvalues, crs, gt, np.NAN)
array_to_raster(slope_path, slopes, crs, gt, np.NAN)
array_to_raster(trend_path, trends, crs, gt)
print("save rasters over!")

五、结果绘图

由于QGIS软件打开和一些相关操作的速度都要比ArcGIS快的多,而且QGIS内置的取色器的功能也方便绘图时设置颜色,因此本文使用QGIS绘制结果图,如下图所示。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在模仿中精进数据分析与可视化01——颗粒物浓度时空变化趋势(Mann–Kendall Test) 的相关文章

随机推荐

  • clion set make -j8

    编译速度太慢对于程序猿来说很不友好 因此在clion中 可以设置cmake j8 最大化利用CPU核心来提供编译速度 在哪里设置呢 很简单 设置 gt Build Execution Deployment gt CMake gt Build
  • 内网隧道代理技术(二十七)之 DNS隧道介绍

    DNS隧道介绍 DNS协议介绍 域名系统 Domain Name System 缩写 DNS 是互联网的一项服务 它作为将域名和IP地址相互映射的一个分布式数据库 能够使人更方便地访问互联网 DNS使用TCP和UDP端口53 当前 对于每一
  • win10设置关机计划

    方法一 推荐 1 win r键打开运行窗口 cmd进入命令行 2 输入关机命令 修改时间完毕后 粘贴进入命令行 schtasks create tn shut tr shutdown s f sc once st 20 00 sd 2021
  • Tomcat服务器下载安装及配置教程(IDEA中使用Tomcat)

    目录 友情提醒 第一章 Tomcat下载与安装 1 1 Tomcat介绍 1 2 官网下载 第二章 Tomcat配置环境变量 2 1 windows环境变量配置 2 2 验证Tomcat配置是否成功 2 3 报错解决 第三章 IDEA整合T
  • 投影问题:带号求解,及中央子午线计算

    2 WGS 1984 坐标系的墨卡托投影分度带 UTM ZONE 选择方法如下 1 北半球地区 选择最后字母为 N 的带 2 可根据公式计算 带数 经度整数位 6 的整数部分 31 给一个实用公式吧 6度的 n int L 6 1 中央子午
  • javascript 防抖节流

    Javascript防抖和节流的深入理解和实践 http www ptbird cn javascript anti shake throttle html https www cnblogs com momo798 p 9177767 h
  • @RequestMapping用法详解

    这个相当于servlet的请求配置
  • [LeetCode-88]-Merge Sorted Array(有序数组合并)

    文章目录 0 题目相关 1 Solution 2 其他改进方案 0 题目相关 题目解读 给定两个有序数组 对数组进行合并操作 要求合并后的数组依旧有序 原题描述 原题链接 Given two sorted integer arrays nu
  • 【第39篇】RepLKNet将内核扩展到 31x31:重新审视 CNN 中的大型内核设计

    文章目录 摘要 一 简介 二 相关工作 2 1 大内核模型 2 2 模型缩放技术 2 3 结构重新参数化 三 应用大卷积的指南 四 RepLKNet 大内核架构 4 1 架构规范 4 2 使大内核更大 4 3 ImageNet 分类 4 5
  • python,pycharm 的环境变量设置

    官网下载安装python解释器时 如果忘记勾选添加到环境变量 add to path 可进行如下操作 来添加 更改环境变量 1 右键单击桌面上的 此计算机 图标 然后选择 属性 2 打开系统窗口并单击左侧的 高级系统设置 3 单击系统属性底
  • 如何让网页自适应所有屏幕宽度

    随着网络的快熟发展 越来越多的人使用手机上网 移动设备正超过桌面设备 成为访问互联网的最常见终端 于是 网页设计师不得不面对一个难题 如何才能在不同大小的设备上呈现同样的网页 手机的屏幕比较小 宽度通常在600像素以下 PC的屏幕宽度 一般
  • Markdown 文本居中、字体颜色以及数学公式

    文章目录 文本格式 文字居中 字体 字体颜色 字体大小 背景色 颜色 数学公式 希腊字母 行内与独行 上标 下标与组合 汉字 字体与格式 占位符 定界符与组合 四则运算 高级运算 逻辑运算 集合运算 数学符号 文本格式 文字居中 1 文字居
  • 数据结构---求最大公约数

    求最大公约数 穷举法 辗转相除法法 第一步 第二步 第三步 JAVA实现 更相减损术 第一步 第二步 第三步 JAVA实现 更相减损术与移位相结合 操作逻辑 例子 JAVA实现 写一段代码 求出两个整数的最大公约数 要尽量优化算法的性能 例
  • Python 处理错误和异常

    微信公众号 数据分析与统计学习如有问题或建议 请公众号留言最近更新时间 2018 7 2 一 前言 Python的系列文章主要介绍python语言的基础语法知识 按照核心内建数据类型 语句 函数 类 异常 标准模块的顺序对相关的语法知识进行
  • imx6ull开发板,usb免驱摄像头的配置

    在 dev下面 只能找到video0 说明开发板并没有识别出有新连接进来的摄像头 需要在内核中 配置支持UVC标准的USB驱动 重新配置即可
  • cve 爬虫_爬虫CNVD构建漏洞库

    import requests from lxml import etree import xlsxwriter from requests utils import add dict to cookiejar import execjs
  • 关于电路交换、报文交换和分组交换

    交换 所谓交换 指的就是服务器与服务器之间的数据交换 考纲要求掌握三种 电路交换 报文交换和分组交换 这篇文章主要介绍这三种交换方式 以及分组交换中的数据报和虚电路 电路交换 电路交换即在通信之前 在通信双方之间建立一条被双方独占的物理通路
  • obsidian加git备份,同时忽略掉自己不想同步的文件夹

    最近想用这个语雀进行知识库的分享 但是这个语雀的会员费太贵了 思来想去还是用 git 比较好 因为这个知识库的内容都是自己的笔记 为了能够访问的更加方便我选择了这个 gitte 而不是 github 我的知识库链接 knowledge 第一
  • 如何在sqlplus执行sql文件

    1 Oracle数据库的sqlplus可以直接执行SQL语句吗 2 SQL Plus中怎么执行多个 sql脚本文件 3 如何在sqlplus执行sql文件 4 怎样在sqlplus中批量执行sql文件 Oracle数据库的sqlplus可以
  • 在模仿中精进数据分析与可视化01——颗粒物浓度时空变化趋势(Mann–Kendall Test)

    本文是在模仿中精进数据分析与可视化系列的第一期 颗粒物浓度时空变化趋势 Mann Kendall Test 主要目的是参考其他作品模仿学习进而提高数据分析与可视化的能力 如果有问题和建议 欢迎在评论区指出 若有其他想要看的作品 也欢迎在评论