Dengan data bersih dari Bagian 2: Membersihkan Data, saatnya merangkum 365 hari pengukuran menjadi angka-angka yang bisa dilaporkan: rata-rata suhu per bulan, hari terpanas dan terdingin, serta rekap curah hujan. Semua perhitungan di bagian ini memakai fungsi agregasi NumPy yang telah dipelajari pada Chapter Operasi Berdasarkan Axis — kita hanya mengganti konteksnya menjadi data cuaca.
Satu keputusan teknis perlu disepakati di awal. Kalender 2025 tidak bisa dibagi rata menjadi bulan-bulan 30 hari, maka kita menyederhanakan analisis bulanan menjadi 12 blok × 30 hari = 360 hari pertama; lima hari terakhir Desember tetap terhitung dalam statistik tahunan tetapi tidak masuk tabel bulanan. Penyederhanaan seperti ini lazim dalam analisis eksploratif, selama disebutkan terbuka — dan seluruh proyek memakai aturan yang konsisten.
Statistik Bulanan dengan reshape #
Menghitung rata-rata dua belas bulan tidak membutuhkan loop. Kita mengiris 360 hari pertama, melipatnya menjadi matriks 12 × 30 dengan reshape (Chapter reshape), lalu mengagregasi sepanjang axis=1 — axis hari — sehingga tersisa satu nilai per bulan:
import numpy as np
# Pembangun data cuaca 2025 (data bersih, tanpa sentinel).
rng = np.random.default_rng(42)
t = np.arange(365)
noise = rng.normal(0.0, 1.0, (365, 3)) * np.array([0.8, 0.6, 0.8])
musim = -np.cos(2 * np.pi * t / 365)
suhu_rata = 27.0 + 2.5 * musim + 0.001 * t + noise[:, 0]
suhu_min = suhu_rata - 3.5 + noise[:, 1]
suhu_max = suhu_rata + 4.0 + noise[:, 2]
curah_hujan = np.clip(rng.normal(5.0, 7.0, 365), 0.0, None)
curah_hujan *= 1 + 0.7 * np.cos(2 * np.pi * t / 365)
data = np.column_stack([suhu_rata, suhu_min, suhu_max, curah_hujan])
suhu_bulanan = suhu_rata[:360].reshape(12, 30)
rata_bulanan = suhu_bulanan.mean(axis=1)
bulan = np.array(["Januari", "Februari", "Maret", "April", "Mei", "Juni",
"Juli", "Agustus", "September", "Oktober", "November", "Desember"])
for b, r in zip(bulan, rata_bulanan):
print(f"{b:<10}: {r:5.2f} °C")
print("terpanas :", bulan[np.argmax(rata_bulanan)], f"{rata_bulanan.max():.2f} °C")
print("terdingin:", bulan[np.argmin(rata_bulanan)], f"{rata_bulanan.min():.2f} °C")Output yang Dihasilkan:
Januari : 24.63 °C
Februari : 25.22 °C
Maret : 26.31 °C
April : 27.83 °C
Mei : 28.74 °C
Juni : 29.50 °C
Juli : 29.59 °C
Agustus : 28.88 °C
September : 28.07 °C
Oktober : 26.77 °C
November : 25.86 °C
Desember : 25.26 °C
terpanas : Juli 29.59 °C
terdingin: Januari 24.63 °CYang terjadi di balik blok singkat ini:
suhu_rata[:360].reshape(12, 30): iris 360 elemen dilipat menjadi 12 baris bulan; karena array aslinya 1-D dan kontigu,reshapehanya mengubah cara membaca memori tanpa menyalin data..mean(axis=1): agregasi berjalan horizontal — rata-rata 30 hari di dalam satu baris — menghasilkan 12 nilai bulanan;axis=0justru akan memberi rata-rata per posisi hari.zip(bulan, rata_bulanan): memasangkan label dengan angka agar output siap dibaca manusia.bulan[np.argmax(rata_bulanan)]:argmaxmemberi posisi nilai tertinggi, bukan nilainya, sehingga kita bisa memetakan posisi itu ke nama bulan (lihat Chapter min, max, argmin, dan argmax).
Pola yang muncul sesuai desain dataset: suhu merambat naik dari Januari (24.63 °C) menuju puncak Juli (29.59 °C), lalu turun kembali — rentang musiman hampir 5 °C.
Hari Terpanas dan Terdingin #
Rata-rata bulanan menyembunyikan hari-hari ekstrem. Untuk menemukannya, kita memakai argmax dan argmin pada deret harian, lalu memetakan indeks hari ke tanggal sesungguhnya memakai datetime64 dari Chapter datetime64 dan timedelta64:
import numpy as np
# Pembangun data cuaca 2025 (data bersih, tanpa sentinel).
rng = np.random.default_rng(42)
t = np.arange(365)
noise = rng.normal(0.0, 1.0, (365, 3)) * np.array([0.8, 0.6, 0.8])
musim = -np.cos(2 * np.pi * t / 365)
suhu_rata = 27.0 + 2.5 * musim + 0.001 * t + noise[:, 0]
suhu_min = suhu_rata - 3.5 + noise[:, 1]
suhu_max = suhu_rata + 4.0 + noise[:, 2]
curah_hujan = np.clip(rng.normal(5.0, 7.0, 365), 0.0, None)
curah_hujan *= 1 + 0.7 * np.cos(2 * np.pi * t / 365)
data = np.column_stack([suhu_rata, suhu_min, suhu_max, curah_hujan])
tanggal = np.arange(np.datetime64("2025-01-01"), np.datetime64("2026-01-01"))
i_max = np.argmax(suhu_rata)
i_min = np.argmin(suhu_rata)
print(f"terpanas : {tanggal[i_max]} {suhu_rata[i_max]:.2f} °C")
print(f"terdingin : {tanggal[i_min]} {suhu_rata[i_min]:.2f} °C")
j = np.argmax(suhu_max)
print(f"suhu max tertinggi: {tanggal[j]} {suhu_max[j]:.2f} °C")
k = np.argmin(suhu_min)
print(f"suhu min terendah : {tanggal[k]} {suhu_min[k]:.2f} °C")Output yang Dihasilkan:
terpanas : 2025-07-15 31.24 °C
terdingin : 2025-12-09 23.29 °C
suhu max tertinggi: 2025-06-24 35.84 °C
suhu min terendah : 2025-12-29 19.32 °CPenjelasan singkat:
np.arange(datetime64, datetime64): membuat deret 365 tanggal harian tanpa loop, sehinggatanggal[i]selalu sejajar dengansuhu_rata[i].argmaxpadasuhu_rata: hari terpanas jatuh pada 15 Juli (31.24 °C) — bertepatan dengan puncak musiman, tetapi tanggal persisnya ditentukan derau harian.- Hari terdingin 9 Desember: menariknya, bulan terdingin adalah Januari, tetapi hari terdingin justru di Desember; rata-rata dan ekstrem tidak harus jatuh di tempat yang sama, dan laporan yang jujur menyajikan keduanya.
Rekap Curah Hujan #
Statistik hujan yang paling sering diminta adalah jumlah hari hujan, total tahunan, dan peristiwa hujan terbesar. Ketiganya hanya butuh perbandingan, count_nonzero, dan argmax (pola penghitungan serupa dibahas pada Chapter Counting dan Frekuensi):
import numpy as np
# Pembangun data cuaca 2025 (data bersih, tanpa sentinel).
rng = np.random.default_rng(42)
t = np.arange(365)
noise = rng.normal(0.0, 1.0, (365, 3)) * np.array([0.8, 0.6, 0.8])
musim = -np.cos(2 * np.pi * t / 365)
suhu_rata = 27.0 + 2.5 * musim + 0.001 * t + noise[:, 0]
suhu_min = suhu_rata - 3.5 + noise[:, 1]
suhu_max = suhu_rata + 4.0 + noise[:, 2]
curah_hujan = np.clip(rng.normal(5.0, 7.0, 365), 0.0, None)
curah_hujan *= 1 + 0.7 * np.cos(2 * np.pi * t / 365)
data = np.column_stack([suhu_rata, suhu_min, suhu_max, curah_hujan])
tanggal = np.arange(np.datetime64("2025-01-01"), np.datetime64("2026-01-01"))
hari_hujan = np.count_nonzero(curah_hujan > 1.0)
print("hari hujan (> 1 mm) :", hari_hujan, f"({hari_hujan / 365:.1%})")
print("total curah hujan :", f"{curah_hujan.sum():.1f} mm")
print("rata-rata harian :", f"{curah_hujan.mean():.2f} mm")
i = np.argmax(curah_hujan)
print(f"hujan terbesar: {tanggal[i]} {curah_hujan[i]:.1f} mm")
nol = np.count_nonzero(curah_hujan == 0.0)
print("hari tanpa hujan (0 mm):", nol)Output yang Dihasilkan:
hari hujan (> 1 mm) : 257 (70.4%)
total curah hujan : 2338.0 mm
rata-rata harian : 6.41 mm
hujan terbesar: 2025-12-28 35.8 mm
hari tanpa hujan (0 mm): 85Uraian singkat:
curah_hujan > 1.0: ambang satu milimeter memisahkan gerimis yang tidak berarti dari hujan sesungguhnya; hasilnya mask boolean sepanjang 365 hari.np.count_nonzero(...): menghitung selTrue— jauh lebih ringkas daripada loop penghitung.curah_hujan.sum()dan.mean(): agregasi total dan rata-rata sepanjang satu sumbu data 1-D.argmaxpada hujan: peristiwa terbesar (35.8 mm pada 28 Desember) terjadi saat faktor musim hujan sedang tinggi di akhir tahun.
Angka-angkanya konsisten dengan profil kota sangat lembap: 70.4% hari di atas ambang hujan, total 2 338 mm setahun. Sisa 85 hari tanpa hujan terkonsentrasi saat faktor cos menekan curah hujan di pertengahan tahun.
Statistik di bagian ini masih berdiri sendiri-sendiri. Bagian 4: Menganalisis Pola Cuaca akan menyatukannya — menaksir tren, menyaring anomali, dan merangkai laporan akhir proyek.