0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

xarrayでgradsの機能を代替

0
Last updated at Posted at 2026-03-13

xarrayの詳しい説明はここ。

gradsでやっていたことをxarrayでできるようにする。gradsよりも軸の取り扱いが面倒なので、データを読み込んだ時点で必要に応じて軸データの変換を行う。

IO

gradsデータの読み込み

xgradsを使えば直接gradsデータをxarrayとして読み込める。ただし、

  • 複雑な template
  • yrev
  • zrev
  • sequential binary
    は苦手なので、その場合は1度netcdfデータに変換する。
from xgrads import open_CtlDataset

ds = open_CtlDataset("data.ctl")

netcdfの読み込み

ds=xr.open_dataset('input.nc')

DataArray, DataSetから変数を取り出す

以下の時間操作や空間操作では変数名の指定が抜けているが、基本的に変数を指定してデータを処理する。変数名を指定しない場合、データセット全てに対して同じ処理がかかる。

# safe method
u=ds['u']
# simple but not safe
u=ds.u
# multiple values
ds2=ds['u','v']

軸データの修正

# read data without decoding time
ds1=xr.open_dataset('temp_ens.nc',decode_times=False)
# rename time unit
ds1=ds1.rename({'time_counter':'time'})
# reset taxis by pandas
ds1["time"] = pd.date_range(start="2001-01-01",periods=276,freq="MS")

時間操作

時間平均

# monthly mean
da.groupby("time.month").mean("time")
# seasonal mean
da.groupby("time.season").mean("time")
# annual mean
annual = ds.t.groupby("time.year").mean()

時間平均(特定範囲)

# during specific periods (date)
tmean = ds.t.sel(time=slice("2001-01-01","2010-12-31")).mean("time")
# during specific periods (year only)
tmean = ds.t.sel(time=slice("2001","2010")).mean("time")
# during seasons
jja = ds.t.sel(time=ds.time.dt.month.isin([6,7,8])).mean("time")

アノマリー計算

# monthly climatology
clim = da.groupby("time.month").mean("time")
# monthly aomaly
anom = da.groupby("time.month") - clim

移動平均

# 3-month running mean, time centering, minimum 1 month data
da.rolling(time=3,center=True,min_periods=1).mean()

時間解像度変更

ds.resample(time='1D').sum() #daily sum
ds.resample(time='AS').mean() #annual mean

時間シフト相関

# da2 is 1 month before
corr = xr.corr(da1, da2.shift(time=1), dim="time")

空間操作

領域平均

import numpy as np

# latitudinal weight
weights = np.cos(np.deg2rad(ds.lat))

# average after weighting
mean_val = (
    ds.var.sel(lat=slice(10,20), lon=slice(120,150))
    .weighted(weights)
    .mean(("lat","lon"))
)

緯度経度サブセット

gradsだと

set lon 120 150
set lat -10 10

xarrayだと

da = ds.t.sel(
    lon=slice(120,150),
    lat=slice(-10,10)
)

zonal mean

#zonal mean
zonal = da.mean("lon")
#or
zonal = da.mean(("lon","time"))
#plot in latitude-level section
zonal.plot(
    x="lat",
    y="level",
    yincrease=False
)

zonal & meridional mean

u_eq = (
    ds.u
    .mean("lon")
    .sel(lat=slice(-5,5))
    .mean("lat")
)

厳密には緯度方向に重み付けをする。

import numpy as np

weights = np.cos(np.deg2rad(ds.lat))

u_eq = (
    ds.u.mean("lon")
    .weighted(weights)
    .mean("lat")
)

補間処理

以下は単純な緯度経度補間で球面上補間ではないので、xesmfを使ったほうがいい

ds.interp(lat=new_lat, lon=new_lon, method='linear')

log(p)で鉛直補間

da_log = da.assign_coords(lev=np.log(da.lev))

new_lev = np.log([925, 775, 600, 400])

da_interp = da_log.interp(lev=new_lev)
da_interp = da_interp.assign_coords(lev=np.exp(da_interp.lev))

