Multidimensional data processing#

Setelah membaca chapter ini, pembaca diharapkan dapat

  • Memahami struktur data multidimensi (NetCDF) dan cara membacanya menggunakan Xarray.

  • Mengolah data multidimensi dengan operasi manipulasi dan komputasi dasar.

Intro#

Pada mata pelatihan sebelumnya, kita telah mencoba mengolah data tabular menggunakan pandas. Namun, data meteorologi-oseanografi, khususnya yang berasal dari keluaran model, tidak mudah disimpan dalam bentuk tabular.

Data keluaran model terdiri dari banyak dimensi (waktu, latitude, longitude, kedalaman/ketinggian). Misalnya, parameter temperatur pada suatu tempat di muka bumi direpresentasikan dengan tiga dimensi.

\[ T(x,y,t) \]

dimana \(x, y,\) dan \(t\) masing-masing menandakan longitude, latitude, dan waktu.

Pada bagian ini, kita akan mempelajari bagaimana xarray dapat dengan mudah untuk mengolah struktur data seperti ini.

Struktur data multi dimensi#

Setidaknya terdapat empat terminologi penting dalam data multi dimensi (yang disimpan sepeti dalam format netcdf), yaitu variabel, koordinat, dimensi atau indeks, serta atribut.

  • variabel: array multi dimensi berisi variabel fisis seperti suhu udara, presipitasi, tinggi gelombang, dll. Direpresentasikan oleh koordinat (latitude, longitude, dan waktu).

  • koordinat: wadah seperti dictionary yang menyimpan label dan array dua dimensi berisi dimensi.

  • dimensi: dimensi dari masing-masing koordinat (longitude, latitude, time).

  • atribut: dictionary untuk menyimpan metadata.

xarray
***

Lebih spesifik, struktur data utama dalam Xarray terbagi menjadi dua, yaitu DataArray dan Dataset.

DataArray#

Ini merupakan implementasi dari xarray untuk menyimpan array multi dimensi. Beberapa properti penting antara lain:

  • values: array multi dimensi yang menyimpan nilai dari satu variabel tertentu

  • dims: dimensi dari masing-masing sumbu

  • coords: wadah seperti dictionary yang menyimpan label dan dimensi

  • attrs: dictionary penyimpan metadata

Dataset#

Xarray Dataset berisi kumpulan dari DataArray yang disimpan dalam wadah berbentuk dictionary. Properti penting antara lain:

  • data_vars: wadah seperti dictionary untuk menyimpan DataArray

  • dims: dimensi dari masing-masing sumbu

  • coords: wadah seperti dictionary yang menyimpan label dan dimensi

  • attrs: dictionary penyimpan metadata

Membaca dataset#

Built-in method xarray untuk membuka dataset adalah xarray.open_dataset. Method ini dapat digunakan untuk membuka beberapa macam format data multidimensi seperti netcdf, hdf5, zarr, grib, pydap, dengan menspesifikkan argument engine.

Xarray juga mendukung untuk membaca kumpulan file dalam satu kali proses dengan method xarray.open_mfdataset. Method ini akan mereturn xarray dataset yang telah mengalami pembagian (chunking) secara otomatis.

Dalam praktik ini, kita akan mencoba untuk membuka dataset hindcast dari BMKG-OFS yang tersimpan dalam database opendap.

Load module#

# load module

import xarray as xr
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

Load data#

Single file#

