crosstab: Tabulasi Silang

Tabulasi silang frekuensi dengan crosstab untuk pelaporan ringkas.

Daftar isi

Fungsi crosstab menghitung tabel frekuensi silang antara dua kolom kategori dan menjadi penutup modul pengubahan bentuk. Topik ini membahas frekuensi silang ruang terhadap status sensor, proporsi per baris dengan normalize, agregasi nilai dengan values dan aggfunc, serta penerapannya sebagai laporan ringkas kondisi sensor per ruang pada dataset kontrak 96 baris.

crosstab menghitung frekuensi silang#

Fungsi crosstab menjumlahkan banyaknya baris untuk setiap pasangan kategori dari dua kolom, lalu menyusun hasilnya sebagai tabel lebar dengan baris dan kolom kategori. Bangun dataset kontrak log sensor berikut sebagai bahan seluruh topik ini.

python Membangun dataset log sensor 96 baris
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)  # disimpan agar blok berikutnya cukup membaca berkas ini
print(len(df))
text Keluaran
96

Baca kembali berkasnya, lalu hitung tabulasi silang ruang terhadap status sensor dengan satu panggilan. Kedua argumennya berupa deret kategori, bukan nama kolom pada satu DataFrame, sehingga crosstab juga dapat memadukan kolom dari sumber yang berbeda.

python Frekuensi silang ruang dan status sensor
import pandas as pd

df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
print(pd.crosstab(df["ruang"], df["status_sensor"]))
text Keluaran
status_sensor  kalibrasi  normal  rusak
ruang
Lab A                  3      32      1
Lab B                  5      31      2
Ruang Arsip            3      19      0

Barisnya adalah nilai unik ruang dan kolomnya adalah nilai unik status_sensor, dengan urutan alfabetis pada keduanya. Setiap sel menghitung baris yang memiliki pasangan kategori tersebut, misalnya terdapat dua bacaan berstatus rusak di Lab B dan nol di Ruang Arsip. Di balik layar, crosstab merupakan kasus khusus pivot_table dengan agregasi hitung, sehingga tempatnya yang wajar memang pada keluarga pengubah bentuk ini.

Proporsi per baris dengan normalize#

Frekuensi mentah sulit dibandingkan apabila jumlah baris tiap kategori berbeda jauh, dan parameter normalize mengubah frekuensi menjadi proporsi. Nilai normalize="index" membagi setiap sel dengan total barisnya, sehingga jumlah proporsi tiap baris tepat satu.

python Proporsi status sensor per ruang
import pandas as pd

df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
print(pd.crosstab(df["ruang"], df["status_sensor"], normalize="index").round(2))
text Keluaran
status_sensor  kalibrasi  normal  rusak
ruang
Lab A               0.08    0.89   0.03
Lab B               0.13    0.82   0.05
Ruang Arsip         0.14    0.86   0.00

Setiap baris berjumlah 1.00, misalnya Lab A memuat 0.08 ditambah 0.89 ditambah 0.03, dan pembulatan dua desimal menyisakan selisih yang dapat diabaikan. Proporsi memperlihatkan hal yang tidak tampak pada frekuensi mentah, yaitu porsi kalibrasi tertinggi justru berada di Ruang Arsip meskipun jumlah bacaannya paling sedikit. Nilai lain yang tersedia adalah "columns" untuk proporsi per kolom dan "all" untuk proporsi terhadap seluruh tabel, sehingga sudut pandangnya dapat dipilih sesuai kebutuhan laporan.

Rata-rata suhu dengan values dan aggfunc#

Parameter values beserta aggfunc mengganti isi sel dari hitungan frekuensi menjadi agregasi kolom nilai lain, sebagaimana pivot_table pada topik pivot. Contoh berikut menghitung rata-rata suhu untuk setiap pasangan ruang dan status.

python Rata-rata suhu per pasangan ruang dan status
import pandas as pd

df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
print(pd.crosstab(df["ruang"], df["status_sensor"], values=df["suhu_c"], aggfunc="mean").round(1))
text Keluaran
status_sensor  kalibrasi  normal  rusak
ruang
Lab A               23.3    23.7   25.3
Lab B               23.4    23.8   25.0
Ruang Arsip         23.4    24.4    NaN

Sel Ruang Arsip untuk status rusak berupa NaN karena tidak ada baris dengan kombinasi itu, sebagaimana ditunjukkan tabel frekuensi yang selnya nol. Pola yang tampak cukup konsisten, yaitu bacaan berstatus rusak cenderung berasal dari suhu yang lebih tinggi daripada status lain. Kombinasi values dan aggfunc dengan demikian menjadikan crosstab bukan sekadar penghitung, melainkan penyusun ringkasan beragregasi pada kerangka silang yang sama.

Laporan ringkas kondisi sensor per ruang#

Ketiga tabel di atas menyusun laporan kondisi sensor yang siap diserahkan tanpa pengolahan tambahan. Tabel frekuensi menjadi bagian volumetriknya, yaitu Lab A mencatat 32 bacaan normal, 3 kalibrasi, dan 1 rusak, Lab B mencatat 31 normal, 5 kalibrasi, dan 2 rusak, sedangkan Ruang Arsip mencatat 19 normal, 3 kalibrasi, dan 0 rusak. Sel nol pada Ruang Arsip penting dicatat karena berarti tidak ada sensor yang gagal total, bukan bahwa data itu hilang.

Tabel proporsi menjadi bagian perbandingannya karena jumlah bacaan per ruang tidak seimbang, yaitu 36 untuk Lab A, 38 untuk Lab B, dan 22 untuk Ruang Arsip. Porsi bacaan normal tertinggi dimiliki Lab A pada 0.89, sedangkan porsi kalibrasi tertinggi dimiliki Ruang Arsip pada 0.14. Tabel rata-rata suhu melengkapi laporan dengan petunjuk teknis, karena kedua sel berstatus rusak berasal dari suhu sekitar 25 derajat, lebih tinggi daripada status lain pada baris yang sama. Untuk laporan mingguan, kombinasi tiga tabel ini cukup, dan tabelnya dapat diperbarui hanya dengan mengganti sumber df tanpa mengubah satu pun baris kodenya.

Ringkasan#

  • crosstab menghitung frekuensi silang dua kolom kategori dan merupakan kasus khusus pivot_table dengan agregasi hitung.
  • normalize="index" mengubah frekuensi menjadi proporsi per baris, dengan pilihan "columns" dan "all" untuk sudut pandang lain.
  • values beserta aggfunc mengganti hitungan dengan agregasi kolom nilai, dan kombinasi tanpa baris tetap berupa NaN.

Referensi#