リグリッド

xesmfを合わせて利用する。

import xarray as xr
import xesmf as xe
import numpy as np

ds_out = xr.Dataset(
    {
        "lat": (["lat"], np.arange(-89, 90, 2)),
        "lon": (["lon"], np.arange(0, 360, 2)),
    }
)

regridder = xe.Regridder(ds_in, ds_out, "bilinear")
ds_out = regridder(ds_in)

アンサンブル処理

アンサンブルデータ例

import xarray as xr
import numpy as np

da = xr.DataArray(
    np.random.rand(10,12,36,72),
    dims=("member","time","lat","lon")
)

ens_mean = da.mean("member")

ファイルが複数ある場合

以下で複数ファイルをアンサンブルメンバーのデータとして取り扱う

ds = xr.open_mfdataset(
    "run*.nc",
    concat_dim="member",
    combine="nested"
)

ens_mean = ds.var.mean("member")

統計値

# ensemble mean
ens_mean = ds.var.mean("member")
# variance
ens_var = ds.var.var("member")
# standard deviation
spread = ds.var.std("member")

条件抽出

ラベルによる抽出

ds.sel(time='2024-01-01', lat=35.0, lon=135.0)

マスク処理

# mask out nino34<1
da.sel(time=da["nino34"] > 1)

# mask out temp<308.15
ds.where(ds.temp > 308.15)

# mask out land=0
t_mask = ds.t.where(land==1)

描写

基本

da.plot()
ds.temp.isel(time=0).plot()

最も簡単なクイックルックコード

import xarray as xr
import matplotlib.pyplot as plt

# read data
ds = xr.open_dataset('sample_data.nc')
# display temp
ds.temp.isel(time=0).plot()
# display window
plt.show()

関数関係

回帰係数の算出(tregr)

# x: index, y: OLR
beta = xr.cov(x, y, dim="time") / xr.var(x, dim="time")

相関係数(tcorr)

xr.corr(x,y,dim="time")

鉛直積算(vint)

# precipitable water
g = 9.81
dp = q.level.diff("level")
q_mid = q.isel(level=slice(0,-1))
pw = (q_mid * dp).sum("level") / g

鉛直積算をかける前に、鉛直座標を必要に応じて反転させるには以下を使う。圧力に関して昇順にデータが並び替わる。

ds2=ds.sortby('plev',ascending=True)

回転, 発散(hcurl,hdivg)

残念ながらxarrayでなくてmetpyを使うのが簡単で確実。次元が合ってないと計算できないので注意。

import metpy.calc as mpcalc

# hcurl
curl = mpcalc.vorticity(u, v)
# hdivg
div = mpcalc.divergence(u, v)

metpyはunitがないとエラーになるので、xarrayでは以下でmetpyが読めるunitを与える

ds["u"].attrs["units"] = "m/s"
u = ds.u.metpy.quantify()

データセット

DataArrayは変数が一つのデータ、DataSetは変数が複数のデータ。

to_netcdfで簡単にnetcdfに出力できる。軸の情報が間違っていたり、違っているとxarrayで再度読み込んだときに計算に使えないので注意が必要。

da.to_netcdf('output.nc')

DataArray

da = xr.DataArray(
    np.random.rand(10,5,8),
    dims=("time","lat","lon"),
    coords={
        "time": np.arange(10),
        "lat": np.linspace(-90,90,5),
        "lon": np.linspace(0,360,8)
    },
    name="u_wind"
)

DataSet

ds = xr.Dataset(
    {
        "temp": (("lat","lon"), np.random.rand(3,4)),
        "precip": (("lat","lon"), np.random.rand(3,4))
    },
    coords={
        "lat": [10,20,30],
        "lon": [100,110,120,130]
    }
)

print(ds)

大規模データ並列処理

daskで複数ファイルにまたがる大きなファイルを取り扱える。

ds = xr.open_mfdataset("*.nc", chunks={"time":12})
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?