Pada Chapter sebelumnya, rolling() menghitung statistik di dalam jendela berukuran tetap: begitu nilai baru masuk, nilai paling lama keluar dari perhitungan. Ada pertanyaan analisis yang justru membutuhkan kebalikannya, misalnya “berapa rata-rata penjualan sejak 1 Januari sampai hari ini?” atau “berapa rekor penjualan tertinggi sejauh ini?”. Untuk kebutuhan seperti itu, pandas menyediakan expanding(), yaitu window yang ukurannya terus bertambah dari satu observasi hingga mencakup seluruh data. Pada chapter ini kita membedah mekanisme expanding(), membandingkan hasilnya dengan rolling(), lalu memanfaatkannya untuk mendeteksi hari yang memecahkan rekor penjualan.

Mekanisme Window Kumulatif #

expanding() tidak langsung menghasilkan angka. Method ini mengembalikan objek expanding window yang kemudian kita beri statistik, misalnya mean(), sum(), atau max(). Pada baris pertama, statistik dihitung dari satu observasi; pada baris kedua dari dua observasi; demikian seterusnya sampai baris terakhir memakai seluruh data. Karena tidak ada nilai yang dibuang dari perhitungan, hasilnya disebut statistik kumulatif. Parameter min_periods default-nya 1, sehingga baris pertama sudah terisi angka — berbeda dengan rolling(3) yang menghasilkan NaN sampai jendela terkumpul penuh.

Skrip berikut membandingkan rolling(3) dengan expanding() pada penjualan harian toko kita selama sepuluh hari pertama Januari 2026:

python
import pandas as pd

tanggal = pd.date_range("2026-01-01", "2026-01-10", freq="D")
penjualan = pd.Series(
    [200, 202, 284, 286, 208, 210, 212, 214, 216, 298],
    index=tanggal,
    name="penjualan",
)

print("Data penjualan 10 hari pertama Januari 2026:")
print(penjualan)

banding = pd.DataFrame(
    {
        "penjualan": penjualan,
        "rolling_3hari": penjualan.rolling(3).mean().round(1),
        "expanding": penjualan.expanding().mean().round(1),
    }
)
print("\nRolling 3 hari vs expanding (rata-rata):")
print(banding)

ringkas = penjualan.expanding().agg(["min", "max", "mean"])
print("\nTiga baris terakhir statistik kumulatif:")
print(ringkas.tail(3).round(1))

rekor = penjualan.expanding().max()
print("\nHari dengan penjualan pecah rekor:")
print(penjualan[penjualan == rekor])

Output yang Dihasilkan:

text
Data penjualan 10 hari pertama Januari 2026:
2026-01-01    200
2026-01-02    202
2026-01-03    284
2026-01-04    286
2026-01-05    208
2026-01-06    210
2026-01-07    212
2026-01-08    214
2026-01-09    216
2026-01-10    298
Freq: D, Name: penjualan, dtype: int64

Rolling 3 hari vs expanding (rata-rata):
            penjualan  rolling_3hari  expanding
2026-01-01        200            NaN      200.0
2026-01-02        202            NaN      201.0
2026-01-03        284          228.7      228.7
2026-01-04        286          257.3      243.0
2026-01-05        208          259.3      236.0
2026-01-06        210          234.7      231.7
2026-01-07        212          210.0      228.9
2026-01-08        214          212.0      227.0
2026-01-09        216          214.0      225.8
2026-01-10        298          242.7      233.0

Tiga baris terakhir statistik kumulatif:
              min    max   mean
2026-01-08  200.0  286.0  227.0
2026-01-09  200.0  286.0  225.8
2026-01-10  200.0  298.0  233.0

Hari dengan penjualan pecah rekor:
2026-01-01    200
2026-01-02    202
2026-01-03    284
2026-01-04    286
2026-01-10    298
Name: penjualan, dtype: int64

Mari kita telaah baris-baris kuncinya:

  1. Baris 3 (date_range): pandas membuat DatetimeIndex sepuluh hari berturut-turut mulai 2026-01-01 dengan frekuensi "D" (harian).
  2. Baris 4-8 (pd.Series): sepuluh nilai penjualan ditempelkan pada index tanggal, dengan name="penjualan" agar repr Series lebih informatif.
  3. Baris 13-19 (pd.DataFrame): tiga kolom disandingkan untuk perbandingan berdampingan: nilai asli, rata-rata rolling(3), dan rata-rata expanding(), semuanya dibulatkan satu desimal.
  4. Baris 23 (agg): expanding().agg(["min", "max", "mean"]) menghitung tiga statistik kumulatif sekaligus; tail(3) hanya menampilkan tiga baris terakhirnya.
  5. Baris 27-29 (deteksi rekor): expanding().max() menjadi patokan rekor, lalu penjualan[penjualan == rekor] memfilter tanggal yang nilainya sama dengan rekor kumulatif tersebut.

Membaca Hasil Perbandingan #

Pada 2026-01-03, kolom rolling_3hari dan expanding sama-sama 228.7 karena keduanya menghitung (200 + 202 + 284) / 3. Perbedaan baru muncul di 2026-01-04: rolling_3hari bernilai 257.3 (rata-rata tiga hari terakhir), sedangkan expanding bernilai 243.0 (rata-rata empat hari sejak awal periode). Pola ini berlanjut sampai akhir data: rolling_3hari merespons fluktuasi lokal dan ikut turun saat penjualan hari kerja biasa, sedangkan expanding bergerak lebih halus karena seluruh riwayat menahan pergeserannya. Keduanya sama-sama sah; pilihannya bergantung pada pertanyaan analisis — tren jangka pendek atau akumulasi sejak awal.

Statistik Kumulatif dan Deteksi Rekor #

Bagian akhir skrip memperlihatkan dua penerapan yang sering dipakai. Pertama, agg(["min", "max", "mean"]) merangkum batas terendah, rekor tertinggi, dan rata-rata sejauh ini; pada 2026-01-09 rekor masih 286.0, lalu naik ke 298.0 di 2026-01-10. Kedua, membandingkan nilai asli dengan rekor kumulatif menghasilkan lima hari rekor: 200, 202, 284, 286, dan 298 unit. Setiap kali penjualan melewati rekor sebelumnya, hasil expanding().max() ikut naik, sehingga tanggal-tanggal tersebut adalah momen ketika toko mencetak angka tertinggi terbarunya.

Dokumentasi Windowing operations menempatkan expanding() dalam satu keluarga dengan rolling() dan ewm(), sedangkan referensi pandas.DataFrame.expanding merinci parameter seperti min_periods. expanding() memberi bobot sama pada seluruh data lama, padahal sering kali data terbaru lebih informatif daripada data berbulan-bulan lalu. Chapter berikutnya membahas exponentially weighted window melalui ewm(), yang memberi bobot terbesar pada observasi terkini dan bobot menurun secara eksponensial ke arah data lama.