1、Theil-Sen Median方法又称为Sen斜率估计,是一种稳健的非参数统计的趋势计算方法。它通过考虑数据集中所有可能的点对,计算这些点对之间的斜率,并选择这些斜率的中位数来获取整体趋势的稳健估计。Theil-Sen方法提供了一种对数据趋势的鲁棒估计。与传统的最小二乘法相比,这使得Theil-Sen方法对于异常值或离群值更为鲁棒。Theil-Sen方法是确定性的,这意味着对于给定的数据集,它总是会产生相同的结果。这有助于提高算法的可复制性和稳定性。该方法在处理时间序列分析、环境科学、金融等领域中被广泛使用。在这些领域,数据经常受到噪声、离群值或其他异常情况的影响,而Theil-Sen方法的鲁棒性使其成为一种有价值的工具,该方法计算效率高,对于测量误差和利群数据不敏感,适用于长时间序列数据的趋势分析。
2、Mann-Kendall(MK)检验是一种非参数的时间序列趋势性检验方法,与一些需要数据满足正态分布假设的方法不同,其适用于各种类型的数据分布,不需要测量值服从正太分布,Mann-Kendall方法对于数据中的离群值相对稳健,且不受缺失值和异常值的影响,适用于长时间序列数据的趋势显著检验。

在遥感图像处理中,经常会将这两种方法进行结合来分析总体的变化趋势及其显著性。比如:对下面22年的rsei影像进行分析。

python实现MK趋势检验_python


话不多说,直接上代码,有基础的可以用代码进行运算调试,没有基础的可以下载exe文件去计算,链接放下面。

import numpy as np
import pymannkendall as mk
import os
from osgeo import gdal


def write(file_name, image, projection,geotransform,x_size,y_size):
    dtype = gdal.GDT_Float32
    # 数据格式
    driver = gdal.GetDriverByName('GTIFF')
    # 创建数据,设置文件路径及名称
    new_ds = driver.Create(file_name, x_size, y_size, 1, dtype)
    # 设置投影信息及6参数
    new_ds.SetGeoTransform(geotransform)
    new_ds.SetProjection(projection)
    # 将值写入new_ds中
    new_ds.GetRasterBand(1).WriteArray(image)
    # 把缓存数据写入磁盘
    new_ds.FlushCache()
    del new_ds

def sen_mk_test(path1, result_path):
    # image_path:影像的存储路径
    # outputPath:结果输出路径
    filepaths = []
    for file in os.listdir(path1):
        filepath1 = os.path.join(path1, file)
        filepaths.append(filepath1)
    # 获取影像数量
    num_images = len(filepaths)
    # 读取影像数据
    img1 = gdal.Open(filepaths[0])
    # 获取影像的投影,高度和宽度
    transform1 = img1.GetGeoTransform()
    proj = img1.GetProjection()
    height1 = img1.RasterYSize
    width1 = img1.RasterXSize
    array1 = img1.ReadAsArray(0, 0, width1, height1)
    del img1

    # 读取所有影像
    for path1 in filepaths[1:]:
        if path1[-3:] == 'tif':
            # print(path1)
            img2 = gdal.Open(path1)
            array2 = img2.ReadAsArray(0, 0, width1, height1)
            array1 = np.vstack((array1, array2))
            del img2
    #将数组变为三维数组
    array1 = array1.reshape((num_images, height1, width1))
    # nums, width, height = array1.shape

    # 输出矩阵,无值区用nan填充
    slope_array = np.full([height1, width1], np.nan)
    z_array = np.full([height1, width1],  np.nan)
    Trend_array = np.full([height1, width1],  np.nan)
    Tau_array = np.full([height1, width1],  np.nan)
    s_array = np.full([height1, width1],  np.nan)
    p_array = np.full([height1, width1],  np.nan)
    # 只有有值的区域才进行mk检验
    c1 = np.isnan(array1)
    sum_array1 = np.sum(c1, axis=0)
    # nan_positions = np.where(sum_array1 == num_images)
    positions = np.where(sum_array1<5)

    # 输出总像元数量
    # print("all the pixel counts are {0}".format(len(positions[0])))
    # mk test
    for i in range(len(positions[0])):
        # print(i)
        x = positions[0][i]
        y = positions[1][i]
        mk_list1 = array1[:, x, y]
        # print(mk_list1)
        trend, h, p, z, Tau, s, var_s, slope, intercept = mk.original_test(mk_list1)
        # print(trend)
        # print(trend, h, p, z, Tau, s, var_s, slope, intercept)


        # '''
        # trend: tells the trend (increasing, decreasing or no trend)
        #         h: True (if trend is present) or False (if trend is absence)
        #         p: p-value of the significance test
        #         z: normalized test statistics
        #         Tau: Kendall Tau
        #         s: Mann-Kendal's score
        #         var_s: Variance S
        #         slope: Theil-Sen estimator/slope
        #         intercept: intercept of Kendall-Theil Robust Line
        # '''

        if trend == "decreasing":
            trend_value = -1
        elif trend == "increasing":
            trend_value = 1
        else:
            trend_value = 0
        slope_array[x, y] = slope
        s_array[x, y] = s
        z_array[x, y] = z
        Trend_array[x, y] = trend_value
        p_array[x, y] = p
        Tau_array[x, y] = Tau
    all_array = [slope_array, Trend_array, p_array, s_array, Tau_array, z_array]
    slope_save_path = os.path.join(result_path, "slope.tif")
    Trend_save_path = os.path.join(result_path, "Trend.tif")
    p_save_path = os.path.join(result_path, "p.tif")
    s_save_path = os.path.join(result_path, "s.tif")
    tau_save_path = os.path.join(result_path, "tau.tif")
    z_save_path = os.path.join(result_path, "z.tif")
    image_save_paths = [slope_save_path, Trend_save_path, p_save_path, s_save_path, tau_save_path, z_save_path]
    for i in range(len(all_array)):
        write(image_save_paths[i], all_array[i], proj, transform1, width1, height1)


if __name__ == '__main__':
    # 调用
    path1 = r"F:\rsei"
    result_path = r"F:\结果"
    sen_mk_test(path1, result_path)

程序自取:
我用夸克网盘分享了「MK_Sen趋势检验.exe」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/66815b080ac4
提取码:sSBu