Python遥感开发之数据趋势分析Sen+mk


前言:主要使用Python完成遥感时间序列数据趋势分析Sen+mk,得到slope、trend、p、s、tau、z指标。


1 方法介绍

1.1 Theil-Sen Median方法

又被称为 Sen 斜率估计,是一种稳健的非参数统计的趋势计算方法。该方法计算效率高,对于测量误差和离群数据不敏感,常被用于长时间序列数据的趋势分析中。对于后续代码计算结果中的slope.tif解读,当slope大于0表示随时间序列呈现上升趋势;slope小于0表示随时间序列呈现下降趋势。
在这里插入图片描述

1.2 Mann-Kendall方法

Mann-Kendall是一种非参数统计检验方法,最初由Mann在1945年提出,后由Kendall和Sneyers进一步完善,其优点是不需要测量值服从正态分布,也不要求趋势是线性的,并且不受缺失值和异常值的影响,在长时间序列数据的趋势显著检验中得到了十分广泛的应用。对于后续代码计算结果中的z.tif,当|Z|大于1.65、1.96和2.58时,表示趋势分别通过了置信度为90%、95%和99%的显著性检验。
在这里插入图片描述
在这里插入图片描述

2 Python实现Sen+mk

# coding:utf-8
import numpy as np
import pymannkendall as mk
import os
import rasterio as ras

# 写影像
def writeImage(image_save_path, height1, width1, para_array, bandDes, transform1):
    with ras.open(
            image_save_path,
            'w',
            driver='GTiff',
            height=height1,
            width=width1,
            count=1,
            dtype=para_array.dtype,
            crs='+proj=latlong',
            transform=transform1,
    ) as dst:
        dst.write_band(1, para_array)
        dst.set_band_description(1, bandDes)
    del dst

def sen_mk_test(image_path, outputPath):
    # image_path:影像的存储路径
    # outputPath:结果输出路径
    global path1
    filepaths = []
    for file in os.listdir(path1):
        filepath1 = os.path.join(path1, file)
        filepaths.append(filepath1)

    # 获取影像数量
    num_images = len(filepaths)
    # 读取影像数据
    img1 = ras.open(filepaths[0])
    # 获取影像的投影,高度和宽度
    transform1 = img1.transform
    height1 = img1.height
    width1 = img1.width
    array1 = img1.read()
    img1.close()
    # 读取所有影像
    for path1 in filepaths[1:]:
        if path1[-3:] == 'tif':
            print(path1)
            img2 = ras.open(path1)
            array2 = img2.read()
            array1 = np.vstack((array1, array2))
            img2.close()
    nums, width, height = array1.shape
    # 输出矩阵,无值区用-9999填充
    slope_array = np.full([width, height], np.nan)
    z_array = np.full([width, height], np.nan)
    Trend_array = np.full([width, height], np.nan)
    Tau_array = np.full([width, height], np.nan)
    s_array = np.full([width, height], np.nan)
    p_array = np.full([width, height], 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 != num_images)
    # 输出总像元数量
    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]
        trend, h, p, z, Tau, s, var_s, slope, intercept = mk.original_test(mk_list1)
        '''        
        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  # senslope
        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]
    band_Des = ['slope', 'trend', 'p_value', 'score', 'tau', 'z_value']
    for i in range(len(all_array)):
        writeImage(image_save_paths[i], height1, width1, all_array[i], band_Des[i], transform1)

if __name__ == '__main__':
    # 调用
    path1 = r"E:\AAWORK\work\研究方向\rsei\data\年\rsei_year-25km"
    result_path = r"E:\AAWORK\work\研究方向\rsei\data\年\out"
    sen_mk_test(path1, result_path)
  • slope_array:存储每个像元的Sen’s Slope值,表示该像元的趋势斜率。
  • trend_array:存储每个像元的趋势方向,1表示增加,-1表示减少,0表示无趋势。
  • p_array:存储每个像元的p值,用于判断趋势的显著性。
  • s_array:存储每个像元的Mann-Kendall S统计量。
  • tau_array:存储每个像元的Kendall Tau值,表示相关性强度和方向。
  • z_array:存储每个像元的标准化检验统计量Z,用于计算p值并判断趋势显著性。

3 最终结果

3.1 对slope.tif以及z.tif进行重分类

  • slope>0赋值1表示增加
  • slope=0赋值0表示不变
  • slope<0赋值-1表示减少
  • |z|>1.96赋值2表示显著
  • |z|<=1.96赋值1表示不显著

3.2 对分类结果相乘

  • -2:显著减少
  • -1:不显著减少
  • 0:稳定不变
  • 1:不显著增加
  • 2:显著增加

3.3 最终结果Python代码实现

import numpy as np
import rasterio as ras

def classify_rasters(slope_path, z_path, output_path):
    with ras.open(slope_path) as slope_src, ras.open(z_path) as z_src:
        slope = slope_src.read(1)
        z = z_src.read(1)
        profile = slope_src.profile

    # 重分类
    classified_slope = np.full(slope.shape, 0, dtype=np.int8)
    classified_slope[slope > 0] = 1
    classified_slope[slope < 0] = -1

    classified_z = np.full(z.shape, 1, dtype=np.int8)
    classified_z[np.abs(z) > 1.96] = 2
    classified_z[np.abs(z) <= 1.96] = 1

    # 相乘得到最终分类结果
    final_class = classified_slope * classified_z

    # 保存结果
    with ras.open(
        output_path, 'w',
        driver='GTiff',
        height=final_class.shape[0],
        width=final_class.shape[1],
        count=1,
        dtype=final_class.dtype,
        crs=profile['crs'],
        transform=profile['transform']
    ) as dst:
        dst.write(final_class, 1)

if __name__ == '__main__':
    # 调用
    slope_path = r"E:\AAWORK\work\研究方向\rsei\data\年\out\slope.tif"
    z_path = r"E:\AAWORK\work\研究方向\rsei\data\年\out\z.tif"
    output_path = r"E:\AAWORK\work\研究方向\rsei\data\年\out\final_classification.tif"
    classify_rasters(slope_path, z_path, output_path)
  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SEN MK趋势分析是一种用于研究和预测股票市场中股票价格变动趋势的技术分析方法。SEN MK指的是用于测量股票价格趋势的指标。 SEN MK趋势分析基于股票价格历史数据,通过计算移动平均线来观察股票价格的趋势。移动平均线是用于平滑价格波动并确定趋势的一种统计工具。 SEN MK趋势分析的主要原理是当股票价格在短期移动平均线之上且短期移动平均线在长期移动平均线之上时,表明股票价格处于上升趋势;当股票价格在短期移动平均线之下且短期移动平均线在长期移动平均线之下时,表明股票价格处于下降趋势。通过观察SEN MK指标的变化,投资者可以判断股票价格的趋势,并据此做出买入或卖出的决策。 SEN MK趋势分析在股票市场中被广泛应用。它可以帮助投资者更好地理解股票市场中价格走势的规律性,并根据趋势的变化做出相应的操作策略。虽然SEN MK趋势分析只是市场分析中的一个方法,但它能够为投资者提供重要的参考依据,增加投资决策的准确性。 然而,需要注意的是,任何一种技术分析方法都不能百分之百地预测股票价格的走势。市场中存在许多不确定因素,如政策变化、宏观经济环境等,这些因素可能会对股票价格产生较大影响。因此,在使用SEN MK趋势分析时,投资者应该综合考虑其他因素,并谨慎决策。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

等待着冬天的风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值