Pada Praktikum 5, kita mempelajari hubungan antarpeubah melalui visualisasi, tabel, dan ukuran korelasi. Pertemuan ini melanjutkan alur tersebut dengan pertanyaan baru:
Dari seluruh peubah yang tersedia, peubah mana yang paling relevan untuk dipertahankan?
Proses memilih sebagian peubah yang relevan disebut seleksi peubah atau feature selection. Pada praktikum ini kita fokus pada metode filter, yaitu metode yang menilai setiap fitur menggunakan ukuran statistik sebelum model dibangun.
Sebelum memilih fitur, kenali target, tipe fitur, dan alasan pemilihannya.
Seleksi peubah adalah proses mempertahankan fitur yang relevan dan menyisihkan fitur yang kurang informatif untuk tujuan analisis tertentu.
Seleksi peubah dapat membantu:
Namun, fitur yang tidak terpilih oleh satu metode belum tentu sama sekali tidak berguna. Hasil seleksi selalu bergantung pada target, ukuran statistik, batas seleksi, dan konteks analisis.
| Metode | Cara kerja | Contoh |
|---|---|---|
| Filter | Menilai fitur menggunakan ukuran statistik sebelum model dilatih | Chi-square, ANOVA, korelasi, mutual information |
| Wrapper | Mencoba beberapa subset fitur dan membandingkan kinerja model | Forward selection, backward elimination, RFE |
| Embedded | Seleksi terjadi sebagai bagian dari proses pelatihan model | LASSO, decision tree, random forest |
Pada praktikum ini kita hanya membahas metode filter.
| Tipe fitur | Tipe target | Metode yang dapat digunakan |
|---|---|---|
| Kategorik | Kategorik | Chi-square |
| Numerik | Kategorik | ANOVA F-test |
| Numerik | Numerik | Korelasi Pearson atau Spearman |
| Token/kata | Kategorik | Chi-square setelah teks dibentuk menjadi matriks fitur |
| Token/kata tanpa target | Tidak ada | Document Frequency |
| Teks yang ingin diberi bobot | Tidak ada | TF-IDF, kemudian threshold atau top-k |
Jika tidak ada target: jangan memaksakan Chi-square, ANOVA, atau korelasi dengan target. Gunakan kriteria tanpa target, misalnya proporsi missing value, varians sangat rendah, fitur duplikat, korelasi antarprediktor, atau Document Frequency untuk data teks.
Jalankan install.packages() hanya jika package belum
pernah dipasang.
tipsAgar alurnya tetap terhubung dengan Praktikum 5, kita kembali
menggunakan dataset tips. Pada praktikum ini, dataset
tersebut digunakan untuk memahami cara memilih fitur.
data("tips", package = "reshape2")
tips <- tips %>%
mutate(
across(c(sex, smoker, day, time), as.factor)
)
str(tips)## 'data.frame': 244 obs. of 7 variables:
## $ total_bill: num 17 10.3 21 23.7 24.6 ...
## $ tip : num 1.01 1.66 3.5 3.31 3.61 4.71 2 3.12 1.96 3.23 ...
## $ sex : Factor w/ 2 levels "Female","Male": 1 2 2 2 1 2 2 2 2 2 ...
## $ smoker : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
## $ day : Factor w/ 4 levels "Fri","Sat","Sun",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ time : Factor w/ 2 levels "Dinner","Lunch": 1 1 1 1 1 1 1 1 1 1 ...
## $ size : int 2 3 3 2 4 4 2 4 2 2 ...
ringkasan_tips <- data.frame(
Peubah = names(tips),
Tipe = sapply(tips, function(x) class(x)[1]),
Keterangan = c(
"Total tagihan restoran",
"Tip yang diberikan",
"Jenis kelamin pembayar",
"Status perokok",
"Hari kunjungan",
"Waktu makan",
"Jumlah orang dalam grup"
)
)
kable(ringkasan_tips, align = c("l", "l", "l"))| Peubah | Tipe | Keterangan | |
|---|---|---|---|
| total_bill | total_bill | numeric | Total tagihan restoran |
| tip | tip | numeric | Tip yang diberikan |
| sex | sex | factor | Jenis kelamin pembayar |
| smoker | smoker | factor | Status perokok |
| day | day | factor | Hari kunjungan |
| time | time | factor | Waktu makan |
| size | size | integer | Jumlah orang dalam grup |
Pada contoh Chi-square dan ANOVA, time digunakan sebagai
target kategorik. Pada contoh korelasi, tip digunakan
sebagai target numerik.
⚠️ Pada praktikum ini seluruh data digunakan agar hasil eksplorasi mudah dibandingkan. Jika seleksi fitur dilakukan untuk membangun dan mengevaluasi model prediksi, tentukan fitur menggunakan data training saja untuk mencegah data leakage.
Uji Chi-square digunakan untuk memeriksa apakah dua peubah kategorik saling berasosiasi.
Untuk setiap fitur, hipotesisnya adalah:
Kita akan menilai apakah sex, smoker, dan
day berkaitan dengan target time.
##
## Dinner Lunch
## Female 52 35
## Male 124 33
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tabel_sex_time
## X-squared = 9.3438, df = 1, p-value = 0.002237
Cara membaca output:
p-value;p-value < 0.05, terdapat bukti statistik adanya
asosiasi;uji_sex_time$expected.Jika ada frekuensi harapan yang kecil (pedoman umum: kurang dari 5), pendekatan p-value Chi-square biasa perlu ditinjau. Pada tabel yang cukup besar, R dapat menghitung p-value melalui simulasi Monte Carlo.
P-value membantu menilai bukti statistik, tetapi tidak menunjukkan besar asosiasi. Karena itu, kita tambahkan Cramer’s V sebagai ukuran kekuatan asosiasi.
fitur_kategorik <- c("sex", "smoker", "day")
set.seed(1381) # membuat hasil simulasi dapat diulang
hasil_chi <- lapply(fitur_kategorik, function(fitur) {
tabel <- table(tips[[fitur]], tips$time)
harapan <- outer(rowSums(tabel), colSums(tabel)) / sum(tabel)
perlu_simulasi <- any(harapan < 5)
uji <- chisq.test(
tabel,
simulate.p.value = perlu_simulasi,
B = 10000
)
chi_square <- unname(uji$statistic)
n <- sum(tabel)
cramers_v <- sqrt(
chi_square / (n * (min(dim(tabel)) - 1))
)
data.frame(
fitur = fitur,
chi_square = chi_square,
p_value = uji$p.value,
cramers_v = cramers_v,
frekuensi_harapan_minimum = min(uji$expected),
metode_p_value = if (perlu_simulasi) "Simulasi" else "Asimtotik"
)
}) %>%
bind_rows() %>%
mutate(
p_adjusted = p.adjust(p_value, method = "BH"),
keputusan = if_else(
p_adjusted < 0.05,
"Dipertimbangkan",
"Belum terpilih"
)
) %>%
arrange(p_value)
kable(hasil_chi, digits = 4)| fitur | chi_square | p_value | cramers_v | frekuensi_harapan_minimum | metode_p_value | p_adjusted | keputusan |
|---|---|---|---|---|---|---|---|
| day | 217.1127 | 0.0000 | 0.9433 | 5.2951 | Asimtotik | 0.0000 | Dipertimbangkan |
| sex | 9.3438 | 0.0022 | 0.1957 | 24.2459 | Asimtotik | 0.0034 | Dipertimbangkan |
| smoker | 0.5054 | 0.4771 | 0.0455 | 25.9180 | Asimtotik | 0.4771 | Belum terpilih |
ggplot(
hasil_chi,
aes(x = reorder(fitur, cramers_v), y = cramers_v)
) +
geom_col(fill = "#E67E22", width = 0.65) +
coord_flip() +
labs(
title = "Kekuatan Asosiasi Fitur Kategorik dengan Waktu Makan",
x = "Fitur",
y = "Cramer's V"
) +
theme_minimal()Interpretasi hasil (kriteria p-value yang sudah dikoreksi dengan Benjamini–Hochberg):
day memiliki asosiasi paling kuat dengan
time;sex juga menunjukkan asosiasi secara statistik, tetapi
kekuatannya jauh lebih kecil;smoker tidak memenuhi kriteria
p-value < 0.05 pada data ini.Hasil tersebut masuk akal dalam konteks dataset karena sebagian besar observasi makan siang terjadi pada Thursday dan Friday, sedangkan Saturday dan Sunday didominasi makan malam. Hubungan ini menggambarkan struktur data, bukan hubungan sebab-akibat.
Untuk day, perhatikan kolom metode_p_value:
ada sel tabel dengan frekuensi harapan kecil, sehingga p-value dihitung
lewat simulasi. P-value simulasi dapat sedikit berubah bila jumlah
simulasi atau seed diubah. Statistik Chi-square dan Cramer’s V tetap
dihitung dari tabel asli.
Latihan 1: ubah target menjadi smoker.
Gunakan sex, day, dan time
sebagai kandidat fitur. Fitur mana yang terpilih pada taraf 5%?
ANOVA F-test digunakan ketika fitur berbentuk numerik dan target berbentuk kategorik. Metode ini memeriksa apakah rata-rata suatu fitur berbeda antar kelas target.
Hipotesis untuk setiap fitur adalah:
Kandidat fitur numerik yang digunakan adalah total_bill,
tip, dan size, sedangkan targetnya adalah
time.
fitur_numerik <- c("total_bill", "tip", "size")
hasil_anova <- lapply(fitur_numerik, function(fitur) {
formula_uji <- as.formula(paste(fitur, "~ time"))
tabel_anova <- summary(aov(formula_uji, data = tips))[[1]]
data.frame(
fitur = fitur,
f_value = tabel_anova[1, "F value"],
p_value = tabel_anova[1, "Pr(>F)"]
)
}) %>%
bind_rows() %>%
mutate(
p_adjusted = p.adjust(p_value, method = "BH"),
keputusan = if_else(
p_adjusted < 0.05,
"Dipertimbangkan",
"Belum terpilih"
)
) %>%
arrange(p_value)
kable(hasil_anova, digits = 4)| fitur | f_value | p_value | p_adjusted | keputusan |
|---|---|---|---|---|
| total_bill | 8.3963 | 0.0041 | 0.0123 | Dipertimbangkan |
| tip | 3.6338 | 0.0578 | 0.0867 | Belum terpilih |
| size | 2.6159 | 0.1071 | 0.1071 | Belum terpilih |
rata_rata_time <- tips %>%
group_by(time) %>%
summarise(
across(
all_of(fitur_numerik),
~ mean(.x, na.rm = TRUE)
),
.groups = "drop"
)
kable(rata_rata_time, digits = 3)| time | total_bill | tip | size |
|---|---|---|---|
| Dinner | 20.797 | 3.103 | 2.631 |
| Lunch | 17.169 | 2.728 | 2.412 |
ggplot(
hasil_anova,
aes(x = reorder(fitur, -log10(p_adjusted)), y = -log10(p_adjusted))
) +
geom_col(fill = "#294B67", width = 0.65) +
geom_hline(
yintercept = -log10(0.05),
linetype = "dashed",
color = "#E67E22"
) +
coord_flip() +
labs(
title = "Peringkat Fitur Berdasarkan ANOVA",
subtitle = "Garis putus-putus: batas p-value terkoreksi = 0.05",
x = "Fitur",
y = "-log10(p-value)"
) +
theme_minimal()Interpretasi hasil (p-value yang sudah dikoreksi):
total_bill memenuhi kriteria
p-value < 0.05;tip memiliki p-value sekitar 0,058 sehingga belum
memenuhi batas 0,05;size juga belum memenuhi batas 0,05.P-value yang sedikit lebih besar daripada 0,05 tidak berarti hubungan pasti tidak ada. Kesimpulan yang tepat adalah bukti pada data ini belum cukup untuk memenuhi kriteria seleksi yang ditetapkan. ANOVA membandingkan rata-rata antarkelompok; variance threshold menyaring fitur yang variasinya kecil tanpa memakai target. Keduanya berbeda, meski sama-sama melibatkan gagasan variasi.
ANOVA mengasumsikan observasi independen, galat yang kurang lebih normal, dan variasi antarkelompok yang sebanding. Pada data nyata, periksa distribusi dan pencilan sebelum menarik kesimpulan kuat.
Latihan 2: ganti target menjadi smoker.
Bandingkan hasil ANOVA untuk total_bill, tip,
dan size. Apakah hasil seleksinya sama?
Jika fitur dan target sama-sama numerik, korelasi dapat digunakan untuk memberi peringkat fitur berdasarkan arah dan kekuatan hubungannya dengan target.
Pada contoh ini:
tip;total_bill dan size.Kita menggunakan korelasi Pearson karena fokusnya adalah hubungan linear.
target_numerik <- "tip"
fitur_korelasi <- c("total_bill", "size")
hasil_korelasi <- lapply(fitur_korelasi, function(fitur) {
uji <- cor.test(
tips[[fitur]],
tips[[target_numerik]],
method = "pearson"
)
data.frame(
fitur = fitur,
korelasi = unname(uji$estimate),
p_value = uji$p.value
)
}) %>%
bind_rows() %>%
mutate(
absolut_korelasi = abs(korelasi),
keputusan = if_else(
absolut_korelasi >= 0.30 & p_value < 0.05,
"Dipertimbangkan",
"Belum terpilih"
)
) %>%
arrange(desc(absolut_korelasi))
kable(hasil_korelasi, digits = 4)| fitur | korelasi | p_value | absolut_korelasi | keputusan |
|---|---|---|---|---|
| total_bill | 0.6757 | 0 | 0.6757 | Dipertimbangkan |
| size | 0.4893 | 0 | 0.4893 | Dipertimbangkan |
ggplot(
hasil_korelasi,
aes(x = reorder(fitur, absolut_korelasi), y = absolut_korelasi)
) +
geom_col(fill = "#E67E22", width = 0.65) +
geom_hline(
yintercept = 0.30,
linetype = "dashed",
color = "#294B67"
) +
coord_flip() +
labs(
title = "Korelasi Kandidat Fitur dengan Tip",
subtitle = "Batas |r| ≥ 0.30 hanya digunakan sebagai contoh kriteria",
x = "Fitur",
y = "Nilai absolut korelasi"
) +
theme_minimal()Interpretasi hasil:
total_bill dengan tip sekitar
0,676;size dengan tip sekitar
0,489;p-value < 0.05.Nilai absolut digunakan untuk pemeringkatan karena korelasi positif dan negatif sama-sama dapat informatif. Tanda positif atau negatif tetap harus dipertahankan ketika menginterpretasikan arah hubungan.
⚠️ Tidak ada batas korelasi yang berlaku universal. Batas 0,30 pada contoh ini merupakan kriteria pembelajaran dan harus disesuaikan dengan bidang kajian serta tujuan analisis.
Latihan 3: gunakan korelasi Spearman pada pasangan fitur yang sama. Apakah urutan fitur berubah?
Data hasil scraping sering memiliki satu kolom teks yang kemudian diubah menjadi ratusan atau ribuan token. Tidak semua token perlu dipertahankan.
Pada bagian ini kita menggunakan dua pendekatan:
ulasan <- data.frame(
id = 1:8,
teks = c(
"pengiriman cepat dan layanan pelanggan sangat baik",
"layanan pelanggan buruk dan respon sangat lambat",
"barang bagus tetapi pengiriman sangat lambat",
"sangat puas dengan pengiriman dan layanan",
"harga murah tetapi kualitas barang kurang baik",
"kualitas barang baik dan harga cukup murah",
"respon pelanggan cepat dan layanan sangat ramah",
"pengiriman lambat tetapi kualitas barang bagus"
),
stringsAsFactors = FALSE
)
ulasanstop_id <- c(
"dan", "yang", "di", "ke", "dari", "dengan",
"sangat", "untuk", "ini", "itu", "saya",
"tetapi", "cukup"
)
token <- ulasan %>%
unnest_tokens(kata, teks) %>%
filter(!kata %in% stop_id)
head(token, 12)Document Frequency menghitung jumlah dokumen yang memuat sebuah kata. Pada contoh ini kita mempertahankan kata yang:
n_dokumen <- nrow(ulasan)
hasil_df <- token %>%
distinct(id, kata) %>%
count(kata, name = "document_frequency") %>%
mutate(
proporsi_dokumen = document_frequency / n_dokumen,
keputusan = if_else(
document_frequency >= 2 & proporsi_dokumen <= 0.75,
"Dipertahankan",
"Dihapus"
)
) %>%
arrange(desc(document_frequency), kata)
kable(hasil_df, digits = 3)| kata | document_frequency | proporsi_dokumen | keputusan |
|---|---|---|---|
| barang | 4 | 0.500 | Dipertahankan |
| layanan | 4 | 0.500 | Dipertahankan |
| pengiriman | 4 | 0.500 | Dipertahankan |
| baik | 3 | 0.375 | Dipertahankan |
| kualitas | 3 | 0.375 | Dipertahankan |
| lambat | 3 | 0.375 | Dipertahankan |
| pelanggan | 3 | 0.375 | Dipertahankan |
| bagus | 2 | 0.250 | Dipertahankan |
| cepat | 2 | 0.250 | Dipertahankan |
| harga | 2 | 0.250 | Dipertahankan |
| murah | 2 | 0.250 | Dipertahankan |
| respon | 2 | 0.250 | Dipertahankan |
| buruk | 1 | 0.125 | Dihapus |
| kurang | 1 | 0.125 | Dihapus |
| puas | 1 | 0.125 | Dihapus |
| ramah | 1 | 0.125 | Dihapus |
hasil_df %>%
filter(keputusan == "Dipertahankan") %>%
ggplot(
aes(
x = reorder(kata, document_frequency),
y = document_frequency
)
) +
geom_col(fill = "#294B67", width = 0.7) +
coord_flip() +
labs(
title = "Kata yang Lolos Document Frequency Filtering",
x = "Kata",
y = "Jumlah dokumen"
) +
theme_minimal()DF Filtering bersifat hard filtering karena kata yang tidak memenuhi batas benar-benar dikeluarkan dari kumpulan fitur.
TF-IDF memberikan bobot tinggi pada kata yang relatif penting dalam suatu dokumen, tetapi tidak terlalu umum di seluruh dokumen.
hasil_tfidf <- token %>%
count(id, kata, name = "n") %>%
ungroup() %>%
bind_tf_idf(kata, id, n)
top_tfidf <- hasil_tfidf %>%
group_by(id) %>%
slice_max(tf_idf, n = 3, with_ties = FALSE) %>%
ungroup()
kable(top_tfidf, digits = 4)| id | kata | n | tf | idf | tf_idf |
|---|---|---|---|---|---|
| 1 | cepat | 1 | 0.2000 | 1.3863 | 0.2773 |
| 1 | baik | 1 | 0.2000 | 0.9808 | 0.1962 |
| 1 | pelanggan | 1 | 0.2000 | 0.9808 | 0.1962 |
| 2 | buruk | 1 | 0.2000 | 2.0794 | 0.4159 |
| 2 | respon | 1 | 0.2000 | 1.3863 | 0.2773 |
| 2 | lambat | 1 | 0.2000 | 0.9808 | 0.1962 |
| 3 | bagus | 1 | 0.2500 | 1.3863 | 0.3466 |
| 3 | lambat | 1 | 0.2500 | 0.9808 | 0.2452 |
| 3 | barang | 1 | 0.2500 | 0.6931 | 0.1733 |
| 4 | puas | 1 | 0.3333 | 2.0794 | 0.6931 |
| 4 | layanan | 1 | 0.3333 | 0.6931 | 0.2310 |
| 4 | pengiriman | 1 | 0.3333 | 0.6931 | 0.2310 |
| 5 | kurang | 1 | 0.1667 | 2.0794 | 0.3466 |
| 5 | harga | 1 | 0.1667 | 1.3863 | 0.2310 |
| 5 | murah | 1 | 0.1667 | 1.3863 | 0.2310 |
| 6 | harga | 1 | 0.2000 | 1.3863 | 0.2773 |
| 6 | murah | 1 | 0.2000 | 1.3863 | 0.2773 |
| 6 | baik | 1 | 0.2000 | 0.9808 | 0.1962 |
| 7 | ramah | 1 | 0.2000 | 2.0794 | 0.4159 |
| 7 | cepat | 1 | 0.2000 | 1.3863 | 0.2773 |
| 7 | respon | 1 | 0.2000 | 1.3863 | 0.2773 |
| 8 | bagus | 1 | 0.2000 | 1.3863 | 0.2773 |
| 8 | kualitas | 1 | 0.2000 | 0.9808 | 0.1962 |
| 8 | lambat | 1 | 0.2000 | 0.9808 | 0.1962 |
ggplot(
top_tfidf,
aes(
x = tf_idf,
y = reorder_within(kata, tf_idf, id),
fill = factor(id)
)
) +
geom_col(show.legend = FALSE) +
facet_wrap(~ id, scales = "free_y") +
scale_y_reordered() +
labs(
title = "Tiga Kata dengan TF-IDF Tertinggi pada Setiap Dokumen",
x = "TF-IDF",
y = "Kata"
) +
theme_minimal()TF-IDF pada dasarnya merupakan pembobotan, bukan penghapusan fitur. Seleksi terjadi ketika kita menerapkan batas skor atau memilih sejumlah fitur dengan skor tertinggi, seperti top-3 pada contoh.
Latihan 4: ubah batas minimum DF dari 2 menjadi 3. Kata apa saja yang masih dipertahankan? Jelaskan mengapa jumlah fiturnya berkurang.
P-value kecil memberikan bukti adanya hubungan, tetapi tidak otomatis menunjukkan bahwa hubungannya kuat atau penting secara praktis. Karena itu:
Metode filter univariat dapat melewatkan dua fitur yang lemah secara individual tetapi berguna ketika digunakan bersama. Hasil filter sebaiknya menjadi tahap awal, bukan satu-satunya dasar keputusan.
Jika ratusan fitur diuji sekaligus, beberapa p-value kecil dapat muncul hanya karena kebetulan. Salah satu pilihan sederhana adalah koreksi Benjamini-Hochberg melalui:
Jika tujuan akhirnya adalah prediksi, pemilihan fitur dilakukan pada data training. Fitur terpilih kemudian diterapkan tanpa dihitung ulang pada data testing.
set.seed(1381)
indeks_train <- sample(
seq_len(nrow(data)),
size = floor(0.80 * nrow(data))
)
data_train <- data[indeks_train, ]
data_test <- data[-indeks_train, ]
# Hitung kriteria seleksi hanya menggunakan data_train.Pada Pertemuan 6, aktivitas ini langsung digunakan untuk melanjutkan infografis proyek kelompok. Tidak ada tugas terpisah.
Ganti nama file, target, dan daftar fitur sesuai data masing-masing.
data_kelompok <- read.csv("data_kelompok.csv")
dim(data_kelompok)
names(data_kelompok)
str(data_kelompok)target <- "engagement"
fitur_numerik <- c("jumlah_like", "jumlah_komentar", "jumlah_kata")
hasil <- lapply(fitur_numerik, function(fitur) {
uji <- cor.test(
data_kelompok[[fitur]],
data_kelompok[[target]],
method = "spearman",
exact = FALSE
)
data.frame(
fitur = fitur,
korelasi = unname(uji$estimate),
p_value = uji$p.value
)
}) %>%
bind_rows() %>%
arrange(desc(abs(korelasi)))
hasil| Bagian | Informasi yang dicantumkan |
|---|---|
| Tujuan seleksi | Fitur apa yang ingin dipilih dan untuk tujuan apa |
| Metode | Chi-square, ANOVA, korelasi, DF, atau metode lain yang relevan |
| Kriteria | Batas p-value, top-k, threshold, atau minimum DF |
| Hasil | Fitur yang dipertahankan dan dihapus |
| Visual | Satu tabel atau grafik hasil pemeringkatan |
| Kesimpulan | Alasan singkat pemilihan fitur |
Diskusi kelas: Metode filtering apa yang paling sesuai untuk data kelompok kalian? Jelaskan kaitannya dengan tipe fitur dan tujuan analisis.
Alur berpikir seleksi peubah dapat diringkas sebagai berikut:
| Kondisi | Metode utama |
|---|---|
| Kategorik dengan target kategorik | Chi-square |
| Numerik dengan target kategorik | ANOVA |
| Numerik dengan target numerik | Korelasi |
| Teks tanpa target | Document Frequency |
| Pembobotan kata | TF-IDF dilanjutkan threshold atau top-k |
Seleksi fitur membantu menyederhanakan data, tetapi keputusan akhir tidak boleh hanya bergantung pada satu angka. Gunakan pengetahuan konteks, kualitas data, dan tujuan analisis sebagai pertimbangan utama.
chisq.test(), aov(),
cor.test(), dan p.adjust().