dset = xr.open_dataset("http://web.pusmar.id:8082/opendap/inawaves_hindcast/2025/H_hires_202501.nc")
dset
<xarray.Dataset> Size: 14GB
Dimensions:  (time: 249, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 2kB 2025-01-01 ... 2025-02-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables: (12/17)
    hs       (time, lat, lon) float64 844MB ...
    hmax     (time, lat, lon) float64 844MB ...
    dir      (time, lat, lon) float64 844MB ...
    dp       (time, lat, lon) float64 844MB ...
    lm       (time, lat, lon) float64 844MB ...
    t01      (time, lat, lon) float64 844MB ...
    ...       ...
    ptp00    (time, lat, lon) float64 844MB ...
    ptp01    (time, lat, lon) float64 844MB ...
    ptp02    (time, lat, lon) float64 844MB ...
    pdi00    (time, lat, lon) float64 844MB ...
    pdi01    (time, lat, lon) float64 844MB ...
    pdi02    (time, lat, lon) float64 844MB ...
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8

Multi file#

lifile = [
    "http://web.pusmar.id:8082/opendap/inawaves_hindcast/2025/H_hires_202501.nc",
    "http://web.pusmar.id:8082/opendap/inawaves_hindcast/2025/H_hires_202502.nc"
]
dsetmf = xr.open_mfdataset(lifile)
dsetmf
<xarray.Dataset> Size: 27GB
Dimensions:  (time: 474, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 4kB 2025-01-01 ... 2025-03-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables: (12/17)
    hs       (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    hmax     (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    dir      (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    dp       (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    lm       (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    t01      (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    ...       ...
    ptp00    (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    ptp01    (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    ptp02    (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    pdi00    (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    pdi01    (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
    pdi02    (time, lat, lon) float64 2GB dask.array<chunksize=(249, 481, 881), meta=np.ndarray>
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
# QUICK VIEW TO THE DATA
dset['hs'][0].plot()
<matplotlib.collections.QuadMesh at 0x7fbaf82c42f0>
../_images/9aefaf0ec06f81e024f2b7ecdf209f68df7c02b852fe6c0750a4135eb19e7aac.png

Manipulasi dataset#

Operasi manipulasi dasar#

Operasi umum yang digunakan untuk mengolah dataset xarray antara lain indexing, slicing, interpolating, dan masking.

Operasi dasar

Method

Indexing

regular numpy indexing atau .sel atau .isel

Slicing

regular numpy slicing atau .sel atau .isel

Interpolating

.sel atau .interp

Masking

.where

Method .sel dan .isel memiliki kemampuan yang sama untuk melakukan seleksi data baik untuk DataArray maupun Dataset (regular numpy indexing hanya berlaku untuk DataArray), namun keduanya terdapat perbedaan mendasar.

.sel

.isel

Seleksi data

berdasarkan nilai dari label dimensi

berdasarkan index atau urutan dari nilai dimensi


Apakah sadar jika terdapat langkah yang terlewat, yang ada di pemrosesan data tabular tapi tidak ada di sini? Ya, kita tidak mempertimbangkan proses pembersihan data karena output model biasanya sudah melalui proses quality control, berbeda dengan raw data tabular dari observasi. Sehingga, fokus kita dititikberatkan pada pemrosesan data lebih lanjut.

Indexing#

Sebagai percobaan, kita akan melakukan seleksi data untuk

  • variabel hs

  • waktu ke 1 atau 2025-01-01T00:00:00.000000000

  • lat lon masing masing -15 dan 90 (urutan ke 1)

# REGULAR NUMPY INDEXING => hanya berlaku untuk DataArray

# ingat kembali bahwa indexing di python dimulai dengan 0, bukan 1
hst0 = dset['hs'][0] # select variable hs untuk urutan waktu ke 1
hssel = dset['hs'][0][0,0] # select variable hs untuk urutan waktu ke 1, dan lat lon masing-masing juga ke 1

# cek datanya
display(hst0)
print(hssel.data)
<xarray.DataArray 'hs' (lat: 481, lon: 881)> Size: 3MB
[423761 values with dtype=float64]
Coordinates:
    time     datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Attributes:
    long_name:      Significant wave height
    standard_name:  sea_surface_wave_significant_height
    units:          m
1.9658203125
# .isel => berlaku untuk DataArray dan Dataset

hst0 = dset['hs'].isel(time=0) # select variable hs untuk urutan waktu ke 1
hst0l0 = hst0.isel(lon=0, lat=0) # select variable hs untuk urutan waktu ke 1, dan lat lon masing-masing juga ke 1

# cek datanya
display(hst0)
print(hst0l0.data)
<xarray.DataArray 'hs' (lat: 481, lon: 881)> Size: 3MB
[423761 values with dtype=float64]
Coordinates:
    time     datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Attributes:
    long_name:      Significant wave height
    standard_name:  sea_surface_wave_significant_height
    units:          m
1.9658203125
# .sel => berlaku untuk DataArray dan Dataset

hst0 = dset['hs'].sel(time="2025-01-01T00:00:00.000000000") # select variable hs untuk urutan waktu ke 1
hst0l0 = hst0.sel(lon=90, lat=-15) # select variable hs untuk urutan waktu ke 1, dan lat lon masing-masing juga ke 1

# cek datanyaS
display(hst0)
print(hst0l0.data)
<xarray.DataArray 'hs' (lat: 481, lon: 881)> Size: 3MB
[423761 values with dtype=float64]
Coordinates:
    time     datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Attributes:
    long_name:      Significant wave height
    standard_name:  sea_surface_wave_significant_height
    units:          m
1.9658203125

Slicing#

Pada dasarnya, slicing diselesaikan menggunakan python built-in function slice untuk mendapatkan batas nilai yang diinginkan.

Sebagai percobaan, kita akan melakukan seleksi data untuk

  • variabel hs

  • waktu ke 1 hingga 8 atau 2025-01-01T00:00:00 hingga 2025-01-01T21:00:00

  • lat lon masing masing -15 - 0 dan 90 - 120

Dalam hal ini, kita tidak akan mengandalkan regular numpy indexing dan .isel karena diperlukan proses lanjutan untuk menentukan ada di urutan berapa batas latitude dan longitude yang kita hendaki. Sehingga, kita hanya akan mengandalkan method .sel untuk mempermudah pemrosesan.

hst08 = dset.sel(time=slice('2025-01-01T00:00:00', '2025-01-01T21:00:00'))
hssel = hst08.sel(lat=slice(-15,0), lon=slice(90,120))

# cek datanya
display(hssel)

# quick plot
hssel['hs'][0].plot()
<xarray.Dataset> Size: 126MB
Dimensions:  (time: 8, lat: 241, lon: 481)
Coordinates:
  * time     (time) datetime64[ns] 64B 2025-01-01 ... 2025-01-01T21:00:00
  * lat      (lat) float32 964B -15.0 -14.94 -14.88 ... -0.125 -0.0625 0.0
  * lon      (lon) float32 2kB 90.0 90.06 90.12 90.19 ... 119.9 119.9 120.0
Data variables: (12/17)
    hs       (time, lat, lon) float64 7MB ...
    hmax     (time, lat, lon) float64 7MB ...
    dir      (time, lat, lon) float64 7MB ...
    dp       (time, lat, lon) float64 7MB ...
    lm       (time, lat, lon) float64 7MB ...
    t01      (time, lat, lon) float64 7MB ...
    ...       ...
    ptp00    (time, lat, lon) float64 7MB ...
    ptp01    (time, lat, lon) float64 7MB ...
    ptp02    (time, lat, lon) float64 7MB ...
    pdi00    (time, lat, lon) float64 7MB ...
    pdi01    (time, lat, lon) float64 7MB ...
    pdi02    (time, lat, lon) float64 7MB ...
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
<matplotlib.collections.QuadMesh at 0x7fbaf2f307d0>
../_images/b4feb48b6275964191a0eeb9e2c7fd6dd35387e4e4918f50d0c4f749b93cb05c.png

Interpolating#

Interpolasi berguna apabila kita perlu menarik data titik yang lokasinya tidak berada persis di titik grid. Selain itu, method .interp juga berguna untuk proses regriding.

Interpolasi linear diselesaikan menggunakan metode interpolasi bilinear.

%%time
# .sel nearest
dssel = dset['hs'].isel(time=0).sel(lat=-7.21, lon=121.21, method='nearest')
print(dssel.data)
0.791015625
CPU times: user 6.32 ms, sys: 82 μs, total: 6.4 ms
Wall time: 141 ms
%%time
# .interp
dssel = dset['hs'].isel(time=0).interp(lat=-7.21, lon=121.21, method='linear')
print(dssel.data)
0.7919578124999956
CPU times: user 145 ms, sys: 20 ms, total: 165 ms
Wall time: 2.06 s
# .interp for regridding
dssel = dset['hs'].isel(time=0).sel(lat=slice(-7.5,-6.25), lon=slice(110,118))

new_lon = np.linspace(dssel.lon[0].data, dssel.lon[-1].data, dssel.sizes['lon']*3)
new_lat = np.linspace(dssel.lat[0].data, dssel.lat[-1].data, dssel.sizes['lat']*3)
dsinterp= dssel.interp(lat=new_lat, lon=new_lon)

# Check datanya
fig, ax = plt.subplots(figsize=(20,5), ncols=2)
dssel.plot(ax=ax[0])
dsinterp.plot(ax=ax[1])
ax[0].set_title("Raw data")
ax[1].set_title("Interpolated data")
plt.tight_layout()
plt.show()
../_images/58954ceea7243473077275ef0ac36b7caaf591fe04d11de010d8976c414d370e.png

Masking#

Sebagai percobaan, kita akan memasking daratan khususnya untuk variabel hs.

# Membuat dataset unmasked

dsetfilled = dset[['hs']].isel(time=slice(0,1)).sel(lon=slice(100,120), lat=slice(-9, -6)).fillna(0.0)
dsetfilled['hs'].plot(figsize=(20,5))
<matplotlib.collections.QuadMesh at 0x7fbae97f7390>
../_images/6090453d896407c92d85124e5188312aaac8f5b18347ffc160043b783e13e23e.png
dsetnan = xr.where(dsetfilled != 0, dsetfilled['hs'], np.nan)
dsetnan['hs'].plot(figsize=(20,5))
<matplotlib.collections.QuadMesh at 0x7fbae96e8b90>
../_images/eb42405f7a587b5b68a5e6301b601135d87b960a45a852517a6197490d692529.png

Operasi komputasi dasar#

Aritmatika dasar#

Operasi aritmatika dasar, seperti penjumlahan hingga pembagian bisa diaplikasikan pada DataArray. Pada contoh ini, kita akan menghitung komponen u dan v dari variable mean_wave_direction.

dsetwave = dset[['hs','dir']].isel(time=slice(0,1))
dsetwave
<xarray.Dataset> Size: 7MB
Dimensions:  (time: 1, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables:
    hs       (time, lat, lon) float64 3MB ...
    dir      (time, lat, lon) float64 3MB ...
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
%%time
# Operasi aritmatika dasar dapat dilakukan pada DataArray

uwave = np.cos(np.deg2rad(dsetwave['dir']))
vwave = np.sin(np.deg2rad(dsetwave['dir']))
display(uwave)
display(vwave)
<xarray.DataArray 'dir' (time: 1, lat: 481, lon: 881)> Size: 3MB
array([[[ 0.17210372,  0.16820712,  0.16432471, ...,         nan,
                 nan,         nan],
        [ 0.17705455,  0.17327889,  0.16911433, ...,         nan,
                 nan,         nan],
        [ 0.18196738,  0.17894979,  0.17507474, ...,         nan,
                 nan,         nan],
        ...,
        [-0.75432926, -0.73974809, -0.71655166, ..., -0.94174487,
         -0.94391469, -0.95091948],
        [-0.75852099, -0.74429561, -0.72183337, ..., -0.92626806,
         -0.9264029 , -0.93243347],
        [-0.76282485, -0.74486449, -0.72498708, ..., -0.91261412,
         -0.91013789, -0.90739247]]], shape=(1, 481, 881))
Coordinates:
  * time     (time) datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Attributes:
    long_name:      Mean Wave Direction
    standard_name:  sea_surface_mean_wave_from_direction
    units:          degree
<xarray.DataArray 'dir' (time: 1, lat: 481, lon: 881)> Size: 3MB
array([[[ 0.98507883,  0.98575167,  0.9864063 , ...,         nan,
                 nan,         nan],
        [ 0.98420104,  0.9848728 ,  0.98559644, ...,         nan,
                 nan,         nan],
        [ 0.98330457,  0.98385821,  0.98455515, ...,         nan,
                 nan,         nan],
        ...,
        [-0.65649628, -0.67288392, -0.69753403, ..., -0.33632812,
         -0.33018943, -0.30943842],
        [-0.65164861, -0.66785032, -0.6920669 , ..., -0.37686533,
         -0.37653376, -0.3613417 ],
        [-0.64660517, -0.66721578, -0.68876246, ..., -0.40882205,
         -0.41430547, -0.42028432]]], shape=(1, 481, 881))
Coordinates:
  * time     (time) datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Attributes:
    long_name:      Mean Wave Direction
    standard_name:  sea_surface_mean_wave_from_direction
    units:          degree
CPU times: user 119 ms, sys: 263 μs, total: 119 ms
Wall time: 2.69 s
# QUICK PLOT

fig, ax = plt.subplots(figsize=(20,5), ncols=2)
uwave.plot(ax=ax[0])
ax[0].set_title("UWAVE")
vwave.plot(ax=ax[1])
ax[1].set_title("VWAVE")
plt.tight_layout()
plt.show()
../_images/823388b6abe6829b19d3899facb1b9da3404badb53c476b935e1c9c695d1baa7.png

Apakah terdapat kekeliruan? Ya, satuan dari komponen gelombang u dan v seharusnya bukan degrees, tapi radians. Ini terjadi karena hasil dari komputasi sebelumnya tidak serta merta mengubah atribut, kecuali hanya menurunkan dari variabel induk (dset['dir']).

Pembuatan dataset#

uvwave = xr.Dataset(
    data_vars={
        'uwave':xr.DataArray(
            dims=['time', 'lat', 'lon'], 
            data=uwave.data,
            coords={'time': uwave.time.data, 'lat': uwave.lat.data, 'lon': uwave.lon.data},
            attrs={
                'long_name': 'U Component of Wave',
                'units': None,
            }
        ),
        'vwave':xr.DataArray(
            dims=['time', 'lat', 'lon'], 
            data=vwave.data,
            coords={'time': uwave.time.data, 'lat': uwave.lat.data, 'lon': uwave.lon.data},
            attrs={
                'long_name': 'V Component of Wave',
                'units': None
            }
        ),
    },
    coords={
        'time':('time', uwave.time.data, dsetwave.time.attrs),
        'lat': ('lat', uwave.lat.data, dsetwave.lat.attrs),
        'lon': ('lon', uwave.lon.data, dsetwave.lon.attrs)
    },
    attrs=dsetwave.attrs
)
uvwave
<xarray.Dataset> Size: 7MB
Dimensions:  (time: 1, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables:
    uwave    (time, lat, lon) float64 3MB 0.1721 0.1682 ... -0.9101 -0.9074
    vwave    (time, lat, lon) float64 3MB 0.9851 0.9858 ... -0.4143 -0.4203
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8

Penggabungan#

Terdapat dua method umum untuk menggabungkan dua dataset, yaitu .merge dan .concat.

.merge

.concat

Menggabungkan beberapa Dataset yang memiliki variabel yang berbeda, namun dimensi yang sama

Menggabungkan beberapa dataset yang memiliki variabel yang sama, namun dimensi yang berbeda

merge#
dsetuvwave = xr.merge([dsetwave, uvwave])
dsetuvwave
<xarray.Dataset> Size: 14MB
Dimensions:  (time: 1, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 8B 2025-01-01
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables:
    hs       (time, lat, lon) float64 3MB ...
    dir      (time, lat, lon) float64 3MB 80.09 80.32 80.54 ... -155.5 -155.1
    uwave    (time, lat, lon) float64 3MB 0.1721 0.1682 ... -0.9101 -0.9074
    vwave    (time, lat, lon) float64 3MB 0.9851 0.9858 ... -0.4143 -0.4203
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
concat#
ds1 = dsetwave
ds2 = dset[['hs', 'dir']].isel(time=slice(1,2))
xr.concat([ds1, ds2], dim='time') # concatenate dataset along time axis
<xarray.Dataset> Size: 14MB
Dimensions:  (time: 2, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 16B 2025-01-01 2025-01-01T03:00:00
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables:
    hs       (time, lat, lon) float64 7MB 1.966 1.958 1.949 ... 1.479 1.452
    dir      (time, lat, lon) float64 7MB 80.09 80.32 80.54 ... -156.0 -155.6
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8

Bagaimana jika kita menggabungkan dataset yang memiliki variabel dan dimensi yang berbeda? Menggunakan .concat, namun variabel akan terbroadcast dengan nilai NaN apabila di salah satu dataset tidak terdapat variabel tersebut. Perhatikan contoh berikut.

dsetconcat = xr.concat([dsetuvwave, ds2], dim='time')
dsetconcat
<xarray.Dataset> Size: 27MB
Dimensions:  (time: 2, lat: 481, lon: 881)
Coordinates:
  * time     (time) datetime64[ns] 16B 2025-01-01 2025-01-01T03:00:00
  * lat      (lat) float32 2kB -15.0 -14.94 -14.88 -14.81 ... 14.88 14.94 15.0
  * lon      (lon) float32 4kB 90.0 90.06 90.12 90.19 ... 144.9 144.9 145.0
Data variables:
    hs       (time, lat, lon) float64 7MB 1.966 1.958 1.949 ... 1.479 1.452
    dir      (time, lat, lon) float64 7MB 80.09 80.32 80.54 ... -156.0 -155.6
    uwave    (time, lat, lon) float64 7MB 0.1721 0.1682 0.1643 ... nan nan nan
    vwave    (time, lat, lon) float64 7MB 0.9851 0.9858 0.9864 ... nan nan nan
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8

Dataset yang diatas menghasilkan nilai NaN untuk variabel uwave dan vwave pada dimensi waktu kedua.

Kita bisa memeriksanya dengan method .isnull dan .sum untuk melihat jumlah dan proporsi nilainya.

df_nan_pct = (
    (dsetconcat.isnull().sum(dim=('lat', 'lon')) / (dsetconcat.sizes['lat'] * dsetconcat.sizes['lon']) * 100)
    .to_dataframe()
)
df_nan_pct
hs dir uwave vwave
time
2025-01-01 00:00:00 18.336751 18.336751 18.336751 18.336751
2025-01-01 03:00:00 18.336751 18.336751 100.000000 100.000000
dfcek = (
    (dsetconcat.isnull().sum(dim=('lat','lon')) / 
    (dsetconcat.sizes['lat'] * dsetconcat.sizes['lon']))*100
).to_dataframe()
dfcek
hs dir uwave vwave
time
2025-01-01 00:00:00 18.336751 18.336751 18.336751 18.336751
2025-01-01 03:00:00 18.336751 18.336751 100.000000 100.000000

Agregasi#

Metode agregasi yang umum digunakan untuk mereduksi dimensi Dataset antaran lain parameter statistik (.mean, .max, .min, .std, .sum, .count, .quantile, .median), .groupby, .resample, dan .rolling.

Method

Keterangan

Parameter statistik (.mean, .max, .min, .std, .sum, .count, .quantile, .median)

Agregasi berdasarkan perhitungan statistik

.groupby

Mengelompokkan data berdasarkan label waktu atau kategori lain

.resample

Mengubah frekuensi data waktu (upsample atau downsample)

.rolling

Menghitung agregasi dengan jendela geser (rolling window)

dsetsel = dset[['hs']].sel(lat=slice(-7.5,-6.25), lon=slice(110,118))
dsetsel
<xarray.Dataset> Size: 5MB
Dimensions:  (time: 249, lat: 21, lon: 129)
Coordinates:
  * time     (time) datetime64[ns] 2kB 2025-01-01 ... 2025-02-01
  * lat      (lat) float32 84B -7.5 -7.438 -7.375 -7.312 ... -6.375 -6.312 -6.25
  * lon      (lon) float32 516B 110.0 110.1 110.1 110.2 ... 117.9 117.9 118.0
Data variables:
    hs       (time, lat, lon) float64 5MB ...
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
Agregasi statistik#
%%time

dsmean = dsetsel.mean(dim=['lon', 'lat'])
dsmax  = dsetsel.max(dim=['lon', 'lat'])
dsmin  = dsetsel.min(dim=['lon', 'lat'])
dsstd  = dsetsel.std(dim=['lon', 'lat'])
dssum  = dsetsel.sum(dim=['lon', 'lat'])
dscount  = dsetsel.count(dim=['lon', 'lat'])
dsquantile  = dsetsel.quantile(.75, dim=['lon', 'lat'])
dsmedian  = dsetsel.median(dim=['lon', 'lat'])

lids = [dsmean, dsmax, dsmin, dsstd, dssum, dscount, dsquantile, dsmedian]
CPU times: user 187 ms, sys: 8.75 ms, total: 196 ms
Wall time: 2.42 s
ncols, nrows = 4, 2
fig, ax = plt.subplots(figsize=(15, 10), ncols=ncols, nrows=nrows)
for i in range(ncols * nrows):
    col = i % ncols
    row = i // ncols
    lids[i]['hs'].plot(ax=ax[row, col])  # Note: ax[row, col] for 2D subplot
    ax[row, col].set_title(f'Plot {i}: {lids[i].attrs.get("title", "")}')
../_images/bb481e7ffe7eb6733f0ecdc85e8111839656ba852e2bc49f28d6fa78fc53bce2.png
Groupby#
dfgrouped = dsetsel.groupby('time.hour')

for key, val in dfgrouped:
    print(key, type(val))
    
dfhourlymean = dfgrouped.mean()
dfhourlymean
0 <class 'xarray.core.dataset.Dataset'>
3 <class 'xarray.core.dataset.Dataset'>
6 <class 'xarray.core.dataset.Dataset'>
9 <class 'xarray.core.dataset.Dataset'>
12 <class 'xarray.core.dataset.Dataset'>
15 <class 'xarray.core.dataset.Dataset'>
18 <class 'xarray.core.dataset.Dataset'>
21 <class 'xarray.core.dataset.Dataset'>
<xarray.Dataset> Size: 174kB
Dimensions:  (hour: 8, lat: 21, lon: 129)
Coordinates:
  * lat      (lat) float32 84B -7.5 -7.438 -7.375 -7.312 ... -6.375 -6.312 -6.25
  * lon      (lon) float32 516B 110.0 110.1 110.1 110.2 ... 117.9 117.9 118.0
  * hour     (hour) int64 64B 0 3 6 9 12 15 18 21
Data variables:
    hs       (hour, lat, lon) float64 173kB nan nan nan ... 0.7359 0.7336 0.7316
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
dfhourlymean['hs'].mean(dim=['lon','lat']).plot(ax=plt.subplots(figsize=(8,4))[-1])
[<matplotlib.lines.Line2D at 0x7fbae8f5d590>]
../_images/d21b64eb4672442c7a78aff3f4f888ea204699d29459f6ca0243b945f6bf693c.png

resample#
dsetres = dsetsel.resample(time='1D')
dsetresmean = dsetres.mean()
dsetresmean
<xarray.Dataset> Size: 694kB
Dimensions:  (time: 32, lat: 21, lon: 129)
Coordinates:
  * lat      (lat) float32 84B -7.5 -7.438 -7.375 -7.312 ... -6.375 -6.312 -6.25
  * lon      (lon) float32 516B 110.0 110.1 110.1 110.2 ... 117.9 117.9 118.0
  * time     (time) datetime64[ns] 256B 2025-01-01 2025-01-02 ... 2025-02-01
Data variables:
    hs       (time, lat, lon) float64 694kB nan nan nan nan ... 1.365 1.363 1.36
Attributes:
    source:       Inawaves - BMKG Ocean Forecast System (OFS)
    description:  Inawaves Model - Hindcast
    institution:  BMKG - Center For Marine Meteorology
    email:        produksi.maritim@bmkg.go.id
    Conventions:  CF-1.8
dsetresmean['hs'].mean(dim=['lon','lat']).plot(ax=plt.subplots(figsize=(8,4))[-1])
[<matplotlib.lines.Line2D at 0x7fbae8fd6350>]
../_images/dc785f53f20ab2a2f3996a9177129074d750d5819e39987462b4e6dcfa239341.png
rolling#
%%time

dsetrol = dsetsel.rolling(time=8, center=True)
dsetrol
CPU times: user 4.77 ms, sys: 25 μs, total: 4.8 ms
Wall time: 3.9 ms
DatasetRolling [time->8(center)]
# PERBANDINGAN
fig, ax = plt.subplots(figsize=(12,5), ncols=2)
dsetrol.mean()['hs'].mean(['lon','lat']).plot(ax=ax[0])
dsetsel['hs'].mean(['lon','lat']).plot(ax=ax[1])
ax[0].set_title("Rolling window (8 window mean)")
ax[1].set_title("No Rolling window")
plt.tight_layout()
plt.show()
../_images/100da98d34ebef588d826ee0c91e51d8c3f10f1fedbea407edab94d7fb144380.png