sacpy使用指南
sacpy 文档合集
安装
pip install sacpy注意:必须用pip,该库没有发布在conda-forge中
经验正交函数(EOF)分析
导入
import numpy as npimport xarray as xrfrom sacpy import EOFclass EOF
EOF(经验正交函数)分析类,用于将时空场分解为空间模态和时间系数。
EOF(data, weights=None)
作用:初始化 EOF 分析对象。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data | np.ndarray / xr.DataArray | 必需 | 输入数据,形状 (time, *space) |
weights | np.ndarray / None | None | 空间权重,形状可广播至空间维度。常见用法:纬度余弦平方根权重 np.sqrt(cos(lat)) |
注意:若传入 xr.DataArray,内部会转为 numpy 数组。
solve(method="eig", st=False, dim_min=10, chunks=None)
作用:求解 EOF,得到特征值和特征向量。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
method | str | "eig" | 求解方法: - "eig":协方差矩阵特征分解- "svd":SVD 分解(适合 time < space 的情况)- "dask_svd":使用 Dask 的 SVD(需 dask 库) |
st | bool | False | 是否打印求解起止时间 |
dim_min | int | 10 | eig 模式下的最小维度(SVD 模式自动取 min(time, space)) |
chunks | tuple / None | None | dask_svd 模式的块大小,必须提供 |
无返回值,结果保存在对象属性中。
使用示例:
# 准备数据(异常场)sst = xr.open_dataset('sst.nc')['sst']sst_anom = sst - sst.groupby('time.month').mean('time')
# 纬度权重coslat = np.cos(np.deg2rad(sst_anom['lat'].values))
# EOF 分析eof_obj = EOF(sst_anom, weights=np.sqrt(coslat))eof_obj.solve(method="eig")get_eign(npt=4)
作用:获取前 n 个特征值(未缩放)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 4 | 返回的特征值数量 |
返回:np.ndarray,形状 (npt,)
使用示例:
eign = eof_obj.get_eign(npt=3)get_varperc(npt=None)
作用:返回各模态解释的方差比例(0~1)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int / None | None | 返回数量。None 返回所有 |
公式:var_perc[i] = eigenvalue[i] / sum(variance_of_all_space_points)
返回:np.ndarray,形状 (npt,)
使用示例:
vf = eof_obj.get_varperc(npt=5)print(vf) # 前5个模态的方差解释比例north_test(npt=10, perc=False, ddof=None)
作用:使用 North et al. (1982) 方法计算特征值的典型误差。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 10 | 检验的模态数量 |
perc | bool | False | 是否按总方差缩放(True 时误差尺度同 get_varperc) |
ddof | int / None | None | 自由度。None 默认使用 time_length |
返回:np.ndarray,形状 (npt,)
使用示例:
errors = eof_obj.north_test(npt=5)evals = eof_obj.get_eign(5)
# 判断是否显著分离for i in range(4): if evals[i] - errors[i] > evals[i+1] + errors[i+1]: print(f"模式 {i+1} 与 {i+2} 分离良好")get_pc(npt=None, scaling="std")
作用:获取主成分时间序列(PCs)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int / None | None | 返回的 PC 数量。None 返回所有 |
scaling | str | "std" | 缩放方式: - None:不缩放(原始 PC)- "std":除以标准差,使每个 PC 方差为 1- "DSE":除以 sqrt(特征值)- "MSE":乘以 sqrt(特征值) |
返回:np.ndarray,形状 (npt, time)
使用示例:
# 获取前3个标准化 PCpcs = eof_obj.get_pc(npt=3, scaling="std")
# 获取所有未缩放 PCpcs_raw = eof_obj.get_pc(scaling=None)
# 获取第1个 PC(E 型缩放)pc1 = eof_obj.get_pc(npt=1, scaling="MSE")get_pt(npt=None, scaling="mstd")
作用:获取空间模态(patterns / EOFs)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int / None | None | 返回的模式数量 |
scaling | str | "mstd" | 缩放方式: - None:不缩放(原始特征向量)- "std"(即 "mstd"):乘以 PC 的标准差- "DSE":除以特征值- "MSE":乘以特征值 |
返回:np.ndarray,形状 (npt, *origin_space_shape)
使用示例:
# 获取前3个空间模态(与标准化PC匹配)patterns = eof_obj.get_pt(npt=3, scaling="mstd")
# 获取原始特征向量(不缩放)patterns_raw = eof_obj.get_pt(npt=3, scaling=None)correlation_map(npt)
作用:计算每个 EOF 模式对应的空间相关系数图(PC 与原始场每个格点的相关系数)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 必需 | 计算的模式数量 |
返回:np.ndarray,形状 (npt, *origin_space_shape),值域 [-1, 1]
使用示例:
corr_maps = eof_obj.correlation_map(npt=3)# corr_maps[0] 为第1模态的相关系数空间分布projection(proj_field, npt=None, scaling="std")
作用:将新场投影到已有的 EOF 空间模态上,得到伪 PC。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
proj_field | np.ndarray | 必需 | 待投影场,形状 (time, *space) |
npt | int / None | None | 投影到前几个模态 |
scaling | str | "std" | PC 缩放方式(同 get_pc 的 scaling) |
返回:np.ndarray,形状 (npt, proj_time)
使用示例:
# 将新的海温场投影到前3个 EOF 上new_sst = xr.open_dataset('new_sst.nc')['sst'].valuespseudo_pcs = eof_obj.projection(new_sst, npt=3)decoder(pcs)
作用:用给定的 PC 和已有的空间模态重构原始场。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
pcs | np.ndarray | 必需 | PC 序列,形状 (*time, pc_num) |
返回:np.ndarray,形状 (*time, *origin_space_shape)。若初始化时提供了 weights,重构时会自动除以权重。
使用示例:
# 用第1个 PC 重构场pc1 = eof_obj.get_pc(npt=1, scaling="std")recon = eof_obj.decoder(pc1.T) # 注意 transpose# recon 形状:(time, lat, lon)load_pt(patterns)
作用:从外部加载空间模态(用于解码等操作)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
patterns | np.ndarray | 必需 | 空间模态,形状 (npt, *space) |
使用示例:
eof_obj.load_pt(precomputed_patterns)完整示例:EOF 分析+绘图
import numpy as npimport xarray as xrimport matplotlib.pyplot as pltimport cartopy.crs as ccrsfrom sacpy import EOF
# 1. 数据准备da = xr.open_dataset('sst.nc')['sst']da_anom = da.groupby('time.month') - da.groupby('time.month').mean('time')
# 2. EOF 分析coslat = np.cos(np.deg2rad(da_anom['lat'].values))eof = EOF(da_anom, weights=np.sqrt(coslat))eof.solve()vf = eof.get_varperc()print(f"EOF1 方差解释: {vf[0]:.2%}")
# 3. 获取结果pc1 = eof.get_pc(npt=1, scaling="std") # (1, time)pt1 = eof.get_pt(npt=1, scaling="mstd") # (1, lat, lon)corr_map = eof.correlation_map(npt=1) # (1, lat, lon)
# 4. 绘图(使用 sacpy 的绘图扩展)import sacpy.Map # 注册 GeoAxesSubplot 扩展方法
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=190))c = ax.scontourf(da_anom['lon'], da_anom['lat'], corr_map[0], cmap='RdBu_r')ax.init_map(coastlines=True)plt.colorbar(c, label='Correlation')plt.title('EOF1 Correlation Map')plt.show()奇异值分解(SVD)/ 最大协方差分析(MCA)
导入
import numpy as npimport xarray as xrfrom sacpy import SVD, MCA # MCA 是 SVD 的别名class SVD
SVD(奇异值分解)分析类,用于研究两个场之间的耦合关系。MCA 是其别名。
SVD(data1, data2, complex=False)
作用:初始化 SVD 分析对象。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data1 | np.ndarray / xr.DataArray | 必需 | 左场数据,形状 (time, *space1) |
data2 | np.ndarray / xr.DataArray | 必需 | 右场数据,形状 (time, *space2) |
complex | bool | False | 是否使用复数类型 |
注意:data1 和 data2 的时间维度必须相等。
solve()
作用:求解 SVD,计算协方差矩阵并分解。
无参数,无返回值。结果保存在对象属性中。
使用示例:
svd_obj = SVD(sst_anom, precip_anom)svd_obj.solve()get_eign()
作用:返回协方差矩阵的奇异值。
返回:np.ndarray
使用示例:
eign = svd_obj.get_eign()get_varperc(npt)
作用:返回各 SVD 模态的方差解释比例(基于奇异值平方的占比)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 必需 | 返回的模式数量 |
公式:var_perc[i] = eign[i]^2 / sum(eign^2)
返回:np.ndarray,形状 (npt,)
使用示例:
vf = svd_obj.get_varperc(npt=5)get_pc(npt, norm="std")
作用:获取左场和右场的时间系数(expansion coefficients)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 必需 | 返回的模式数量 |
norm | str | "std" | 标准化方式: - "std":除以各自的标准差- 其他值:不做标准化 |
返回:(pc_left, pc_right),均为 np.ndarray,形状 (npt, time)
使用示例:
pc_left, pc_right = svd_obj.get_pc(npt=3, norm="std")get_pt(npt, norm="std")
作用:获取左场和右场的空间模态(SVD patterns)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 必需 | 返回的模式数量 |
norm | str | "std" | 标准化方式。"std" 时乘以对应 PC 的标准差 |
返回:(patterns_left, patterns_right),形状分别为 (npt, *space1) 和 (npt, *space2)
使用示例:
pt_left, pt_right = svd_obj.get_pt(npt=3)# pt_left 形状: (3, lat1, lon1)# pt_right 形状: (3, lat2, lon2)get_homogeneous_map(npt=3, norm="std")
作用:获取齐次相关图(homogeneous correlation map)—— 每个 SVD 模态的 PC 与自身场之间的线性回归图。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 3 | 计算的模式数量 |
norm | str | "std" | 标准化方式 |
返回:(map_left, map_right),形状同 get_pt
使用示例:
homo_left, homo_right = svd_obj.get_homogeneous_map(npt=3)get_heterogeneous_map(npt=3, norm="std")
作用:获取非齐次相关图(heterogeneous correlation map)—— 左场 PC 与右场数据的回归图,以及右场 PC 与左场数据的回归图。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 3 | 计算的模式数量 |
norm | str | "std" | 标准化方式 |
返回:(map_left, map_right)
使用示例:
hetero_left, hetero_right = svd_obj.get_heterogeneous_map(npt=3)注意:当前实现中
get_homogeneous_map和get_heterogeneous_map逻辑相同,均返回 PC 与对应原始场的回归系数图。
get_var_contribution(npt=3)
作用:计算各 SVD 模态对左场和右场总方差的贡献比例。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
npt | int | 3 | 计算的模式数量 |
返回:(left_var, right_var),均为 np.ndarray,形状 (npt,)
公式:var[i] = sum(PC_i^2) / sum(data^2)
使用示例:
left_contrib, right_contrib = svd_obj.get_var_contribution(npt=3)print(f"SVD1 对左场方差贡献: {left_contrib[0]:.2%}")print(f"SVD1 对右场方差贡献: {right_contrib[0]:.2%}")完整示例:SVD 分析
import numpy as npimport xarray as xrimport matplotlib.pyplot as pltimport cartopy.crs as ccrsfrom sacpy import SVD, get_anom
# 1. 数据准备sst = xr.open_dataset('sst.nc')['sst']precip = xr.open_dataset('precip.nc')['precip']
sst_anom = get_anom(sst) # (time, lat, lon)precip_anom = get_anom(precip) # (time, lat, lon)
# 2. SVD 分析svd = SVD(sst_anom, precip_anom)svd.solve()
# 3. 获取结果pc_left, pc_right = svd.get_pc(npt=3, norm="std")hetero_left, hetero_right = svd.get_heterogeneous_map(npt=2)
# 4. 绘图 - 第1 SVD 模态的非齐次相关图import sacpy.Map
fig, axes = plt.subplots(1, 2, subplot_kw={ 'projection': ccrs.PlateCarree(central_longitude=190)})
ax = axes[0]c = ax.scontourf(sst_anom['lon'], sst_anom['lat'], hetero_left[0], cmap='RdBu_r', extent='both')ax.init_map(coastlines=True)ax.set_title('Heterogeneous Map (SST ← Precip PC)')
ax = axes[1]c = ax.scontourf(precip_anom['lon'], precip_anom['lat'], hetero_right[0], cmap='RdBu_r', extent='both')ax.init_map(coastlines=True)ax.set_title('Heterogeneous Map (Precip ← SST PC)')
plt.show()线性回归
导入
import numpy as npimport xarray as xrfrom sacpy import LinReg, MultLinReg# 或直接使用底层函数from sacpy.linger_cal import linear_reg, multi_linreg, multi_corr, partial_corrclass LinReg
一元线性回归类。
LinReg(x, y, neff=None)
作用:进行一元线性回归 y = slope * x + intercept。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray / xr.DataArray | 必需 | 自变量(预测因子),形状 (time,) |
y | np.ndarray / xr.DataArray | 必需 | 因变量(响应变量),形状 (time, *space) |
neff | int / None | None | 有效自由度(用于 T 检验)。None 时使用 time-2 |
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
slope | np.ndarray / xr.DataArray | 回归斜率,形状 (*space) |
intcpt | np.ndarray / xr.DataArray | 截距,形状 (*space) |
corr | np.ndarray / xr.DataArray | 相关系数,形状 (*space),值域 [-1, 1] |
p_value | np.ndarray / xr.DataArray | p 值(双尾 T 检验),形状 (*space) |
使用示例:
# 对 ENSO 指数与海温场做回归enso_idx = enso_idx # shape: (time,)reg = LinReg(enso_idx, sst_anom)
# 获取回归系数slope_map = reg.slope # shape: (lat, lon)corr_map = reg.corr # 相关系数pval_map = reg.p_value # 显著性
# 若输入为 xr.DataArray,输出自动保留坐标LinReg.mask(threshold=0.05)
作用:按 p 值阈值掩码不显著区域。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
threshold | float | 0.05 | p 值阈值,超过此值的格点设为 NaN |
无返回值,生成三个新属性:slope1、intcpt1、corr1。
使用示例:
reg.mask(threshold=0.05)# 使用 reg.slope1 / reg.corr1 获取仅显著区域的回归图class MultLinReg
多元线性回归类。
MultLinReg(x, y, cal_sim=True)
作用:进行多元线性回归 y = slope[0]*x[0] + slope[1]*x[1] + ... + intercept。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray / xr.DataArray | 必需 | 因子矩阵,形状 (time, N_factor) |
y | np.ndarray / xr.DataArray | 必需 | 因变量,形状 (time, *space) |
cal_sim | bool | True | 是否在初始化时自动计算回归结果 |
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
slope | np.ndarray | 回归系数,形状 (N_factor, *space) |
intcpt | np.ndarray | 截距,形状 (*space) |
R | np.ndarray | 复相关系数,形状 (*space) |
pv_all | np.ndarray | 整体 F 检验 p 值,形状 (*space) |
pv_i | np.ndarray | 各因子 F 检验 p 值,形状 (N_factor, *space) |
使用示例:
# 三个因子对海温的多元回归factors = np.column_stack([enso, pdo, amo]) # (time, 3)reg_m = MultLinReg(factors, sst_anom)
# ENSO 单独的回归系数场enso_slope = reg_m.slope[0] # 第1个因子的斜率场enso_pval = reg_m.pv_i[0] # 第1个因子的 p 值场MultLinReg.cal_corr()
作用:计算所有因子与因变量之间的相关系数矩阵。
返回:np.ndarray,形状 (*space, N_factor+1, N_factor+1),最后两个维度为相关矩阵。
MultLinReg.cal_paritial_corr(idx)
作用:计算第 idx 个因子与因变量的偏相关系数(排除其他因子影响)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
idx | int | 必需 | 因子的索引(0-based) |
返回:np.ndarray,形状 (*space)
使用示例:
# 计算 ENSO 的偏相关(排除 PDO 和 AMO 的影响)reg_m.cal_corr() # 先计算相关系数矩阵partial_r = reg_m.cal_paritial_corr(idx=0)class M2mLinReg
多变量对多变量的相关分析类。
M2mLinReg(x, y)
作用:计算两组多变量时间序列之间的相关系数矩阵。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 形状 (time, N_factor) |
y | np.ndarray | 必需 | 形状 (time, M_factor) |
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
corr | np.ndarray | 相关系数矩阵,形状 (N_factor, M_factor) |
p_value | np.ndarray | p 值矩阵,形状 (N_factor, M_factor) |
使用示例:
m2m = M2mLinReg(factors, pcs) # factors: (time, 3), pcs: (time, 5)print(m2m.corr) # (3, 5) 相关系数矩阵print(m2m.p_value) # 显著性矩阵class SpaceCorr
空间相关类。
SpaceCorr(x, y)
作用:计算两个同形状空间场之间的逐点相关系数。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 形状 (time, *space) |
y | np.ndarray | 必需 | 形状 (time, *space) |
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
corr | np.ndarray | 逐点相关系数,形状 (*space) |
底层函数
这些函数是 LinReg 和 MultLinReg 的底层实现,可直接调用。
linear_reg(x, y, neff=None)
等同 LinReg(x, y, neff)。返回 (slope, intcpt, corr, p_value)。
multi_linreg(x, y)
等同 MultLinReg(x, y)。返回 (slope, intcpt, R, pv_all, pv_i)。
partial_corr(x, y, idx, mul_corr=None)
等同 MultLinReg.cal_paritial_corr(idx)。
multi_corr(x, y)
等同 MultLinReg.cal_corr()。
完整示例
import numpy as npimport xarray as xrimport matplotlib.pyplot as pltimport cartopy.crs as ccrsfrom sacpy import LinReg, MultLinRegimport sacpy.Map
# 一元回归 + 绘图da = xr.open_dataset('sst.nc')['sst']enso = np.random.randn(da.shape[0])
reg = LinReg(enso, da)reg.mask(0.05)
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=190))c = ax.scontourf(da['lon'], da['lat'], reg.slope1, cmap='RdBu_r')ax.sig_plot(da['lon'], da['lat'], reg.p_value, marker='..')ax.init_map(coastlines=True)plt.colorbar(c, label='Regression slope')plt.title('ENSO Regression on SST (p<0.05 dotted)')plt.show()显著性检验
导入
import numpy as npimport xarray as xrfrom sacpy import STMV# 或直接使用底层函数from sacpy.SigTest import one_mean_test, two_mean_testclass STMV
均值的显著性 T 检验类(Significance Test of Mean Value)。自动判断单样本或双样本检验。
STMV(data1, data2=None, wrap=True, *param, **kwargs)
作用:对数据执行 T 检验。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data1 | np.ndarray / xr.DataArray | 必需 | 第一组数据,形状 (time, *space) |
data2 | np.ndarray / xr.DataArray / None | None | 第二组数据。None 时进行单样本 T 检验(与 0 比较);否则进行双样本 T 检验 |
wrap | bool | True | 是否将结果包装为 xr.DataArray(需输入为 DataArray) |
*param | - | - | 传递给 scipy.stats.ttest_1samp 或 ttest_ind 的额外参数 |
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
mean | np.ndarray / xr.DataArray | 单样本时为 data1 均值,双样本时为 mean(data1) - mean(data2) |
p_value | np.ndarray / xr.DataArray | p 值,形状 (*space) |
使用示例:
# 单样本检验:检验异常场是否显著偏离 0stmv = STMV(sst_anom)print(stmv.mean) # 时间平均场print(stmv.p_value) # 显著性水平
# 双样本检验:两组数据均值差检验stmv2 = STMV(sst_early, sst_late)print(stmv2.mean) # 均值差(late - early?实际是 early - late)print(stmv2.p_value) # 显著性STMV.get_original_data()
作用:获取原始输入数据。
返回:单样本时返回 data1,双样本时返回 (data1, data2)
one_mean_test(data, expected_mean=None, *param)
作用:单样本 T 检验(底层函数)。检验 data 的均值是否等于 expected_mean。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data | np.ndarray / xr.DataArray | 必需 | 待检验数据,形状 (time, *space) |
expected_mean | np.ndarray / None | None | 期望均值。None 表示与 0 比较 |
*param | - | - | 传递给 scipy.stats.ttest_1samp |
返回:(origin_mean, pvalue),origin_mean 为数据均值。
使用示例:
mean, pval = one_mean_test(sst_anom)two_mean_test(data1, data2, *param)
作用:双样本独立 T 检验(底层函数)。检验两组数据均值是否相等。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data1 | np.ndarray / xr.DataArray | 必需 | 第一组数据,形状 (time1, *space) |
data2 | np.ndarray / xr.DataArray | 必需 | 第二组数据,形状 (time2, *space) |
*param | - | - | 传递给 scipy.stats.ttest_ind |
返回:(mean_diff, pvalue),mean_diff = mean(data1) - mean(data2)。
使用示例:
mean_diff, pval = two_mean_test(sst_1950_1980, sst_1980_2010)完整示例:年代际差异检验+绘图
import numpy as npimport xarray as xrimport matplotlib.pyplot as pltimport cartopy.crs as ccrsfrom sacpy import STMV, get_anomimport sacpy.Map
# 数据sst = xr.open_dataset('sst.nc')['sst']early = sst.sel(time=slice('1950', '1980'))late = sst.sel(time=slice('1985', '2015'))
# 双样本 T 检验stmv = STMV(late, early)
# 绘图ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=190))c = ax.scontourf(sst['lon'], sst['lat'], stmv.mean, cmap='RdBu_r')ax.sig_plot(sst['lon'], sst['lat'], stmv.p_value, marker='..')ax.init_map(coastlines=True)plt.colorbar(c, label='SST Difference (late - early)')plt.title('SST Change between 1950-1980 and 1985-2015')plt.show()谱分析
导入
import numpy as npfrom sacpy import Spectral, CrossSpectralclass Spectral
单变量功率谱分析类(基于 Welch 方法 / WOSA)。
Spectral(x, M_length, overlap=0.5, remove_trend=True, remove_annual=True, normalize_series=True, prewhiten=False)
作用:初始化谱分析对象并预处理时间序列。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 一维时间序列 |
M_length | int | 必需 | WOSA 分段长度,最好为 2 的幂 |
overlap | float | 0.5 | 分段重叠比例。若数据按季节分割,建议设为 0 |
remove_trend | bool | True | 是否去除线性趋势 |
remove_annual | bool | True | 是否去除年循环(harmonic fit) |
normalize_series | bool | True | 是否标准化序列(方差=1) |
prewhiten | bool | False | 是否预白化处理 |
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
dfn | float | 谱的保守自由度估计(分子) |
dfd | float | 零假设的分母自由度 |
ac_x | float | 预处理后序列的自相关系数 |
使用示例:
# 准备一维时间序列ts = monthly_sst.mean(dim=('lon', 'lat')).values # 长度为 N
# 初始化(保留趋势但去除年循环)spec = Spectral(ts, M_length=64, remove_annual=True, remove_trend=False)Spectral.get_spectra(normalize_spectrum=True, detrend='linear', **kwargs)
作用:计算功率谱。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
normalize_spectrum | bool | True | 是否将谱除以均值(便于比较) |
detrend | str | 'linear' | Welch 方法的去趋势设置 |
**kwargs | - | - | 传递给 scipy.signal.welch 的额外参数 |
返回:(f, Pxx) — 频率数组和功率谱。
使用示例:
f, Pxx = spec.get_spectra()Spectral.get_red_noise(method='fit_theory')
作用:拟合红噪声谱。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
method | str | 'fit_theory' | 拟合方法: - 'fit_theory':基于自相关系数理论计算- 'fit_data':对观测谱做曲线拟合 |
返回:np.ndarray,红噪声谱。
使用示例:
red_noise = spec.get_red_noise(method='fit_theory')Spectral.get_rs_sig(p_crit=0.99)
作用:获取基于红噪声理论的显著性水平曲线。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
p_crit | float | 0.99 | 显著性水平(F 检验) |
返回:np.ndarray,显著谱值阈值曲线。
使用示例:
sig_level = spec.get_rs_sig(p_crit=0.95)# 功率谱高于 sig_level 的频率段为显著class CrossSpectral(Spectral)
交叉谱分析类,继承自 Spectral。
CrossSpectral(x, y, M_length, overlap=0.5, ...)
作用:对两个时间序列进行交叉谱分析。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 第一组一维时间序列 |
y | np.ndarray | 必需 | 第二组一维时间序列 |
其余参数同 Spectral.__init__。
新增属性:ac_y(y 序列的自相关系数)。
CrossSpectral.get_spectra(normalize_spectrum=True, detrend='linear', **kwargs)
作用:计算两个序列各自的功率谱。
返回:(f, Pxx, Pyy)
CrossSpectral.get_red_noise(method='fit_theory')
作用:拟合两个序列的红噪声谱。
返回:(rsx, rsy)
CrossSpectral.get_rs_sig(p_crit=0.99)
作用:获取两个序列的显著谱阈值。
返回:(rsx_sig, rsy_sig)
CrossSpectral.get_cross_spectra(detrend='linear', **kwargs)
作用:计算交叉谱(协方差谱、相位谱、凝聚谱)。
返回:(covariance, phase, coherence)
| 返回值 | 说明 |
|---|---|
covariance | 协方差谱(cross-spectrum 实部) |
phase | 相位谱(角度制) |
coherence | 凝聚谱(0~1) |
使用示例:
cov, phase, coh = cross_spec.get_cross_spectra()CrossSpectral.get_coh_sig(p_crit=0.99)
作用:获取凝聚谱的显著性水平。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
p_crit | float | 0.99 | 显著性水平 |
返回:float,凝聚谱显著性阈值。
辅助函数
autocorr(x)
作用:计算时间序列的滞后-1 自相关系数。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 一维时间序列 |
返回:float
from sacpy.spectral import autocorrac = autocorr(ts)完整示例:单变量谱分析
import numpy as npimport matplotlib.pyplot as pltfrom sacpy import Spectral
# 准备数据ts = sst_anom.mean(dim=('lat', 'lon')).values # 区域平均 SSTA
# 谱分析spec = Spectral(ts, M_length=64, remove_annual=True)
# 计算谱f, Pxx = spec.get_spectra()red = spec.get_red_noise()sig = spec.get_rs_sig(p_crit=0.95)
# 绘图plt.figure(figsize=(10, 4))plt.semilogx(1/f, f*Pxx, 'b-', linewidth=1.5, label='Power Spectrum')plt.semilogx(1/f, f*red, 'r--', label='Red Noise')plt.semilogx(1/f, f*sig, 'r:', linewidth=0.5, label='95% Significance')plt.xlabel('Period')plt.ylabel('Frequency x Power')plt.legend()plt.title('Power Spectrum')plt.show()完整示例:交叉谱分析
import numpy as npimport matplotlib.pyplot as pltfrom sacpy import CrossSpectral
# 两个时间序列ts1 = enso_indexts2 = precip_index
cross = CrossSpectral(ts1, ts2, M_length=64)f, Pxx, Pyy = cross.get_spectra()cov, phase, coh = cross.get_cross_spectra()coh_sig = cross.get_coh_sig(p_crit=0.95)
fig, axes = plt.subplots(3, 1, figsize=(10, 8), sharex=True)
axes[0].semilogx(1/f, f*Pxx, label='x')axes[0].semilogx(1/f, f*Pyy, label='y')axes[0].set_ylabel('Power')axes[0].legend()
axes[1].semilogx(1/f, coh)axes[1].axhline(coh_sig, color='r', linestyle='--', label='95% Sig')axes[1].set_ylabel('Coherence')axes[1].set_ylim(0, 1)
axes[2].semilogx(1/f, phase)axes[2].set_ylabel('Phase (°)')axes[2].set_xlabel('Period')
plt.suptitle('Cross-Spectral Analysis')plt.show()地图绘图
导入
绘图扩展通过 import sacpy.Map 即可自动注册到 GeoAxesSubplot 上:
import matplotlib.pyplot as pltimport cartopy.crs as ccrsimport cartopy.feature as cfeatureimport numpy as npimport xarray as xrimport sacpy.Map # 注册所有绘图扩展方法同时也可直接使用工具函数:
from sacpy.Map import get_levelsfrom sacpy.settings import Map as MapSettings绘图风格配置
导入 sacpy.Map 时会自动设置:
- 字体:
Times New Roman - 默认 colormap:
RdBu_r
如需自定义,可在导入后修改 matplotlib 的 rcParams。
get_levels(data, percentile=98, num_level=13, zero_sym=True)
作用:根据数据分布自动生成等值线/填色层级。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data | np.ndarray | 必需 | 待绘制数据 |
percentile | int | 98 | 最高/最低值的百分位数(截断极端值) |
num_level | int | 13 | 层级数量 |
zero_sym | bool | True | 是否以零为中心对称 |
返回:np.ndarray,等间距的层级数组。
使用示例:
levels = get_levels(corr_map, percentile=95, num_level=11, zero_sym=True)GeoAxesSubplot 扩展方法
sacpy.Map 对 cartopy.mpl.geoaxes.GeoAxesSubplot 进行了 monkey-patch,新增以下方法:
scontourf(*args, **kwargs)
作用:智能填色图(contourf)。自动处理层级、colormap 和坐标转换。
| 参数 | 类型 | 说明 |
|---|---|---|
*args | 1~4 个参数 | 支持多种传入方式: - (Z):仅数据(需后续设置坐标)- (Z, levels)- (x, y, Z):经纬度+数据- (x, y, Z, levels) |
新增的 kwargs:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
percentile | int | 98 | 自动层级时的百分位 |
num_level | int | 13 | 自动层级时的层级数 |
zero_sym | bool | True | 层级是否零对称 |
extend | str | "both" | 色棒延伸方向 |
cmap | str | "RdBu_r" | colormap |
transform | crs | PlateCarree() | 数据坐标系统 |
返回:matplotlib.contour.QuadContourSet
使用示例:
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=190))c = ax.scontourf(lon, lat, sst_map)# 或自动层级c = ax.scontourf(lon, lat, sst_map, percentile=95, num_level=11)spcolormesh(*args, **kwargs)
作用:智能 pcolormesh。参数与 scontourf 类似,但使用 vmin/vmax 控制色彩范围。
返回:matplotlib.collections.QuadMesh
使用示例:
m = ax.spcolormesh(lon, lat, data, cmap='coolwarm')scontour(*args, **kwargs)
作用:智能等值线(contour)。自动添加 transform=ccrs.PlateCarree()。
返回:matplotlib.contour.QuadContourSet
squiver(*args, **kwargs)
作用:智能风场图(quiver)。支持抽样步长。
新增 kwargs:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
stepx | int | 1 | x 方向抽样步长 |
stepy | int | 1 | y 方向抽样步长 |
使用示例:
# 每5个格点画一个箭头ax.squiver(lon, lat, u, v, stepx=5, stepy=5)init_map(same_size=True, coastlines=True, draw_ticks=True, **kwargs)
作用:快速初始化地图(画海岸线 + 设置刻度 + 固定宽高比)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
same_size | bool | True | 是否设置 set_aspect("auto") |
coastlines | bool | True | 是否绘制海岸线 |
draw_ticks | bool | True | 是否自动绘制刻度 |
额外传递给 draw_ticks 的 kwargs:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
stepx | int / None | 自动 | 大刻度 X 步长 |
stepy | int / None | 自动 | 大刻度 Y 步长 |
smallx | int / None | 自动 | 小刻度 X 步长 |
smally | int / None | 自动 | 小刻度 Y 步长 |
使用示例:
ax = plt.axes(projection=ccrs.PlateCarree())ax.scontourf(lon, lat, data)ax.init_map() # 自动海岸线+刻度draw_ticks(extend, stepx=None, stepy=None, ...)
作用:为地图添加经纬度刻度。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
extend | list | 必需 | [xmin, xmax, ymin, ymax] |
stepx / stepy | int / None | 自动 | 大刻度步长 |
smallx / smally | int / None | 自动 | 小刻度步长 |
使用示例:
ax.draw_ticks([-180, 180, -90, 90], stepx=30, stepy=15)sig_plot(x, y, pvalue, thrshd=0.05, marker="..", color=None)
作用:显著性打点(在显著区域叠加点/影线)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 经度 |
y | np.ndarray | 必需 | 纬度 |
pvalue | np.ndarray | 必需 | p 值场,形状同数据 |
thrshd | float | 0.05 | 显著性阈值 |
marker | str | ".." | 影线样式(hatch pattern) |
color | str / None | None | 打点颜色 |
使用示例:
ax.scontourf(lon, lat, data)ax.sig_plot(lon, lat, p_value, marker='..', color='k')
sig_plot同样注册到了matplotlib.axes.Axes(非地图 Axes 可用,不带transform)。
xr.DataArray.splot(ax=None, label=0, projection=None, kw1={}, kw2={})
作用:DataArray 的快速绘图方法(需 2D 数据)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ax | Axes / None | None | 坐标轴。None 自动创建 |
label | int | 0 | 经纬度命名:0 = lon/lat,1 = longitude/latitude |
projection | crs / None | None | 地图投影。None 自动使用 PlateCarree |
kw1 | dict | {} | 传递给 scontourf 的参数 |
kw2 | dict | {} | 传递给 init_map 的参数 |
返回:(m, ax) — 填色图对象和坐标轴。
使用示例:
da = sst.isel(time=0) # 2D: (lat, lon)m, ax = da.splot(kw1={'cmap': 'coolwarm', 'extend': 'both'})plt.title('SST')plt.show()class Map(配置)
sacpy.settings.Map 提供了常用 cartopy 投影的字典:
from sacpy.settings import Map
proj = Map.projection_dict['Robinson'](central_longitude=180)proj = Map.projection_dict['Orthographic'](central_longitude=-20, central_latitude=60)支持的投影名称:Robinson, PlateCarree, Mollweide, Orthographic, Mercator, Miller, LambertConformal, NorthPolarStereo, SouthPolarStereo 等 30+ 种。
完整示例
import numpy as npimport xarray as xrimport matplotlib.pyplot as pltimport cartopy.crs as ccrsimport cartopy.feature as cfeatureimport sacpy.Mapfrom sacpy.Map import get_levels
# 准备数据da = xr.open_dataset('sst.nc')['sst'].isel(time=0) # 2D 场lon, lat = da['lon'].values, da['lat'].values
# 创建地图proj = ccrs.PlateCarree(central_longitude=180)fig, axes = plt.subplots(2, 2, figsize=(14, 8), subplot_kw={'projection': proj})axes = axes.flatten()
# 子图1:智能填色 + 陆地 + 显著性打点ax = axes[0]c = ax.scontourf(lon, lat, da.values, cmap='RdBu_r', percentile=98, num_level=13)ax.add_feature(cfeature.LAND, facecolor='lightgray')ax.init_map(coastlines=False)plt.colorbar(c, ax=ax, label='SST')
# 子图2:pcolormeshax = axes[1]m = ax.spcolormesh(lon, lat, da.values, cmap='coolwarm')ax.init_map()plt.colorbar(m, ax=ax)
# 子图3:使用 DataArray.splotax = axes[2]m, _ = da.splot(ax=ax, kw1={'cmap': 'RdBu_r'})ax.set_title('splot method')
# 子图4:不同投影ax = axes[3]proj2 = ccrs.Orthographic(central_longitude=180, central_latitude=0)ax.remove()ax = fig.add_subplot(2, 2, 4, projection=proj2)c = ax.scontourf(lon, lat, da.values, cmap='RdBu_r')ax.coastlines()ax.set_global()plt.colorbar(c, ax=ax, shrink=0.6)
plt.tight_layout()plt.show()数据处理工具
导入
from sacpy import get_anom, spec_moth_dat, spec_moth_yrmeanfrom sacpy import convert_lon, reverse_lon, field_corr, autocorr, sig_scatterfrom sacpy.Util import gradient_da, shp_mask, gradient_array, ddof, rewapperfrom sacpy.linger_cal import linear_reg, multi_linreg, multi_corr, partial_corrget_anom(DaArray, method=0, freq="month", time_coords="time")
作用:计算气候数据的距平(anomaly)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DaArray | xr.DataArray | 必需 | 输入数据,形状 (time, *space) |
method | int | 0 | 距平计算方法: - 0:减去对应月份/日期的多年平均值- 1:去除对应月份/日期的线性趋势 |
freq | str | "month" | 时间频率:"month" 或 "day" |
time_coords | str | "time" | 时间坐标名称 |
返回:xr.DataArray,距平场。
使用示例:
sst_anom = get_anom(sst, method=0, freq="month")spec_moth_dat(DaArray, months)
作用:提取特定月份的数据。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DaArray | xr.DataArray | 必需 | 输入数据 |
months | list / str | 必需 | 月份列表 [12, 1, 2] 或季节名称 "DJF", "MAM", "JJA", "SON" |
返回:xr.DataArray,仅含指定月份的数据。
使用示例:
djf_sst = spec_moth_dat(sst, "DJF") # 冬季数据jja_sst = spec_moth_dat(sst, [6, 7, 8]) # 夏季数据spec_moth_yrmean(DaArray, months)
作用:提取特定月份数据并按年求平均。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DaArray | xr.DataArray | 必需 | 输入数据 |
months | list / str | 必需 | 同 spec_moth_dat |
返回:xr.DataArray,每年一个值(季节均值)。
使用示例:
djf_mean = spec_moth_yrmean(sst, "DJF") # 每年一个冬季平均# 时间坐标变为年份convert_lon(lon)
作用:将经度从 [0, 360] 转换为 [-180, 180]。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
lon | np.ndarray | 必需 | 经度数组 |
返回:np.ndarray
reverse_lon(lon)
作用:将经度从 [-180, 180] 转换为 [0, 360]。
field_corr(field1, field2)
作用:计算两个时空场的逐空间点相关系数。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
field1 | np.ndarray | 必需 | 形状 (time, *space) |
field2 | np.ndarray | 必需 | 形状 (time, *space),时间维度须与 field1 相同 |
返回:np.ndarray,逐点相关系数,形状 (*space)。
使用示例:
corr_map = field_corr(sst, precip)autocorr(x, lags)
作用:计算多维数据的滞后自相关(2D 输入,第一维为时间)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x | np.ndarray | 必需 | 形状 (time, *space) |
lags | int | 必需 | 滞后期数 |
返回:np.ndarray,形状 (*space)。
注意:此为
Util.autocorr(带 lags 参数的多维版本),与spectral.autocorr(一维滞后-1)不同。
sig_scatter(ax, x, y, p, threshold=0.05, **kwargs)
作用:绘制显著散点图,不显著的点被遮蔽。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ax | Axes | 必需 | matplotlib 坐标轴 |
x | np.ndarray | 必需 | 1D 数组 |
y | np.ndarray | 必需 | 1D 数组 |
p | np.ndarray | 必需 | p 值数组 |
threshold | float | 0.05 | 显著性阈值 |
返回:PathCollection(散点图对象)。
使用示例:
sig_scatter(ax, enso, precip, p_values, threshold=0.05, color='red', marker='o')gradient_da(da, dim, method=0, delta=None)
作用:计算 DataArray 沿某维度的梯度(差分)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
da | xr.DataArray | 必需 | 输入数据 |
dim | str | 必需 | 求梯度的维度(如 "lat", "lon") |
method | int | 0 | 0:中心差分(默认)。1:前向差分 |
delta | float / None | None | 网格间距(m)。None 时自动根据 dim 估算 |
返回:xr.DataArray。
使用示例:
dT_dy = gradient_da(sst, "lat") # 经向梯度shp_mask(shp, Dataarray, lat='lat', lon='lon')
作用:用 shapefile 掩码 DataArray(保留多边形内部区域)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
shp | GeoDataFrame | 必需 | geopandas 读入的 shapefile |
Dataarray | xr.DataArray | 必需 | 待掩码数据 |
lat | str | "lat" | 纬度坐标名 |
lon | str | "lon" | 经度坐标名 |
返回:xr.DataArray,区域外的格点设为 NaN。
需要:geopandas、rioxarray、shapely
使用示例:
import geopandas as gpdshp = gpd.read_file('china.shp')sst_china = shp_mask(shp, sst)rewapper(data, origin_dataarray, drop_dims=None)
作用:将计算结果重新包装为 xr.DataArray,保留原始坐标信息。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data | np.ndarray | 必需 | 待包装数据 |
origin_dataarray | xr.DataArray | 必需 | 原始 DataArray(用于提取坐标和维度) |
drop_dims | str / list / None | None | 需删除的维度(如原始数据的 time 维已被压缩) |
注意:此函数处于早期开发阶段,可能不够稳定。
完整示例:数据处理流水线
import xarray as xrimport numpy as npfrom sacpy import get_anom, spec_moth_dat, spec_moth_yrmean, convert_lon
# 加载数据ds = xr.open_dataset('era5_monthly.nc')
# 经度转换(0-360 → -180~180)ds = ds.assign_coords(lon=convert_lon(ds['lon'].values)).sortby('lon')
# 计算距平t_anom = get_anom(ds['t2m'], method=0, freq='month')
# 提取冬季并计算年平均值djf_t = spec_moth_yrmean(t_anom, "DJF") # 每年冬季平均
# 提取夏季jja_t = get_anom(spec_moth_dat(ds['t2m'], "JJA"))
print(djf_t)文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!



