GEE(python)使用GPM降水数据进行趋势分析,MK检验等

目录

    • 1.引用库
    • 2.定义函数
    • 4.趋势分析及MK检验
    • 5.结果图像保存至本地

这段时间有关GPM降水分析的一些代码总结:

1.引用库

#Edited by Xinglu Cheng 2022.01.06
#读取半小时降水数据变为日数据,获取超过90%阈值的总降水量
import ee
import os
import threading
import numpy as np
import matplotlib.pyplot as plt
from osgeo import gdal
from ipygee import Map
from IPython.display import Image
import sys
sys.setrecursionlimit(10000)#修改递归深度

import geemap
import geemap.colormaps as cm
gee_Map = geemap.Map(center=[36.56, 116.98], zoom=6)
gee_Map.add_basemap('Gaode.Normal')

#加入研究区
HHH = ee.FeatureCollection("users/2210902126/GPM/HHH_Area")
    

2.定义函数

#归一化处理---------------------------------------------------------------------------------------------------------------------------
def UnitToOne(image):
    minMax = image.reduceRegion(
        reducer = ee.Reducer.minMax(),
        geometry = HHH,
        scale = 11132,
        maxPixels = 10e9
    )
    name = ee.String(image.bandNames().get(0))
    return image.unitScale(ee.Number(minMax.get(name.cat('_min'))), ee.Number(minMax.get(name.cat('_max'))))

#重采样-------------------------------------------------------------------------------------------
def repro(image):
    image=image.reproject(crs='EPSG:4326',scale=11132)
    return image

#半小时数据转为日数据函数--------------------------------------------------------------------------
DailyPre=ee.List([])
def toDaily(year, EndYear, DailyPre):
    if year > EndYear:
        return DailyPre

    for i in range(1, 13):
        if i == 1 or i == 3 or i == 5 or i == 7 or i == 8 or i == 10 or i == 12: day = 31
        if i == 4 or i == 6 or i == 9 or i == 11: day = 30
        if i == 2 and year % 4 != 0 or i == 2 and year % 4 == 0 and year % 400 != 0: day = 28
        if i == 2 and year % 4 == 0 and year % 100 != 0 or i == 2 and year % 4 == 0 and year % 400 == 0: day = 29
         # 判断一个月的天数

        for d in range(1, day+1):
            if i >= 10 and day >= 10: extend = ee.Date(str(year) + '-' + str(i) + '-' + str(d))
            if i >= 10 and day < 10: extend = ee.Date(str(year) + '-' + str(i) + '-0' + str(d))
            if i < 10 and day >= 10: extend = ee.Date(str(year) + '-0' + str(i) + '-' + str(d))
            if i < 10 and day < 10: extend = ee.Date(str(year) + '-0' + str(i) + '-0' + str(d))
            # 判断月份是否是两位数,两位数不需要加0
            DailyPre= DailyPre.add(ee.ImageCollection("NASA/GPM_L3/IMERG_V06").filter(ee.Filter.date(extend.getRange('day'))).select('precipitationCal').sum().multiply(0.5).clip(HHH).set({'system:time_start': extend}))
            # 将半小时数据变为日数据,并加入日期属性

    year+=1
    return toDaily(year, EndYear, DailyPre)  # 递归

#获取影像的经纬度---------------------------------------------------------------------------------
def getImgData(image):
  image = image.addBands(ee.Image.pixelLonLat())
  data = image.reduceRegion(
      reducer = ee.Reducer.toList(),
      geometry = HHH,
      scale = 11132,
      maxPixels = 1e13
  )
  lat = np.array(ee.Array(data.get("latitude")).getInfo())
  lon = np.array(ee.Array(data.get("longitude")).getInfo())
  return lat, lon

#获取各种各样的信息-------------------------------------------------------------------------------
example=ee.ImageCollection("NASA/GPM_L3/IMERG_V06").filter(ee.Filter.date(ee.Date('2019-09-03').getRange('day'))).select('precipitationCal').sum().multiply(0.5).clip(HHH)#获取一个图像
example=repro(example)#重采样
print(example.getInfo())
row=geemap.ee_to_numpy(example,region=HHH,default_value=-999).squeeze().shape[0]
col=geemap.ee_to_numpy(example,region=HHH,default_value=-999).squeeze().shape[1]#获取行列号
lat,lon=getImgData(example)
lat_min=lat.max()
lon_min=lon.min()
print(lat_min,lon_min)#输出左上角经纬度

