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 と julia (NCDatasets) の対応

Posted at

はじめに

 juliaのnetcdfデータを扱うパッケージにNCDatasetsがある。doiも発行されている(https://doi.org/10.21105/joss.06504)。
 pythonのnetCDF4に相当すると思われるが、比較する記事を見つけられなかった。自分も含め、netCDF4よりもxarrayを使う人もいると思うので、ここではごく基本的なxarrayの関数とNCDatasetsの関数をなんとなく対応させることを目指してまとめた。(用語や文法の説明は適当です。気が向けば追記します。)

NCDatasetsのインストール

juliaは導入済みを想定
まずターミナルでjuliaのREPLを起動

$ julia

のち

julia(REPL)
julia> using Pkg
julia> Pkg.add("NCDatasets")

"NCDatasets"を置き換えれば任意のパッケージをインストール可能

xarrayとjuliaの対応

インポート

python3
import xarray as xr
julia
using NCDatasets

netcdfデータの読み込み

python3
ds = xr.open_dataset('file.nc')
julia
ds = Dataset("file.nc")

変数名と次元の確認

  • 配列順はpythonはCスタイル、juliaはFスタイル
  • ここでは4次元気象データを想定
  • pythonで時間、気圧、緯度、経度の順に作成したnetcdfだが、NCDatasetsで読み込むと経度、緯度、気圧、時間の順となっていた(再現性は不明)
python3
print([key for key, val in ds.items()]
print(ds['temperature'].dims)

['temperature']
('time', 'level', 'latitude', 'longitude')

julia
println(keys(ds))

["longitude", "latitude", "level", "time", "temperature"]

変数の取得

python3
temp = ds['temperature']  # どちらでも可
temp = ds.temperature  # どちらでも可
julia
temp = ds["temperature"][:]
temp = ds["temperature"]  # lazy loadになるらしい

変数の配列サイズの取得

  • ちなみに上述の通り配列順は逆になっている
python3
print(ds.shape)

(504, 27, 321, 1440)

julia
println(size(ds))

(1440, 321, 27, 504)

軸情報の取得

  • ここで定義した変数は下で使います
python3
lons = ds.longitude  # xr.DataArrayを返す
#lons = ds.longitude.values  # np.ndarrayを返す
lats = ds.latitude
levs = ds.level
times = ds.time  # np.datetime64を保持するxr.DataArray
julia
lons = ds["longitude"][:]  # Vectorを返す
lats = ds["latitude"][:]
levs = ds["level"][:]
times = ds["time"][:]  # DateTimeを保持するVector

緯度・経度・気圧の指定(幅なし)

  • 経度130º、緯度45º、500hPaを指定
  • これはxarrayに軍配
  • DimensionalData.jlなどのxarray-likeなパッケージはあるが、netcdfの読み込みはできない?(2024/05/29)
  • (ここでfindallを使うと選択後のArrayの次元はreduceされない)
python3
temp = temp.sel(level=500, latitude=45, longitude=130)
julia
lon_idx = findfirst(lons .== 130)  # 上で定義したlons
lat_idx = findfirst(lats .== 45)  # 上で定義したlats
lev_idx = findfirst(levs .== 500)  # 上で定義したlevs
temp = temp[lon_idx, lat_idx, lev_idx, :]

時刻の指定(幅なし)

python3
import pandas as pd  # 多分、datetimeでもnp.datetime64でもOK
target = pd.Timestamp('2018-02-02 00')
temp = temp.sel(time=target)
julia
using Dates
target = DateTime(2018, 2, 2, 0)
time_idx = findfirst(times .== targed)  # 上で定義したtimes
temp = temp[:, :, :, time_idx]

緯度・経度・気圧の指定(幅あり)

  • データにより緯度軸は北始まり・南始まりの違いがあるが、xarrayはこの順番に敏感
  • juliaの大小比較はデータ順を考える必要ない模様、良い点
python3
temp = temp.sel(level=slice(300, 700),
                latitude=slice(50, 35),  # データは北→南で格納
                longitude=slice(135, 140))
julia
lon_idxs = findall(135. .<= lons .<= 140.)
lat_idxs = findall(35. .<= lats .<= 50.)
lev_idxs = findall(300 .<= levs .<= 700)
temp = temp[lon_idxs, lat_idxs, lev_idxs, :]

時間の指定(幅あり)

python3
temp = temp.sel(time=slice('2018-02-01 00', '2018-02-06 23'))
julia
start_time = DateTime(2018, 2, 1, 0)
end_time = DateTime(2018, 2, 6, 23)
time_idxs = findall(start_time .<= times .<= end_time)
temp = temp[:, :, :, time_idxs]

不要次元の削除

python3
temp = temp.squeeze()  # 一度に複数の該当次元をreduce(削除)
julia
tmep = dropdims(temp, dims=1)  # 一度に一つの次元のみ

平均

  • Statisticsを使う
  • 処理後に次元はreduceされないのでdropdimsを使う
python3
temp_mean = temp.mean('time')  # shape -> (27, 321, 1440)
julia
using Statistics
temp_mean = mean(temp, dims=4)  # size -> (1440, 321, 27, 1)
temp_mean = dropdims(temp, dims=4)  # size -> (1440, 321, 27)

その他(他力本願)

感想

  • 普段使っている関数は概ね変換できたと思う
  • pythonのnetCDF4やFortranに似てる部分あり、乗り換えコストそれなりに低そう
  • xarrayは計算も作図もできるが、NCDatasetsはI/Oに特化している
  • 君はDataArray?ndarray?や、君はTimestamp?datetime64?などの混乱を取り除けそうな予感

参考Web文献

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?