点击下方公众号,回复 资料 ,收获惊喜
引入相关包和导入数据:
import numpy as np import xarray as xr from matplotlib import pyplot as plt # 数据导入 path = "...\\sst.mnmean.nc" # 丢弃一个不必要导入的变量 ds = xr.open_dataset(path, drop_variables=["time_bnds"]) ds = ds.sel(time=slice("1960", "2018")).load()
现代气候学认为在相当长的时间段(一般认为是 30 年)中,变量多年平均是一个稳定的值。因此在一个时间段中,如果能够充分认识变量随平均状态的变化趋势,那么对于预测未来情况是非常有利的。那么这个所谓随着平均态的偏移值便可称为 距平(异常,anomaly) .
距平
下面便提出一个问题: 为什么要费尽心思研究变量的距平而非变量的原始数据 ?若针对于温度这个变量而言,即为什么要使用温度距平(偏离平均值的值)而不非研究绝对温度的变化?
出于以下几个原因,很难对全球平均表面温度以绝对温度的形式进行计算。
某些地域的气象观测 站点分布 稀少(如撒哈拉沙漠地区、偏远的密林),这就意味着为取得格点数据(栅格数据)必须对离散的站点数据值在较大且站点分布稀疏区域内进行插值。这会带来很大的数据不真实性。
对于那些山区中的数据(山区中的的气象观测大多是有人居住地区),必须考虑 海拔高度 对区域平均温度的 影响 。例如,对于一个地区的夏季而言,无论是在山顶还是山下,都可能比往年的平均温度低,然而若考虑绝对温度,这两个地方有很大的不同(一般认为山顶气温比山下温度低)。
在同一时间范围内在一个更小的尺度下(即格点分辨率)考虑变量变化的基准参考值,然后基于这个基准参考值(多年平均值)计算相对于这个基准参考值的异常变化(距平)。在这种情况下,整合了数据,使得 不同地域的变量 能够得以 进行比较 ,以便反映一个区域内不同地方的变量分布形式。
来源:https://www.ncdc.noaa.gov/monitoring-references/faq/anomalies.php
下面需从数据集中 删除 气候平均,从而得到变量随气候平均态变化的残差。一般将这个残差称为距平。
对转换(Transformations)操作而言,消除数据的气候平均是一个很好的例子。转换操作对分组的对象进行操作,但不改变原数据的维度尺寸。
xarray 通过使用 Groupby 算法 使这些类型的转换变得容易。下面给出了计算去除月份温度差异的海温月数据。
def remove_time_mean(x): return x - x.mean(dim="time") ds_anom = ds.groupby("time.month").map(remove_time_mean) ds_anom
也可以简写为下面这种形式
gb = ds.groupby("time.month") ds_anom = gb - gb.mean(dim="time") ds_anom
ds_anom
gb 是分好月份后的海温数据(12 组), gb.mean(dim="time") 是各月的平均海温(12 组),那么 gb - gb.mean(dim="time") 即为对 12 组中的对应组的海温数据(这个组内的每一天的海温数据)减去平均的海温数据。这个结果即为距平。
gb
gb.mean(dim="time")
gb - gb.mean(dim="time")
当经过上述去除季节性周期的影响后,便很容易发现气候变率的信号。
ds_anom.sst.sel(lon=300, lat=50).plot()
北大西洋单点的时间序列
(ds_anom.sel(time="2018-01-01") - ds_anom.sel(time="1960-01-01")).sst.plot()
2018年1月1日与1960年1月1日之间SST之间的差异
xarray 中的 Resample (重采样)的处理方法与 Pandas 包几乎相同。就本质而言,Resample 也是一个分割数据的操作。它与分割操作的基本语法类似。应当注意,对于 Resample 操作而言,其作用对象必须是时间维度。
为说明 Resample 的用法,下面给出一个例子计算逐五年的平均值曲线。
resample_obj = ds_anom.resample(time="5Y") resample_obj
resample_obj
可以看到对于 Resample 操作而言,与 Groupby 操作非常类似,首先也创建了一个 DatasetResample 对象。 .resample(time="5Y") 是对如何对时间进行重采样进行设置,维度为 time ,设置的时间间隔为 5 年。应当指出这里的时间间隔写法与之前 pd.date_range 函数中的 freq 的时间间隔的关键词是一致的。
DatasetResample
.resample(time="5Y")
time
pd.date_range
freq
ds_anom_resample = resample_obj.mean(dim="time") ds_anom_resample
ds_anom_resample
之后就需要对这些分割好的 Resample 对象进行取平均,以便获得每一个分组好的 Resample 对象中的平均值。
假如第一个 Resample 对象的时间范围为 2010 年-2014 年,那么需要对这五年进行平均后,以便得到第一个进行重采样后的值。往后的时间范围类似。
为了说明进行重采样后的效果,下面来看一下(50°N, 60°E)的海温变化情况
ds_anom.sst.sel(lon=300, lat=50).plot() ds_anom_resample.sst.sel(lon=300, lat=50).plot(marker="o")
(50°N, 60°E) 的海温变化
第一行代码将原始海温变化的时间序列画了出来,第二行画了经逐 5 年平均后的海温变化的时间序列。
.plot(marker="o") 中的参数 marker="o" 指定了点的记号类型。如 下图[1] 是关于 marker 参数的可设置类型
.plot(marker="o")
marker="o"
marker
matplotlib.markers
注意:resample 仅能用于正确的日期、时间索引。
Pandas Rolling (Source: forgifs.com)
Rolling 方法也与 pandas 包[2] 中的类似,但是稍有不同的是,它可适用于任意维度。如果将其作用于时间维度,也可称之为 滑动平均 。
ds_anom_rolling = ds_anom.rolling(time=12, center = True).mean() ds_anom_rolling
ds_anom_rolling
参数 time=12 指定了对维度 time 以 12 个月为周期(月数据)变动时间窗, center 参数表明以当前窗的两侧筛选数据,否则是以当前窗的前 12 个月作为筛选目标(包括本身)。 .mean() 表明对每一个 Rolling 对象取平均。
time=12
center
.mean()
为了更好的说明 Rolling 的作用,下面举一个简单的例子说明其功能。
da = xr.DataArray( np.linspace(0, 11, num=12), dims="time", coords=[ pd.date_range("1999-12-15",periods=12,freq=pd.DateOffset(months=1))
da
此处创建 DataArray 类型 da 的方法与之前创建 DataArray 稍有不同。 np.linspace(0, 11, num=12) 代表创建数组的初始值为 0,终末值为 11,并且在这个范围内均匀间隔生成 12 个样本。关于这个函数的说明,可参考 numpy.linspace[3] .
np.linspace(0, 11, num=12)
dims 的创建与之前的类似,但 coords 就有着明显的区别,此处的 coords 是一个元组列表(用方括号包裹,List),而之前的教程中创建的是一个字典(用花括号包裹,dict). 两者创建的区别在于如果用 列表 创建 DataArray 的话, 坐标名称和维度名称是重名 的(Coordinates 项会加粗或者在名称前加*)。若要创建非索引坐标,则必须通过字典创建。
dims
coords
对于多个维度的创建,列表的创建方法也与之前的字典创建方法类似
foo = xr.DataArray( np.random.rand(4, 3), dims=("time", "space"), coords=[ pd.date_range("2000-01-01", periods=4), ["IA", "IL", "IN"],
foo
多个维度 dims 需用小括号或者方括号包裹。不同的 coords 之间的参数用逗号间隔,因为用列表创建坐标维度的特性,无需写坐标维度名称。坐标维度的名称将沿用维度名称的名字。
首先先创建一个时间窗对象
da.rolling(time=5, center=True)