Pertanyaan klasik pada data deret waktu berbunyi: “berapa perubahan penjualan dibanding hari sebelumnya?”. Untuk menjawabnya, nilai “kemarin” harus ditempatkan berdampingan dengan nilai “hari ini” pada baris yang sama. shift() melakukan tepi itu: method ini menggeser seluruh nilai maju atau mundur sebanyak n posisi tanpa mengubah index tanggalnya. Pada chapter ini kita membahas arah pergeseran, pengisian posisi kosong dengan fill_value, perbedaan menggeser nilai versus menggeser index lewat freq, dan penerapannya untuk membandingkan total penjualan antarbulan.

Menggeser Nilai Antarbaris #

df["penjualan"].shift(1) menurunkan setiap nilai satu baris: nilai 2026-01-01 pindah ke baris 2026-01-02, dan seterusnya. Akibatnya baris pertama tidak memiliki pembanding dan diisi NaN, sedangkan dtype kolom hasil menjadi float64 karena harus menampung NaN. Arah sebaliknya, shift(-1), mengangkat nilai satu baris sehingga baris terakhir yang kosong. Dari situ, selisih harian cukup dihitung dengan pengurangan biasa antara kolom asli dan kolom hasil geser.

python
import numpy as np
import pandas as pd

tanggal = pd.date_range("2026-01-01", "2026-01-07", freq="D")
df = pd.DataFrame(
    {"penjualan": [200, 202, 284, 286, 208, 210, 212]},
    index=tanggal,
)
df.index.name = "tanggal"

df["kemarin"] = df["penjualan"].shift(1)
df["perubahan"] = df["penjualan"] - df["kemarin"]
print("Penjualan vs hari sebelumnya:")
print(df)

print("\nshift(1, fill_value=0) mengisi nilai awal:")
print(df["penjualan"].shift(1, fill_value=0))

print("\nshift(1, freq='D') menggeser index, bukan nilai:")
print(df["penjualan"].shift(1, freq="D"))

kalender = pd.date_range("2026-01-01", "2026-03-31", freq="D")
harian = pd.Series(
    200 + 2 * np.arange(len(kalender)) + np.where(kalender.dayofweek >= 5, 80, 0),
    index=kalender,
    name="penjualan",
)
bulanan = harian.resample("ME").sum()
ringkas = pd.DataFrame({"penjualan": bulanan, "bulan_lalu": bulanan.shift(1)})
ringkas["perubahan"] = ringkas["penjualan"] - ringkas["bulan_lalu"]
print("\nPerbandingan total penjualan antarbulan:")
print(ringkas)

Output yang Dihasilkan:

text
Penjualan vs hari sebelumnya:
            penjualan  kemarin  perubahan
tanggal                                  
2026-01-01        200      NaN        NaN
2026-01-02        202    200.0        2.0
2026-01-03        284    202.0       82.0
2026-01-04        286    284.0        2.0
2026-01-05        208    286.0      -78.0
2026-01-06        210    208.0        2.0
2026-01-07        212    210.0        2.0

shift(1, fill_value=0) mengisi nilai awal:
tanggal
2026-01-01      0
2026-01-02    200
2026-01-03    202
2026-01-04    284
2026-01-05    286
2026-01-06    208
2026-01-07    210
Freq: D, Name: penjualan, dtype: int64

shift(1, freq='D') menggeser index, bukan nilai:
tanggal
2026-01-02    200
2026-01-03    202
2026-01-04    284
2026-01-05    286
2026-01-06    208
2026-01-07    210
2026-01-08    212
Freq: D, Name: penjualan, dtype: int64

Perbandingan total penjualan antarbulan:
            penjualan  bulan_lalu  perubahan
2026-01-31       7850         NaN        NaN
2026-02-28       8732      7850.0      882.0
2026-03-31      11508      8732.0     2776.0

Mari kita telaah baris-baris kuncinya:

  1. Baris 4-9: DataFrame penjualan tujuh hari dibuat dari date_range harian, lalu df.index.name = "tanggal" memberi label pada kolom index agar repr lebih terbaca.
  2. Baris 11 (shift(1)): kolom kemarin berisi nilai hari sebelumnya; baris 2026-01-01 bernilai NaN karena tidak ada data sebelum tanggal itu.
  3. Baris 12 (perubahan): df["penjualan"] - df["kemarin"] menghitung selisih harian; angka 82.0 pada 2026-01-03 adalah lonjakan akhir pekan, dan -78.0 pada 2026-01-05 adalah koreksi kembali ke hari kerja.
  4. Baris 16-17 (fill_value): shift(1, fill_value=0) mengganti posisi kosong dengan nol sehingga dtype tetap int64.
  5. Baris 19-20 (freq): shift(1, freq="D") menggeser index satu hari sedangkan nilainya tetap.
  6. Baris 22-30 (analisis bulanan): dataset penuh Januari-Maret 2026 dibentuk dari rumus tren, diringkas resample("ME").sum(), lalu shift(1) menempelkan total bulan sebelumnya.

Mengisi Baris Tepi dengan fill_value #

Parameter fill_value hanya mengisi posisi yang kehilangan pasangannya akibat pergeseran, yaitu baris paling awal untuk shift(1). Perhatikan dua efeknya pada output: nilai awal menjadi 0, dan dtype kolom tetap int64 karena tidak lagi ada NaN. Gunakan opsi ini bila angka nol memang bermakna pada konteks data, misalnya stok habis atau hari toko tutup. Untuk penjualan, mengisi nol akan menekan rata-rata dan selisih pertama, jadi pastikan pilihan tersebut disengaja, bukan sekadar untuk menghilangkan NaN.

Menggeser Index, Bukan Nilai #

Bentuk shift(1, freq="D") sering tertukar dengan shift(1) biasa, padahal hasilnya berbeda total. Tanpa freq, yang berpindah adalah nilai: setiap nilai turun satu baris sehingga angka milik 2026-01-01 kini berada pada baris 2026-01-02, sementara index tidak berubah sama sekali. Dengan freq="D", yang berpindah adalah label index: seluruh tanggal maju satu hari (2026-01-02 hingga 2026-01-08) sementara urutan nilai tidak berubah. Bentuk dengan freq berguna ketika stempel waktu perlu dikoreksi, misalnya seluruh catatan tertulis mundur satu hari karena kesalahan sistem perekam.

Membandingkan Total Antarbulan #

Bagian akhir skrip menerapkan shift() pada granularitas yang lebih kasar. Dataset penuh dibentuk dari rumus 200 + 2 × nomor_hari + 80 untuk akhir pekan, lalu resample("ME").sum() menjumlahkannya per bulan. Kolom bulan_lalu berasal dari bulanan.shift(1), sehingga baris Februari memuat total Januari (7850.0) dan baris Maret memuat total Februari (8732.0). Kolom perubahan lalu menunjukkan pertambahan 882.0 unit pada Februari dan 2776.0 unit pada Maret — pola yang sama dengan analisis harian, hanya pada skala bulanan.

Dokumentasi pandas.DataFrame.shift dan pandas.Series.shift merinci parameter periods, freq, dan fill_value, sementara user guide timeseries mengulas pergeseran dalam konteks deret waktu yang lebih luas. Selisih manual df["penjualan"] - df["kemarin"] pada chapter ini masih memerlukan dua langkah. Chapter berikutnya menyederhanakannya menjadi satu method: diff(), lengkap dengan turunannya untuk perubahan persentase.