3.调用函数以及reducer进行分析
方法1的结果可以直接用geemap进行显示;
方法2由于数据量太大,转为numpy处理,用gdal转为图像存至本地。

#方法1:对每个像元进行筛选,统计超过百分比阈值的日数------------------------------------------------
# year_begin = 2001
# year_end = 2002
# DailyPre=toDaily(year_begin,year_end,DailyPre)#应用函数

# DailyCollection=ee.ImageCollection.fromImages(DailyPre)#将list变为图像集
# def subtract(image):
#     image=image.subtract(Percentile)#减去阈值
#     image=image.mask(image.gt(0))#把小于0的部分变为无效值
#     return image

# Percentile = DailyCollection.reduce(ee.Reducer.percentile([90]))#计算区间百分比内的平均值
# GreaterSubtract = DailyCollection.map(subtract)
# CountDaily= GreaterSubtract.reduce(ee.Reducer.count())#计算每个像元非零值的个数,即大于阈值的个数

#方法2:计算20年的极端降水的总降水量变化趋势--------------------------------------------------------
#定义函数:将阈值以下的部分掩膜
def calculate(year,DailyPre):
    DailyPre=toDaily(year,year,DailyPre)#应用函数
    DailyCollection=ee.ImageCollection.fromImages(DailyPre)
    Percentile = DailyCollection.reduce(ee.Reducer.percentile([90]))#计算区间百分比值
    def subtract(image):
        imageb=image.subtract(Percentile)#减去阈值
        image=image.mask(imageb.gt(0))#把小于0的部分变为无效值
        return image
    DailySubtract = DailyCollection.map(subtract).sum().set("date",ee.Number(i))#提取极端降水事件,计算极端降水的总降水量,并添加年份属性
    return DailySubtract

year_begin = 2001
year_end = 2022
bands = 0
for i in range(year_begin,year_end):
    DailySubtract = calculate(i,DailyPre)
    DailySubtract = repro(DailySubtract)
    if bands==0:
        numArray=geemap.ee_to_numpy(DailySubtract,region=HHH,default_value=-999)
        DailyArray=numArray.copy()
    else:
        numArray=geemap.ee_to_numpy(DailySubtract,region=HHH,default_value=-999).squeeze()#图像转数组
        DailyArray=np.insert(DailyArray,bands,numArray,axis=2)#将数组存入
    bands += 1
    print(i)

4.趋势分析及MK检验

使用方法2的结果数组(每年超过90%百分值的总降水量)进行分析

#线性倾向-----------------------------------------------------------------------------------------
# from sklearn.linear_model import LinearRegression

# #使用线性回归模型进行建模
# y = np.arange(2001,2022,1).reshape(-1, 1)#因变量
# LinearData = np.array([])#创建一个空的数组存储数据
# for i in range(row):
#     for j in range(col):
#         x = DailyArray[i,j,:].reshape(bands).reshape(-1, 1)
#         if x[0] == -999:
#             Data = -999
#         else:
#             LinearModel = LinearRegression()
#             LinearModel.fit(x,y)#使用自变量x和因变量y进行训练模型
#             Data = float(LinearModel.coef_[0])
#         LinearData = np.append(LinearData,Data)
        
# LinearData=LinearData.reshape(row,col)#变为二维数组       
# print(LinearData)

#标准差,中位数 验证波动性-------------------------------------------------------------------------
# LinearData = np.array([])#创建一个空的数组存储数据
# for i in range(row):
#     for j in range(col):
#         x = DailyArray[i,j,:].reshape(bands)
#         if x[0] == -999:
#             Data = -999
#         else:
#             Data = np.std(x)#求标准差
#             # Data = np.median(x)#求中位数
#         LinearData = np.append(LinearData,Data)
        
# LinearData=LinearData.reshape(row,col)#变为二维数组       
# print(LinearData)

#sen_MK趋势分析-----------------------------------------------------------------------------------
import pymannkendall as mk
LinearData = np.array([])#创建一个空的数组存储数据
for i in range(row):
    for j in range(col):
        x = DailyArray[i,j,:].reshape(bands)
        if x[0] == -999:
            Data = -999
        else:
            trend, h, p, z, Tau, s, var_s, slope, intercept = mk.original_test(x)
            #trend:增加减少或没有趋势(1.,-1,0)
            #h:趋势是否存在,True为存在,False为不存在
            #p:显著性检验的p值
            #z:normalized test statistics 正态分布检验统计
            #Tau:Kendall Tau 相关系数
            #s:Mann-Kendal's score 
            #var_s:Variance S
            #slope:senslope 
            if trend=="decreasing":
                trend_value=-1
            elif trend=="increasing":
                trend_value=1
            else:
                trend_value=0
            Data=slope#设置输出的要素
        LinearData = np.append(LinearData,Data)
        
