Abstract
Dosen Pengampu: Bayutama Isnaini, S.Si., M.Si.
Disusun oleh: Kelompok A
| Nama | NIM |
|---|---|
| Giovanny Daniel Lukas Ricarda | 21108062610042 |
| Juliano Parulian Wijanarko | 21108062610054 |
| Khaleeda Afnin Mumtazza | 21108062610058 |
| Moh. Khoirul Anam | 21108062610067 |
| Muhammad Akhtar Bimo Satrio Siswadi | 21108062610069 |
| Muhammad Fayyaz Ihtisham | 21108062610071 |
Di modul ini, kami membuat program simulasi untuk menentukan golongan Uang Kuliah Tunggal (UKT) menggunakan R. Program akan membaca data mahasiswa dari Excel, menghitung skor berdasarkan beberapa indikator ekonomi, menentukan golongan UKT, menampilkan ringkasan dan grafik, lalu menyimpan hasilnya ke file Excel.
Perlu diingat, program yang kami buat ini hanya untuk simulasi pembelajaran. Aturan skor dan nominal UKT di dalamnya kami tentukan sendiri, jadi hasilnya bukan keputusan resmi dari universitas.
Setelah mengikuti modul ini, kami berharap pembaca bisa:
mutate(), case_when(),
coalesce(), dan operasi aritmetika untuk mengolah
data.Kami menggunakan data contoh dari 5 mahasiswa dalam file Excel (.xlsx). File datanya bisa diunduh melalui tautan Google Drive ini.
Di program ini, kami menggunakan tiga paket R:
dplyr: memanipulasi dan meringkas data.readxl: membaca file Excel.writexl: menulis hasil ke file Excel.Jika paket belum terpasang, jalankan kode berikut satu kali di Console RStudio:
install.packages(c("dplyr", "readxl", "writexl"))
Kami menambahkan eval=FALSE supaya kode instalasi ini
tidak dijalankan setiap kali dokumen di-knit. Paket cukup
diinstal satu kali jika memang belum ada di laptop.
library(dplyr)
library(readxl)
library(writexl)
Fungsi library() digunakan untuk memanggil paket supaya
fungsi di dalamnya bisa kami pakai. Contohnya, read_excel()
berasal dari paket readxl, sedangkan mutate(),
case_when(), coalesce(), count(),
arrange(), dan left_join() berasal dari
dplyr.
Supaya kode bisa membaca data, kami menyiapkan file Excel bernama
data_ukt_5_mahasiswa.xlsx dengan nama sheet
Data. Simpan file itu di folder yang sama dengan
file R Markdown ini.
Kalau file Excel masih ada di folder lain, pindahkan atau salin dulu
ke folder proyek RStudio. Pilihan lainnya, ubah nilai
file_input di kode menjadi alamat file yang sesuai. Di
Windows, kami bisa menggunakan garis miring / atau garis
miring terbalik ganda \\, misalnya:
file_input <- "C:/Users/Nama/Documents/data_ukt_5_mahasiswa.xlsx"
Jangan menulis alamat Windows dengan satu garis miring terbalik saja,
karena karakter seperti \U bisa dibaca R sebagai kode
khusus dan memunculkan error.
Nama kolom di Excel perlu sama dengan nama yang dipakai di kode. Berikut kolom-kolom yang digunakan program kami:
| Nama kolom | Isi |
|---|---|
aset |
Nilai aset dalam rupiah |
penghasilan_ayah |
Penghasilan ayah dalam rupiah |
penghasilan_ibu |
Penghasilan ibu dalam rupiah |
penghasilan_wali |
Penghasilan wali dalam rupiah |
pbb |
Nilai PBB dalam rupiah sesuai periode yang dipakai dalam data |
kendaraan_roda2 |
Pajak kendaraan roda dua dalam rupiah |
kendaraan_roda4 |
Pajak kendaraan roda empat dalam rupiah |
listrik |
Tagihan listrik dalam rupiah |
air |
Tagihan air dalam rupiah |
rekening_bulan1 |
Nilai rekening bulan pertama |
rekening_bulan2 |
Nilai rekening bulan kedua |
rekening_bulan3 |
Nilai rekening bulan ketiga |
tanggungan |
Jumlah orang yang menjadi tanggungan |
Kami juga bisa menambahkan kolom identitas seperti nama
atau id_mahasiswa. Namun, kolom indikator di atas harus ada
karena akan dipanggil oleh kode. Untuk data yang kosong, perlakuannya
berbeda-beda tergantung bagian perhitungan, jadi sebaiknya cek lagi
datanya sebelum program dijalankan.
file_input <- "data_ukt_5_mahasiswa.xlsx"
df <- read_excel(file_input, sheet = "Data")
str(df)
## tibble [5 × 14] (S3: tbl_df/tbl/data.frame)
## $ id_mahasiswa : chr [1:5] "MHS001" "MHS002" "MHS003" "MHS004" ...
## $ aset : num [1:5] 5.0e+07 1.5e+08 3.5e+08 8.0e+08 2.0e+09
## $ penghasilan_ibu : num [1:5] 1500000 2500000 3000000 5000000 8000000
## $ penghasilan_ayah: num [1:5] 2.5e+06 4.5e+06 7.0e+06 1.2e+07 2.0e+07
## $ penghasilan_wali: num [1:5] 0 0 0 0 0
## $ pbb : num [1:5] 300000 750000 1500000 3000000 6000000
## $ kendaraan_roda2 : num [1:5] 1 2 2 3 2
## $ kendaraan_roda4 : num [1:5] 0 0 1 1 2
## $ tanggungan : num [1:5] 5 4 3 2 2
## $ listrik : num [1:5] 150000 250000 400000 650000 1200000
## $ air : num [1:5] 50000 100000 150000 250000 400000
## $ rekening_bulan1 : num [1:5] 8.0e+05 2.5e+06 6.0e+06 1.2e+07 3.0e+07
## $ rekening_bulan2 : num [1:5] 1.0e+06 3.0e+06 5.5e+06 1.5e+07 3.5e+07
## $ rekening_bulan3 : num [1:5] 9.0e+05 2.8e+06 6.5e+06 1.4e+07 3.2e+07
names(df)
## [1] "id_mahasiswa" "aset" "penghasilan_ibu" "penghasilan_ayah"
## [5] "penghasilan_wali" "pbb" "kendaraan_roda2" "kendaraan_roda4"
## [9] "tanggungan" "listrik" "air" "rekening_bulan1"
## [13] "rekening_bulan2" "rekening_bulan3"
Penjelasan kode:
file_input berisi nama atau alamat file Excel yang
ingin kami baca.read_excel(file_input, sheet = "Data") mengambil data
dari sheet Data, lalu menyimpannya ke objek
df.str(df) membantu kami melihat bentuk data, nama kolom,
dan tipe datanya.names(df) menampilkan daftar nama kolom yang ada.Dua pemeriksaan terakhir ini berguna untuk memastikan data sudah terbaca dengan benar. Kalau nama kolom di Excel tidak sama dengan yang ada di kode, R bisa menampilkan error seperti object not found. Kami juga perlu memastikan angka uang terbaca sebagai angka, bukan teks.
Di bagian ini, kami mulai menghitung skor untuk setiap indikator.
Fungsi mutate() dipakai untuk menambahkan kolom baru ke
data, sedangkan %>% (pipe) meneruskan hasil
dari satu proses ke proses berikutnya.
Kami menggunakan case_when() untuk menentukan skor
berdasarkan kondisi tertentu. R akan memeriksa kondisi dari atas ke
bawah dan memakai kondisi pertama yang cocok. Karena itu, urutan kondisi
dan batas nilainya perlu diperhatikan.
df_hasil <- df %>%
mutate(
# A. Skor aset
skor_aset = case_when(
is.na(aset) ~ NA_real_,
aset >= 1500000000 ~ 11,
aset <= 50000000 ~ 1,
aset <= 100000000 ~ 2,
aset <= 200000000 ~ 3,
aset <= 350000000 ~ 4,
TRUE ~ 5
),
# B. Skor penghasilan ayah, ibu, dan wali
penghasilan_ayah_0 = coalesce(penghasilan_ayah, 0),
penghasilan_ibu_0 = coalesce(penghasilan_ibu, 0),
penghasilan_wali_0 = coalesce(penghasilan_wali, 0),
total_penghasilan =
penghasilan_ayah_0 +
penghasilan_ibu_0 +
penghasilan_wali_0,
skor_penghasilan = case_when(
total_penghasilan <= 2000000 ~ 1,
total_penghasilan <= 3500000 ~ 2,
total_penghasilan <= 5000000 ~ 3,
total_penghasilan <= 7000000 ~ 4,
total_penghasilan <= 9000000 ~ 5,
total_penghasilan <= 12000000 ~ 6,
total_penghasilan <= 15000000 ~ 7,
total_penghasilan <= 20000000 ~ 8,
total_penghasilan <= 25000000 ~ 9,
TRUE ~ 10
),
# C. Skor PBB
skor_pbb = case_when(
is.na(pbb) ~ NA_real_,
pbb <= 100000 ~ 1,
pbb <= 250000 ~ 2,
pbb <= 500000 ~ 3,
pbb <= 1000000 ~ 4,
pbb <= 1500000 ~ 5,
pbb <= 2000000 ~ 6,
pbb <= 3000000 ~ 7,
pbb <= 4000000 ~ 8,
pbb <= 5000000 ~ 9,
TRUE ~ 10
),
# D. Skor pajak kendaraan
r2_0 = coalesce(kendaraan_roda2, 0),
r4_0 = coalesce(kendaraan_roda4, 0),
total_pajak = r2_0 + r4_0,
skor_kendaraan = case_when(
is.na(kendaraan_roda2) & is.na(kendaraan_roda4) ~ 5,
total_pajak < 1 ~ 1,
total_pajak < 100000 ~ 2,
total_pajak < 200000 ~ 3,
total_pajak < 300000 ~ 4,
total_pajak < 500000 ~ 5,
total_pajak < 750000 ~ 6,
total_pajak < 1000000 ~ 7,
total_pajak < 1500000 ~ 8,
total_pajak < 3000000 ~ 9,
TRUE ~ 10
),
# E. Skor listrik
skor_listrik = case_when(
is.na(listrik) ~ NA_real_,
listrik < 50000 ~ 1,
listrik < 100000 ~ 2,
listrik < 150000 ~ 3,
listrik < 200000 ~ 4,
listrik < 300000 ~ 5,
listrik < 400000 ~ 6,
listrik < 500000 ~ 7,
listrik < 750000 ~ 8,
listrik < 1000000 ~ 9,
TRUE ~ 10
),
# F. Skor air
skor_air = case_when(
is.na(air) ~ NA_real_,
air == 0 ~ 3,
air < 35000 ~ 1,
air < 45000 ~ 2,
air < 55000 ~ 3,
air < 65000 ~ 4,
air < 75000 ~ 5,
air < 90000 ~ 6,
air < 105000 ~ 7,
air < 130000 ~ 8,
air < 170000 ~ 9,
TRUE ~ 10
),
# G. Rata-rata rekening tiga bulan dan skornya
rata_rekening = if_else(
is.na(rekening_bulan1) |
is.na(rekening_bulan2) |
is.na(rekening_bulan3),
NA_real_,
(rekening_bulan1 + rekening_bulan2 + rekening_bulan3) / 3
),
skor_rekening = case_when(
is.na(rata_rekening) ~ NA_real_,
rata_rekening <= 500000 ~ 1,
rata_rekening <= 1000000 ~ 2,
rata_rekening <= 2000000 ~ 3,
rata_rekening <= 3500000 ~ 4,
rata_rekening <= 5000000 ~ 5,
rata_rekening <= 7500000 ~ 6,
rata_rekening <= 10000000 ~ 7,
rata_rekening <= 15000000 ~ 8,
rata_rekening <= 25000000 ~ 9,
TRUE ~ 10
),
# H. Total skor mentah
total_skor_mentah =
pmin(skor_aset, 5) +
skor_penghasilan +
skor_pbb +
skor_kendaraan +
skor_listrik +
skor_air +
skor_rekening,
# I. Pengurang tanggungan
pengurang_tanggungan = coalesce(tanggungan, 0) * 2,
skor_bersih = pmax(
total_skor_mentah - pengurang_tanggungan,
1
),
# J. Penentuan golongan UKT
golongan_ukt = case_when(
is.na(aset) ~ NA_real_,
aset >= 1500000000 ~ 11,
is.na(total_skor_mentah) ~ NA_real_,
skor_bersih <= 12 ~ 1,
skor_bersih <= 18 ~ 2,
skor_bersih <= 24 ~ 3,
skor_bersih <= 30 ~ 4,
skor_bersih <= 36 ~ 5,
skor_bersih <= 42 ~ 6,
skor_bersih <= 48 ~ 7,
skor_bersih <= 54 ~ 8,
skor_bersih <= 60 ~ 9,
TRUE ~ 10
)
)
Di bagian ini, kami membagi nilai aset ke beberapa rentang
menggunakan case_when(). Sebagai contoh, aset sampai
Rp50.000.000 mendapat skor 1, sedangkan nilai aset yang lebih tinggi
masuk ke rentang skor berikutnya.
Beberapa bagian yang perlu kami pahami:
is.na(aset) mengecek apakah nilai aset kosong.NA_real_ digunakan untuk menandai nilai kosong yang
bertipe numerik.TRUE ~ 5 menjadi kondisi terakhir jika tidak ada
kondisi sebelumnya yang cocok.pmin(skor_aset, 5) membatasi skor aset yang ikut
dijumlahkan, sehingga nilainya maksimal 5.Catatan: dalam aturan simulasi yang kami gunakan, mahasiswa dengan aset sebesar Rp1.500.000.000 atau lebih langsung masuk golongan UKT 11. Karena itu, batas aset pada perhitungan skor dan penentuan golongan sudah dibuat konsisten.
Kami memakai coalesce(nilai, 0) untuk mengganti nilai
penghasilan yang kosong (NA) menjadi nol. Setelah itu,
penghasilan ayah, ibu, dan wali dijumlahkan menjadi
total_penghasilan.
Skor penghasilan ditentukan dari total tersebut. Misalnya, total sampai Rp2.000.000 mendapat skor 1, sedangkan total di atas Rp25.000.000 mendapat skor 10.
Ada catatan penting: nilai kosong yang diganti menjadi nol tidak otomatis berarti penghasilan sebenarnya nol. Ini adalah asumsi yang kami pakai dalam simulasi, jadi data yang kosong tetap sebaiknya diperiksa.
Pada bagian ini, kami memberi skor berdasarkan nilai PBB. Semakin tinggi rentang PBB, semakin tinggi skor yang diberikan dalam simulasi.
Berbeda dari data penghasilan, PBB yang kosong tidak kami ubah
menjadi nol. Baris is.na(pbb) ~ NA_real_ membuat nilai
kosong tetap kosong. Akibatnya, data yang belum lengkap bisa memengaruhi
hasil perhitungan.
Variabel r2_0 dan r4_0 menyimpan nilai
pajak kendaraan roda dua dan roda empat setelah nilai kosong diganti
nol. Lalu, total_pajak menjumlahkan kedua nilai
tersebut.
Kami juga membuat aturan khusus: jika kedua kolom kendaraan kosong, skornya langsung ditetapkan 5. Namun, jika hanya salah satu yang kosong, nilai kosong itu dihitung sebagai nol, lalu total pajak digunakan untuk menentukan skor.
Di sini, kami membagi tagihan listrik menjadi sepuluh tingkat skor.
Operator < artinya “kurang dari”. Jadi, kalau nilainya
tepat sama dengan batas tertentu, kondisi itu tidak terpenuhi dan R akan
mengecek kondisi berikutnya. Contohnya, tagihan tepat Rp100.000 tidak
masuk ke kondisi listrik < 100000.
Kalau nilai listrik kosong, skornya tetap NA.
Cara menghitung skor air mirip dengan skor listrik. Bedanya, kami
menambahkan kondisi khusus air == 0 ~ 3, yang berarti
tagihan air sebesar nol mendapat skor 3. Kondisi ini diletakkan lebih
awal supaya diperiksa sebelum rentang nilai yang lain.
Kalau datanya kosong, skornya tetap NA, bukan otomatis
menjadi nol.
Kami menghitung rata_rekening dengan rumus:
Rata-rata = (Bulan 1 + Bulan 2 + Bulan 3) / 3
Sebelum menghitung, if_else() mengecek apakah ada nilai
dari ketiga bulan yang kosong. Kalau minimal satu bulan kosong,
rata-ratanya dibuat NA_real_. Kalau semua bulan terisi, R
menghitung rata-ratanya, lalu nilai tersebut dipakai untuk menentukan
skor_rekening.
Variabel total_skor_mentah menjumlahkan tujuh komponen
berikut:
Fungsi pmin(skor_aset, 5) mengambil nilai yang lebih
kecil antara skor aset dan 5. Dengan cara ini, skor aset yang bernilai
11 tidak ikut membuat total skor menjadi terlalu besar. Jika salah satu
komponen masih NA, total skor juga bisa menjadi
NA.
Kami menggunakan coalesce(tanggungan, 0) untuk mengganti
data tanggungan yang kosong menjadi nol, lalu mengalikannya dengan 2.
Dalam aturan simulasi ini, setiap satu tanggungan mengurangi skor
sebanyak dua poin.
Selanjutnya,
pmax(total_skor_mentah - pengurang_tanggungan, 1)
memastikan skor bersih tidak kurang dari 1, meskipun hasil
pengurangannya lebih kecil dari itu.
Bagian ini menentukan golongan akhir mahasiswa berdasarkan kondisi
yang kami tulis di case_when():
Contohnya, skor bersih maksimal 12 masuk golongan 1, sedangkan skor 13–18 masuk golongan 2. Pola ini berlanjut sampai skor di atas 60 masuk golongan 10.
Urutan kondisi ini penting karena aturan aset sebesar Rp1.500.000.000 atau lebih diperiksa lebih dulu. Jadi, jika syarat itu terpenuhi, aturan golongan 11 langsung digunakan.
tabel_ukt <- data.frame(
golongan_ukt = 1:11,
nominal_ukt = c(
500000,
1000000,
2000000,
4000000,
6000000,
7500000,
10000000,
12500000,
15000000,
17500000,
20000000
)
)
tabel_ukt
## golongan_ukt nominal_ukt
## 1 1 500000
## 2 2 1000000
## 3 3 2000000
## 4 4 4000000
## 5 5 6000000
## 6 6 7500000
## 7 7 10000000
## 8 8 12500000
## 9 9 15000000
## 10 10 17500000
## 11 11 20000000
Dengan data.frame(), kami membuat tabel yang berisi dua
kolom:
golongan_ukt: nomor golongan 1 sampai 11.nominal_ukt: nominal UKT simulasi untuk setiap
golongan.Nominal UKT ini bisa kami ubah sesuai kebutuhan simulasi. Angka yang digunakan di modul ini bukan tarif resmi dari universitas mana pun.
df_hasil <- df_hasil %>%
left_join(tabel_ukt, by = "golongan_ukt") %>%
mutate(
nominal_rupiah = if_else(
is.na(nominal_ukt),
NA_character_,
paste0(
"Rp",
format(
nominal_ukt,
big.mark = ".",
decimal.mark = ",",
scientific = FALSE,
trim = TRUE
)
)
)
)
Kami memakai left_join() untuk menggabungkan
df_hasil dengan tabel_ukt berdasarkan kolom
golongan_ukt. Hasilnya, setiap mahasiswa akan mendapat
nominal UKT sesuai golongannya.
Setelah itu, kami membuat kolom nominal_rupiah supaya
angka UKT lebih mudah dibaca:
format() mengatur pemisah ribuan menggunakan
titik.paste0("Rp", ...) menambahkan awalan
Rp.if_else() mempertahankan nilai kosong jika
nominal_ukt tidak tersedia.Kolom nominal_ukt tetap berupa angka sehingga dapat
digunakan untuk perhitungan; nominal_rupiah adalah versi
teks untuk tampilan.
print(df_hasil)
## # A tibble: 5 × 35
## id_mahasiswa aset penghasilan_ibu penghasilan_ayah penghasilan_wali pbb
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 MHS001 5 e7 1500000 2500000 0 3 e5
## 2 MHS002 1.5e8 2500000 4500000 0 7.5e5
## 3 MHS003 3.5e8 3000000 7000000 0 1.5e6
## 4 MHS004 8 e8 5000000 12000000 0 3 e6
## 5 MHS005 2 e9 8000000 20000000 0 6 e6
## # ℹ 29 more variables: kendaraan_roda2 <dbl>, kendaraan_roda4 <dbl>,
## # tanggungan <dbl>, listrik <dbl>, air <dbl>, rekening_bulan1 <dbl>,
## # rekening_bulan2 <dbl>, rekening_bulan3 <dbl>, skor_aset <dbl>,
## # penghasilan_ayah_0 <dbl>, penghasilan_ibu_0 <dbl>,
## # penghasilan_wali_0 <dbl>, total_penghasilan <dbl>, skor_penghasilan <dbl>,
## # skor_pbb <dbl>, r2_0 <dbl>, r4_0 <dbl>, total_pajak <dbl>,
## # skor_kendaraan <dbl>, skor_listrik <dbl>, skor_air <dbl>, …
ringkasan_ukt <- df_hasil %>%
count(golongan_ukt, name = "jumlah_mahasiswa") %>%
arrange(golongan_ukt)
print(ringkasan_ukt)
## # A tibble: 5 × 2
## golongan_ukt jumlah_mahasiswa
## <dbl> <int>
## 1 1 1
## 2 3 1
## 3 5 1
## 4 7 1
## 5 11 1
Di bagian ini, kami menampilkan hasil dan membuat ringkasannya:
print(df_hasil) menampilkan data mahasiswa lengkap
dengan skor, golongan, dan nominal UKT.count(golongan_ukt, name = "jumlah_mahasiswa")
menghitung jumlah mahasiswa di setiap golongan.arrange(golongan_ukt) mengurutkan golongan dari yang
terkecil sampai terbesar.Kalau ada golongan yang kosong (NA), nilainya juga bisa
muncul di ringkasan. Ini membantu kami melihat apakah ada data yang
belum bisa ditentukan golongannya.
ringkasan_valid <- ringkasan_ukt %>%
filter(!is.na(golongan_ukt))
barplot(
height = ringkasan_valid$jumlah_mahasiswa,
names.arg = ringkasan_valid$golongan_ukt,
col = "steelblue",
xlab = "Golongan UKT",
ylab = "Jumlah mahasiswa",
main = "Sebaran Mahasiswa per Golongan UKT"
)
Sebelum membuat grafik, kami memakai
filter(!is.na(golongan_ukt)) untuk mengeluarkan data yang
golongannya kosong. Tanda ! berarti “bukan”, jadi
!is.na(golongan_ukt) artinya golongan tersebut tidak
kosong.
Pada fungsi barplot():
height mengatur tinggi batang berdasarkan jumlah
mahasiswa.names.arg menampilkan nomor golongan di sumbu
horizontal.xlab dan ylab memberi nama pada
sumbu.main menampilkan judul grafik.Grafik ini memudahkan kami melihat jumlah mahasiswa di tiap golongan. Karena data contoh hanya berisi lima mahasiswa, grafiknya tetap bisa dibuat, tetapi datanya belum cukup untuk mewakili kondisi mahasiswa secara umum.
file_output <- "hasil_akhir_ukt.xlsx"
write_xlsx(
list(
Hasil_UKT = df_hasil,
Ringkasan = ringkasan_ukt
),
path = file_output
)
cat(
"\nData berhasil diproses!\n",
"File hasil: ",
normalizePath(file_output, mustWork = FALSE),
"\n"
)
Kami memberi opsi eval=FALSE pada kode ini supaya file
Excel hasil tidak otomatis dibuat setiap kali modul di-knit.
Kalau ingin menghasilkan file Excel, jalankan kode ini di script R biasa
atau ubah opsi chunk menjadi eval=TRUE.
file_output berisi nama file hasil yang akan
dibuat.write_xlsx() menyimpan hasil ke file Excel dengan dua
sheet, yaitu Hasil_UKT dan Ringkasan.normalizePath() membantu menampilkan alamat file
hasil.cat() menampilkan pesan bahwa proses sudah selesai
beserta lokasi file.Dari program ini, kami menggabungkan beberapa langkah pengolahan data dalam satu alur, mulai dari membaca file Excel, menghitung skor setiap indikator, menentukan golongan UKT, menambahkan nominal UKT, membuat ringkasan dan grafik, sampai menyimpan hasil ke Excel.
Dengan membagi program menjadi beberapa bagian, kami jadi lebih mudah memahami alur kodenya dan mencari bagian yang perlu diperbaiki jika muncul error. Sekali lagi, hasil program ini hanya simulasi berdasarkan aturan yang kami tentukan, bukan penetapan UKT resmi dari universitas.