Bacaan mentah log sensor bergerak naik turun pada setiap lima belas menit, sehingga kecenderungan jangka pendeknya sulit dibaca tanpa perataan. Topik ini membahas rolling untuk rata-rata bergerak dalam jendela tetap, expanding untuk statistik kumulatif sejak awal deret, cara menggabungkan keduanya ke dalam tabel, dan pembuatan grafik garis dengan matplotlib. Setelah membaca, tren suhu pada dataset kontrak dapat ditampilkan berdampingan dengan nilai mentahnya.
Jendela empat bacaan dengan rolling#
Method rolling(window=4) membentuk window, yaitu jendela bergerak yang setiap posisinya memuat 4 baris terakhir termasuk baris saat ini, lalu mean() menghitung rata-ratanya. Pada log berjarak tetap lima belas menit, empat bacaan setara dengan satu jam, sehingga hasilnya lazim disebut rata-rata satu jam. Nilai bawaan min_periods sama dengan ukuran jendela, sehingga posisi yang jendelanya belum penuh menghasilkan NaN.
import numpy as np
import pandas as pd
rng = np.random.default_rng(42)
n = 96
df = pd.DataFrame({
"waktu": pd.date_range("2026-01-05 07:00", periods=n, freq="15min"),
"ruang": rng.choice(["Lab A", "Lab B", "Ruang Arsip"], n, p=[0.4, 0.35, 0.25]),
"suhu_c": np.round(rng.normal(24, 1.5, n), 1),
"lembap_pct": np.round(rng.normal(60, 5, n), 1),
"status_sensor": rng.choice(["normal", "kalibrasi", "rusak"], n, p=[0.85, 0.10, 0.05]),
})
df.to_csv("sensor_log.csv", index=False) # dataset bersama untuk seluruh modul
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
s = df["suhu_c"]
print(s.rolling(window=4).mean().head(6))
print(s.rolling(window=4, min_periods=1).mean().head(6))0 NaN
1 NaN
2 NaN
3 21.950
4 22.725
5 22.925
Name: suhu_c, dtype: float64
0 21.500000
1 21.650000
2 21.766667
3 21.950000
4 22.725000
5 22.925000
Name: suhu_c, dtype: float64Blok pertama keluaran memperlihatkan tiga NaN awal karena jendela 4 bacaan baru penuh pada baris keempat, dan nilai 21.950 pada baris itu adalah rata-rata bacaan 21.5, 21.8, 22.0, dan 22.5. Blok kedua memakai min_periods=1, sehingga setiap posisi dihitung dari bacaan yang tersedia dan tidak ada baris yang kosong. Keduanya menyatu pada baris keempat dan seterusnya, sehingga pilihan min_periods hanya mengubah awal deret, bukan isi jendela yang sudah penuh.
Rata-rata kumulatif dengan expanding#
Method expanding().mean() menghitung rata-rata semua baris dari awal deret sampai baris saat ini, sehingga jendelanya tumbuh terus dan bukan tetap sepanjang 4 baris. Pada baris pertama, hasilnya sama dengan nilai mentahnya karena hanya ada satu bacaan, dan nilainya berubah makin lambat seiring bertambahnya banyak data. Method ini tidak menghasilkan NaN sejak baris pertama, berbeda dengan rolling pada nilai bawaannya.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
print(df["suhu_c"].expanding().mean().head(4))0 21.500000
1 21.650000
2 21.766667
3 21.950000
Name: suhu_c, dtype: float64Keluaran menunjukkan rata-rata yang bergerak dari 21.500000 menuju 21.950000 selama empat bacaan pertama, dan angka 21.950000 yang terakhir sama persis dengan rata-rata jendela 4 bacaan pada bagian sebelumnya karena pada baris tersebut seluruh data yang ada adalah jendelanya. Fungsi lain seperti max dan min dapat dipanggil pada objek expanding yang sama dengan mekanisme tumbuh yang serupa. Statistik kumulatif ini menjawab pertanyaan rata-rata sejauh ini, sedangkan rolling menjawab rata-rata dalam satu jam terakhir.
Menggabungkan hasil ke tabel dan grafik#
Hasil rolling dan expanding ditambahkan sebagai kolom baru dengan penugasan df["nama_kolom"] = deret_hasil, sehingga tabel memuat nilai mentah beserta perataannya dalam satu baris per waktu. Kedua deret hasil memiliki urutan baris yang sama dengan tabel asalnya, sehingga penugasan kolom langsung selaras tanpa langkah penggabungan tambahan. Sepuluh baris pertama tabel berikut membandingkan ketiganya secara langsung.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
df["suhu_menit_60"] = df["suhu_c"].rolling(window=4).mean()
df["suhu_sejauh_ini"] = df["suhu_c"].expanding().mean()
kolom = ["waktu", "suhu_c", "suhu_menit_60", "suhu_sejauh_ini"]
print(df[kolom].head(10)) waktu suhu_c suhu_menit_60 suhu_sejauh_ini
0 2026-01-05 07:00:00 21.5 NaN 21.500000
1 2026-01-05 07:15:00 21.8 NaN 21.650000
2 2026-01-05 07:30:00 22.0 NaN 21.766667
3 2026-01-05 07:45:00 22.5 21.950 21.950000
4 2026-01-05 08:00:00 24.6 22.725 22.480000
5 2026-01-05 08:15:00 22.6 22.925 22.500000
6 2026-01-05 08:30:00 23.4 23.275 22.628571
7 2026-01-05 08:45:00 25.9 24.125 23.037500
8 2026-01-05 09:00:00 23.5 23.850 23.088889
9 2026-01-05 09:15:00 25.1 24.475 23.290000Kolom suhu_menit_60 bernilai NaN pada tiga baris pertama sebagaimana keluaran bagian Jendela empat bacaan dengan rolling, sedangkan suhu_sejauh_ini terisi sejak baris pertama. Perbandingan baris demi baris terlihat langsung, misalnya bacaan mentah 25.9 pada pukul 08.45 disertai rata-rata satu jam 24.125 yang lebih landai. Kolom tambahan seperti ini tetap ikut tersalin ketika tabel difilter atau ditulis ulang, sehingga analisis berikutnya tidak mengulang perhitungannya.
Grafik garis memperlihatkan hubungan ketiga deret tersebut sekaligus, dan blok berikut membuatnya dengan matplotlib lalu menyimpannya sebagai berkas suhu-rolling.svg di direktori kerja. Deret mentah digambar tipis, sedangkan kedua rata-rata digambar lebih tebal agar kecenderungannya menonjol.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).head(24)
plt.figure(figsize=(6.4, 2.8), constrained_layout=True)
plt.plot(df["waktu"], df["suhu_c"], linewidth=1.0, label="nilai mentah")
plt.plot(df["waktu"], df["suhu_c"].rolling(window=4, min_periods=1).mean(), linewidth=1.8, label="rata-rata bergerak 4 bacaan")
plt.plot(df["waktu"], df["suhu_c"].expanding().mean(), linewidth=1.8, label="rata-rata kumulatif")
plt.ylabel("suhu (derajat Celsius)")
plt.legend(bbox_to_anchor=(0.5, -0.42), loc="upper center", ncol=3, fontsize=8)
plt.savefig("suhu-rolling.svg")
print("tersimpan suhu-rolling.svg")tersimpan suhu-rolling.svgBerkas suhu-rolling.svg memuat grafik 24 bacaan pertama, yaitu enam jam pertama log. Garis nilai mentah berayun paling tajam, garis rata-rata bergerak mengikutinya dengan ayunan yang dipangkas, dan garis kumulatif hampir mendatar karena seluruh riwayat ikut dirata-rata. Perbandingan visual ini menegaskan bahwa makin panjang jendela perataannya, makin landai pula deret hasilnya, dengan konsekuensi informasi detail yang makin sedikit.
Kesalahan umum#
Nilai NaN pada awal hasil rolling sering dikira data sensor yang hilang, padahal ia adalah jendela yang belum penuh. Kekeliruan ini berbahaya ketika jumlah NaN dipakai sebagai ukuran kualitas data, karena hitungannya ikut menaik sebesar ukuran jendela dikurangi satu. Blok berikut membandingkan hitungan NaN dari kedua sumber, lalu menunjukkan bahwa jendela menghitung baris dan bukan durasi waktu ketika deret berlubang.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
rata = df["suhu_c"].rolling(window=4).mean()
print("NaN akibat jendela:", rata.isna().sum())
print("data hilang pada kolom asal:", df["suhu_c"].isna().sum())
berlubang = df["suhu_c"].head(6).drop(index=[2, 3])
print(berlubang.rolling(window=4, min_periods=4).mean())NaN akibat jendela: 3
data hilang pada kolom asal: 0
0 NaN
1 NaN
4 NaN
5 22.625
Name: suhu_c, dtype: float64Hitungan 3 berbanding 0 menunjukkan bahwa seluruh NaN berasal dari jendela dan bukan dari data, sehingga min_periods=1 menghilangkannya bila jendela parsial dapat diterima. Deret berlubang menyisihkan bacaan pukul 07.30 dan 07.45, sehingga jendela 4 baris pada posisi terakhirnya merentang dari pukul 07.00 sampai 08.15 atau tujuh puluh lima menit, bukan empat puluh lima menit seperti pada deret utuh. Nilai 22.625 pada baris itu pun merata-ratakan baris yang berjauhan waktunya, sehingga jendela tetap perlu diperiksa terhadap kelengkapan waktu bila maknanya berbasis durasi.
Ringkasan#
rolling(window=4).mean()merata-ratakan 4 baris terakhir pada setiap posisi, danmin_periods=1mengisi awal deret dengan jendela parsial.expanding().mean()menghitung rata-rata seluruh riwayat sampai baris saat ini tanpa NaN, dengan jendela yang terus tumbuh.- Hasil keduanya ditambahkan sebagai kolom baru lewat penugasan
df["nama_kolom"] = deret_hasilsehingga tabel memuat nilai mentah dan perataannya sekaligus. - NaN awal pada
rollingadalah jendela yang belum penuh, dan jendela menghitung baris serta bukan durasi waktu pada deret yang berlubang.
Referensi#
- pandas.DataFrame.rolling — pandas API reference — dokumentasi resmi rolling beserta parameter window dan min_periods.
- pandas.DataFrame.expanding — pandas API reference — dokumentasi resmi expanding untuk statistik kumulatif.
- Windowing operations — pandas User Guide — bab resmi operasi jendela yang mencakup rolling dan expanding.