LinearData=LinearData.reshape(row,col)#变为二维数组       
print(LinearData)

#MK突变分析---------------------------------------------------------------------------------------
# from scipy import stats
# def sk(data):
#     n=len(data)
#     Sk     = [0]
#     UFk    = [0]
#     s      =  0
#     E      = [0]
#     Var    = [0]
#     for i in range(1,n):
#         for j in range(i):
#             if data[i] > data[j]:
#                 s = s+1
#             else:
#                 s = s+0
#         Sk.append(s)
#         E.append((i+1)*(i+2)/4 )                     # Sk[i]的均值
#         Var.append((i+1)*i*(2*(i+1)+5)/72 )            # Sk[i]的方差
#         UFk.append((Sk[i]-E[i])/np.sqrt(Var[i]))
#     UFk=np.array(UFk)
#     return UFk

# #a为置信度
# def MK(data,a):
#     ufk=sk(data)          #顺序列
#     ubk1=sk(data[::-1])   #逆序列
#     ubk=-ubk1[::-1]        #逆转逆序列
    
#     #输出突变点的位置
#     p=[]
#     u=ufk-ubk
#     for i in range(1,len(ufk)):
#         if u[i-1]*u[i]<0:
#             p.append(i)            
#     if p:
#         return p
#     else:
#         p = 0
#         return p 
    
#     #画图
# #     conf_intveral = stats.norm.interval(a, loc=0, scale=1)   #获取置信区间

# #     plt.figure(figsize=(10,5))
# #     plt.plot(range(len(data)),ufk,label = 'UFk',color = 'r')
# #     plt.plot(range(len(data)),ubk,label = 'UBk',color = 'b')
# #     plt.ylabel('UFk-UBk',fontsize=25)
# #     x_lim = plt.xlim()
# #     plt.ylim([-6,7])
# #     plt.plot(x_lim,[conf_intveral[0],conf_intveral[0]],'m--',color='r',label='95%显著区间')
# #     plt.plot(x_lim,[conf_intveral[1],conf_intveral[1]],'m--',color='r')
# #     plt.axhline(0,ls="--",c="k")
# #     plt.legend(loc='upper center',frameon=False,ncol=3,fontsize=20) # 图例
# #     plt.xticks(fontsize=25)
# #     plt.yticks(fontsize=25)
# #     plt.show()

# #输入数据和置信度即可
# LinearData = np.array([])#创建一个空的数组存储数据
# for i in range(row):
#     for j in range(col):
#         x = DailyArray[i,j,:].reshape(bands)
#         if x[0] == -999:
#             Data = -999
#         else:
#             Data=MK(x,0.95)#设置输出的要素
#             if Data!=0:
#                 Data=len(Data)
#         LinearData = np.append(LinearData,Data)
        
# LinearData=LinearData.reshape(row,col)#变为二维数组       
# print(LinearData)

5.结果图像保存至本地

#输出图像
def write_tif(newpath,im_data,im_Geotrans,im_proj,datatype):
    if len(im_data.shape)==3:
        im_width, im_height, im_bands = im_data.shape
    else:
        im_bands, (im_height, im_width) = 1, im_data.shape
    diver = gdal.GetDriverByName('GTiff')
    new_dataset = diver.Create(newpath, im_width, im_height, im_bands, datatype)
    new_dataset.SetGeoTransform(im_Geotrans)
    new_dataset.SetProjection(im_proj)

    if im_bands == 1:
        new_dataset.GetRasterBand(1).WriteArray(im_data)
    else:
        for i in range(im_bands):
            new_dataset.GetRasterBand(i+1).WriteArray(im_data[i])
    del new_dataset

#设置投影和仿射变换
im_Geotrans=(lon_min, 0.10000045742818513, 0.0, lat_min, 0.0, -0.10000045742818513)#投影参数随图像修改
im_proj='GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]'
#调用输出函数
newpath=os.path.expanduser('~')
newpath = os.path.join(newpath, '_name_.tif')#输入名称
write_tif(newpath,LinearData,im_Geotrans,im_proj,gdal.GDT_Float32)

你可能感兴趣的:(python,开发语言,后端)