Python实现时间序列栅格数据MK检验(Mann-Kendall)

01.Mann-Kendall 趋势检验

Mann-Kendall 趋势检验(有时称为 MK 检验)用于分析时间序列数据,以确定持续增加或减少的趋势(单调趋势)。它是一种非参数检验,这意味着它适用于所有分布(即数据不必满足正态性假设),但数据不应具有序列相关性。如果数据具有序列相关性,则可能会影响显著水平(p 值)。

02.pyMannKendall

pyMannKendall是用于非参数 Mann-Kendall 趋势测试系列的 python 包,本文中使用它实现的MK检验。一维数组的MK检验代码如下所示:

import pymannkendall as mk
import numpy as np

#创建数据
data = np.array([34, 33, 29,31,30,39,27, 26, 27, 25, 23, 21, 17, 19, 16, 14, 16, 12, 11, 9, 8])
# MK检验
mk.original_test(data)

# 输出结果
# Mann_Kendall_Test(
#    trend='decreasing', 
#    h=True, 
#    p=1.5860952995438993e-08, 
#    z=-5.651980563258717, 
#    Tau=-0.8952380952380953, 
#    s=-188.0, 
#    var_s=1094.6666666666667, 
#    slope=-1.3333333333333333, 
#    intercept=36.33333333333333)

结果解释:

trend:趋势增加、减少或无趋势(increasing, decreasing or no trend)

h:True(趋势存在)或 False(趋势不存在)

p:显著性检验的p值

z:归一化检验统计量

Tau:Kendall Tau

s:Mann-Kendall分数

var_s:方差 S

slop:Theil-Sen 斜率

intercept:截距

03.时间序列栅格数据MK检验

import glob
import os
import numpy as np
import rasterio as rio
import pymannkendall as mk

# MK检验
def apply_mk_func(arr):
    if len(arr) > 1 and not np.any(np.isnan(arr)):
        trend, h, p, z, Tau, s, var_s, slope, intercept = mk.original_test(arr)
        # 将趋势increasing, decreasing , no trend,替换为 1、-1、0
        trend_value = 0
        if trend == "decreasing":
            trend_value = -1
        elif trend == "increasing":
            trend_value = 1
        return [trend_value, h, p, z, Tau, s, var_s, slope, intercept]
    return np.full((9),np.nan)

# 输出栅格数据
def write_image(image_save_path, data_array, out_meta):
    with rio.open(
            image_save_path,
            'w',
           **out_meta,
    ) as dst:
        dst.write_band(1, data_array)
    del dst

if __name__ == "__main__":
    
    in_path = "data\\ndvi"
    out_path = "data\\ndvi_mk"
    
    file_list =  glob.glob(in_path+'\\*.tif')
    count = len(file_list)
    
    ds_f = rio.open(file_list[0])
    # 获取mate,后续导出tif时候使用;
    meta = ds_f.meta
    
    width = ds_f.width
    height = ds_f.height
    # 构建空三维数组,用于组建时间序列栅格数据;
    time_array = np.zeros((count, height, width))
    for i,file in enumerate(file_list):
        print("读取数据:{0}:{1}".format(i+1, file))
        ds = rio.open(file)
        data = ds.read(1)
        mask = ds.read_masks(1)
        data[mask == 0] = np.nan
        time_array[i] = data
    # 时间轴向应用mk检验函数
    print("=====开始mk检验=====")
    mk_result = np.apply_along_axis(apply_mk_func, 0, time_array)
    out_list = ["trend_value", "h", "p", "z", "Tau", "s", "var_s", "slope", "intercept"]
    print('=====开始导出数据=====')
    for i, out_file in enumerate(out_list):
        image_save_path = os.path.join(out_path, "{}.tif".format(out_file) )
        data_array = mk_result[i]
        write_image(image_save_path, data_array, meta)
        print("导出'{0}'数据:{1}".format(out_file, image_save_path))
    print("完成!!!")

参考文章

[1].趋势检验方法(二)MK趋势检验_mk检验-CSDN博客

[2].MK+Sen趋势检验(长时间栅格数据)_theil-sen median图像行列不一致-CSDN博客

[3].pymannkendall · PyPI

posted @ 2024-03-07 10:03  左左zopes  阅读(1700)  评论(0)    收藏  举报