1 Ringkasan Eksekutif

Dokumen ini menyajikan analisis Survei Kepuasan Pengguna terhadap kinerja lulusan S2 Statistika Terapan FMIPA UNPAD (data tahun 2025). Fokus analisis mencakup:

  • Profil responden pengguna dan institusi
  • Distribusi penilaian pada setiap dimensi kompetensi
  • Skor rata-rata dan Top-2 Box (Baik + Sangat Baik)
  • Indeks kepuasan agregat serta kategorisasinya
  • Reliabilitas instrumen (Cronbach’s alpha)
  • Temuan prioritas berbasis data dan rekomendasi RTL

Catatan privasi: bila params$anonymize = TRUE, kolom identitas (mis. email/nama) tidak ditampilkan pada lampiran data.

2 1. Data dan Metodologi

2.1 1.1 Sumber data

Data dibaca dari berkas Excel:

Apabila path default tidak ditemukan, laporan akan mencoba membaca dari file alternatif di working directory.

2.2 1.2 Skala penilaian

Item kepuasan menggunakan kategori kualitatif:

  • Sangat baik, Baik, Cukup, Kurang

Untuk perhitungan indeks, kategori dipetakan ke skala numerik 1-4:

  • Kurang = 1
  • Cukup = 2
  • Baik = 3
  • Sangat baik = 4

3 2. Persiapan Data

pkgs <- c(
  "tidyverse","readxl","janitor","stringr","kableExtra",
  "DT","psych","scales","glue","forcats","ggrepel"
)
to_install <- pkgs[!pkgs %in% rownames(installed.packages())]
if(length(to_install) > 0) install.packages(to_install, repos = "https://cloud.r-project.org")
invisible(lapply(pkgs, library, character.only = TRUE))
resolve_excel_path <- function(p){
  if (file.exists(p)) return(p)
  candidates <- c(
    basename(p),
    "SurveyKepPengguna.xlsx",
    "SurveyKepPenggguna.xlsx"
  )
  hit <- candidates[file.exists(candidates)][1]
  if (!is.na(hit)) return(hit)
  stop("File Excel tidak ditemukan. Sesuaikan params$excel_path atau letakkan file di working directory.")
}

excel_path <- resolve_excel_path(params$excel_path)

raw <- readxl::read_excel(excel_path, sheet = params$sheet_name) |>
  janitor::clean_names()

tibble(
  n_respon = nrow(raw),
  n_kolom  = ncol(raw),
  file_aktif = excel_path
) |>
  kableExtra::kbl(caption = "Ringkasan ukuran data") |>
  kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover","condensed"))
Ringkasan ukuran data
n_respon n_kolom file_aktif
51 14 //2025/SurveyKepPenggguna.xlsx
id_cols <- c("timestamp","email_address","nama_penilai",
             "nama_staf_karyawan_lulusan_statistika_unpad_yang_dinilai")

item_cols <- raw |>
  select(where(is.character)) |>
  select(matches("^bagaimana_")) |>
  names()

if(length(item_cols) == 0) stop("Kolom item penilaian tidak ditemukan (pola '^bagaimana_').")

item_cols
[1] "bagaimana_kualitas_etika_lulusan_tersebut"                                 
[2] "bagaimana_tingkat_keahlian_statistika_yang_dimiliki_oleh_lulusan_tersebut" 
[3] "bagaimana_tingkat_penguasaan_bahasa_asing_oleh_lulusan_tersebut"           
[4] "bagaimana_tingkat_penguasaan_teknologi_informasi_oleh_lulusan_terkait"     
[5] "bagaimana_tingkat_kemampuan_berkomunikasi_dari_lulusan_tersebut"           
[6] "bagaimana_kemampuan_lulusan_dalam_bekerja_sama_dengan_rekan_rekan_kerjanya"
[7] "bagaimana_kemampuan_lulusan_tersebut_dalam_pengembangan_diri"              
std_text <- function(x){
  x <- as.character(x)
  x <- stringr::str_squish(x)
  x <- stringr::str_to_sentence(x)
  x
}

df <- raw |>
  mutate(across(all_of(item_cols), std_text))

likert_levels <- c("Kurang","Cukup","Baik","Sangat baik")
likert_scores <- c("Kurang" = 1, "Cukup" = 2, "Baik" = 3, "Sangat baik" = 4)

df <- df |>
  mutate(across(all_of(item_cols), ~ factor(.x, levels = likert_levels, ordered = TRUE))) |>
  mutate(across(all_of(item_cols), ~ unname(likert_scores[as.character(.x)]), .names = "{.col}_score"))

score_cols <- paste0(item_cols, "_score")

missing_tbl <- tibble(
  item = item_cols,
  missing_n = map_int(item_cols, ~ sum(is.na(df[[.x]]))),
  missing_pct = map_dbl(item_cols, ~ mean(is.na(df[[.x]])))
) |>
  mutate(item = str_to_sentence(str_replace_all(str_remove(item, "^bagaimana_"), "_", " ")),
         missing_pct = scales::percent(missing_pct, accuracy = 0.1)) |>
  arrange(desc(missing_n))

missing_tbl |>
  kableExtra::kbl(caption = "Jumlah missing per item", col.names = c("Item","Jumlah Missing","Persentase")) |>
  kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover"))
Jumlah missing per item
Item Jumlah Missing Persentase
Kualitas etika lulusan tersebut 0 0.0%
Tingkat keahlian statistika yang dimiliki oleh lulusan tersebut 0 0.0%
Tingkat penguasaan bahasa asing oleh lulusan tersebut 0 0.0%
Tingkat penguasaan teknologi informasi oleh lulusan terkait 0 0.0%
Tingkat kemampuan berkomunikasi dari lulusan tersebut 0 0.0%
Kemampuan lulusan dalam bekerja sama dengan rekan rekan kerjanya 0 0.0%
Kemampuan lulusan tersebut dalam pengembangan diri 0 0.0%

4 3. Profil Responden dan Konteks Penilaian

profile_candidates <- c(
  "institusi_tempat_bekerja_penilai",
  "jabatan_penilai_boleh_tidak_diisi",
  "tahun_lulus_staf_yang_dinilai_dari_statistika_unpad_boleh_tidak_diisi"
)
profile_cols <- profile_candidates[profile_candidates %in% names(df)]

profile_summary <- function(data, col){
  data |>
    mutate(val = as.character(.data[[col]])) |>
    mutate(val = ifelse(is.na(val) | val == "", "(Tidak diisi)", val)) |>
    count(val, sort = TRUE) |>
    mutate(persen = scales::percent(n/sum(n), accuracy = 0.1)) |>
    rename(Kategori = val, Jumlah = n, Persentase = persen)
}

if(length(profile_cols) == 0){
  cat("Kolom profil responden tidak ditemukan pada data.")
} else {
  for(col in profile_cols){
    tab <- profile_summary(df, col)
    tbl_html <- tab |>
      kableExtra::kbl(caption = paste0("Distribusi: ", str_to_sentence(str_replace_all(col, "_", " ")))) |>
      kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover")) |>
      as.character()
    cat(tbl_html, "\n")
  }
}
Distribusi: Institusi tempat bekerja penilai
Kategori Jumlah Persentase
Bank Indonesia 3 5.9%
Tokopedia 3 5.9%
Jabar Digital Service 2 3.9%
PT Bank DBS Indonesia 2 3.9%
BAN 1 2.0%
BAPPEDA KAB. PANGAMDARAN 1 2.0%
BNI 1 2.0%
Badan Pusat Statistik 1 2.0%
Bank Woori Saudara 1 2.0%
Bappeda Kota Jambi 1 2.0%
Bappeda Padang Panjang 1 2.0%
DISKOP UKM BID. KELEMBAGAAN DAN PEMBERDAYAAN KOPERASI 1 2.0%
DPMD JABAR 1 2.0%
Dinas Komunikasi Informatika Statistik dan Persandian 1 2.0%
Dinas Komunikasi Informatika Statitik dan Persandian 1 2.0%
Dinas Koperasi dan Usaha Kecil dan Menengah Kabupaten Bandung 1 2.0%
Dinas Perdagangan dan Perindustrian Kabupaten Bandung 1 2.0%
Fazz Financial Group 1 2.0%
Frontier Market Research 1 2.0%
Idx partners 1 2.0%
JABAR DIGITAL SERVICE 1 2.0%
KG Media 1 2.0%
Kementerian Dalam Negeri 1 2.0%
Kementerian Pertanian 1 2.0%
MNC Channels 1 2.0%
Mandiri Tunas Finance 1 2.0%
PT Bank Central Asia, Tbk 1 2.0%
PT Naturalva Herba Indonesia 1 2.0%
PT Nipro Indonesia Jaya 1 2.0%
PT SUCOFINDO 1 2.0%
PT Saji Bersama Jaya (KINSEI) 1 2.0%
PT Sinbad Karya Perdagangan 1 2.0%
PT Sucofindo 1 2.0%
PT. BANK SYARIAH INDONESIA Tbk. 1 2.0%
PT. Bank Maybank Indonesia 1 2.0%
PT. Cipta kridatama 1 2.0%
PT. GoTo Aplikasi Karya Anak Bangsa 1 2.0%
PT. Propan Raya 1 2.0%
PT. Sendok Garpu Internasional 1 2.0%
Perwakilan BKKBN Provinsi Jawa Barat 1 2.0%
Pt. Cakrawala andalas televisi 1 2.0%
Pusat Analis Kebijakan Obat dan Makanan BPOM 1 2.0%
RCTI 1 2.0%
Riau Andalan Pulp & Paper 1 2.0%
Universitas Kuningan 1 2.0%
Distribusi: Jabatan penilai boleh tidak diisi
Kategori Jumlah Persentase
(Tidak diisi) 12 23.5%
Analis/Manajer 2 3.9%
Business Analytics 2 3.9%
Data Analytics Manager 2 3.9%
Kepala Bidang Statistik 2 3.9%
1 2.0%
Analis Kepegawaian Ahli Muda 1 2.0%
Analis kebijakan Ahli Muda 1 2.0%
Analisis Perencana Muda 1 2.0%
Analytics Manager 1 2.0%
CEO 1 2.0%
Data Analyst Lead 1 2.0%
Data Lead 1 2.0%
Data Product Manager 1 2.0%
Dekan 1 2.0%
Departement Head Research and Development 1 2.0%
Department Head QA/QC 1 2.0%
Fungsional Perencana Ahli Muda 1 2.0%
General Manager 1 2.0%
Geospatial Engineering Lead 1 2.0%
JFT Perencana Ahli Muda 1 2.0%
Junior Associate 1 2.0%
Kepala Bagian Pengembangan Jasa 1 2.0%
Kepala Bidang 1 2.0%
Kepala Bidang PPEPD 1 2.0%
Kepala Unit Branch Support 1 2.0%
Ketua 1 2.0%
Koordinator fungsi statistik produksi/Statistisi ahli muda 1 2.0%
MANAGER MARKETING CPRP 1 2.0%
Operational Contol Center Engineering 1 2.0%
Regional Manager Field Research 1 2.0%
Sekretaris 1 2.0%
Senior Manager, Data Analytics 1 2.0%
Sr consultant 1 2.0%
Subkoordinator DPLHP I 1 2.0%
Supervisor 1 2.0%
Distribusi: Tahun lulus staf yang dinilai dari statistika unpad boleh tidak diisi
Kategori Jumlah Persentase
2017 9 17.6%
2020 9 17.6%
2021 9 17.6%
(Tidak diisi) 8 15.7%
2018 7 13.7%
2019 7 13.7%
2016 2 3.9%

5 4. Hasil Survei Kepuasan Pengguna

5.1 4.1 Distribusi penilaian per dimensi

nice_item <- function(x){
  x |>
    str_replace("^bagaimana_", "") |>
    str_replace_all("_", " ") |>
    str_squish() |>
    str_to_sentence()
}

dist_all <- map_dfr(item_cols, function(col){
  df |>
    mutate(val = as.character(.data[[col]])) |>
    mutate(val = ifelse(is.na(val) | val=="", "(Missing)", val)) |>
    count(val) |>
    mutate(
      persen = n/sum(n),
      item = col
    )
}) |>
  mutate(
    item_label = nice_item(item),
    val = factor(val, levels = c("Kurang","Cukup","Baik","Sangat baik","(Missing)"), ordered = TRUE)
  )

palette_likert <- c(
  "Kurang" = "#d7263d",
  "Cukup" = "#ffb703",
  "Baik" = "#219ebc",
  "Sangat baik" = "#2a9d8f",
  "(Missing)" = "#adb5bd"
)

p_dist <- dist_all |>
  filter(val != "(Missing)") |>
  ggplot(aes(x = fct_reorder(item_label, persen, .fun = max), y = persen, fill = val)) +
  geom_col(position = "fill", color = "white", width = 0.8) +
  coord_flip() +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  scale_fill_manual(values = palette_likert) +
  labs(
    title = "Komposisi Penilaian per Dimensi",
    subtitle = "Proporsi kategori jawaban pada tiap dimensi kompetensi",
    x = NULL,
    y = "Persentase",
    fill = "Kategori"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    panel.grid.major.y = element_blank(),
    plot.title = element_text(face = "bold", color = "#0b3954"),
    legend.position = "bottom"
  )

p_dist

5.2 4.2 Skor rata-rata, Top-2 Box, dan prioritas dimensi

item_summary <- tibble(item = item_cols) |>
  mutate(
    item_label = nice_item(item),
    mean_score = map_dbl(item, ~ mean(df[[paste0(.x, "_score")]], na.rm = TRUE)),
    sd_score   = map_dbl(item, ~ sd(df[[paste0(.x, "_score")]], na.rm = TRUE)),
    n_valid    = map_int(item, ~ sum(!is.na(df[[paste0(.x, "_score")]]))),
    top2 = map_dbl(item, ~ {
      x <- df[[.x]]
      mean(x %in% c("Baik","Sangat baik"), na.rm = TRUE)
    }),
    low2 = map_dbl(item, ~ {
      x <- df[[.x]]
      mean(x %in% c("Kurang","Cukup"), na.rm = TRUE)
    })
  ) |>
  arrange(desc(mean_score))

item_summary |>
  mutate(
    `Rata-rata (1-4)` = round(mean_score, 3),
    SD = round(sd_score, 3),
    `Top-2 Box` = scales::percent(top2, accuracy = 0.1),
    `Low-2 Box` = scales::percent(low2, accuracy = 0.1)
  ) |>
  select(Dimensi = item_label, `N Valid` = n_valid, `Rata-rata (1-4)`, SD, `Top-2 Box`, `Low-2 Box`) |>
  kableExtra::kbl(caption = "Ringkasan skor per dimensi") |>
  kableExtra::kable_styling(full_width = TRUE, bootstrap_options = c("striped","hover","condensed"))
Ringkasan skor per dimensi
Dimensi N Valid Rata-rata (1-4) SD Top-2 Box Low-2 Box
Kualitas etika lulusan tersebut 51 3.804 0.448 98.0% 2.0%
Kemampuan lulusan dalam bekerja sama dengan rekan rekan kerjanya 51 3.608 0.532 98.0% 2.0%
Kemampuan lulusan tersebut dalam pengembangan diri 51 3.588 0.606 98.0% 2.0%
Tingkat keahlian statistika yang dimiliki oleh lulusan tersebut 51 3.471 0.703 92.2% 7.8%
Tingkat penguasaan teknologi informasi oleh lulusan terkait 51 3.471 0.612 98.0% 2.0%
Tingkat kemampuan berkomunikasi dari lulusan tersebut 51 3.392 0.666 94.1% 5.9%
Tingkat penguasaan bahasa asing oleh lulusan tersebut 51 2.961 0.692 82.4% 17.6%
item_summary |>
  mutate(item_label = fct_reorder(item_label, mean_score)) |>
  ggplot(aes(x = item_label, y = mean_score, fill = mean_score)) +
  geom_col(width = 0.75) +
  geom_text(aes(label = round(mean_score, 2)), hjust = -0.15, size = 3.5) +
  coord_flip() +
  scale_fill_gradient(low = "#8ecae6", high = "#023047") +
  scale_y_continuous(limits = c(1, 4.2), breaks = 1:4) +
  labs(
    title = "Rata-rata Skor Kepuasan per Dimensi",
    subtitle = "Skala 1-4 (semakin tinggi semakin baik)",
    x = NULL,
    y = "Rata-rata skor"
  ) +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none", plot.title = element_text(face = "bold", color = "#0b3954"))

5.3 4.3 Indeks Kepuasan Pengguna (Agregat)

Indeks Rata-rata
3.471
Kategori Mutu
Tinggi
Jumlah Responden
51
Statistik Indeks Kepuasan Pengguna
n_respon mean_index sd_index min_index max_index
51 3.471 0.461 1.429 4
ggplot(df_scores, aes(x = indeks_kepuasan)) +
  geom_histogram(bins = 12, fill = "#2a9d8f", color = "white", alpha = 0.95) +
  geom_vline(xintercept = overall$mean_index, linetype = "dashed", color = "#d62828", linewidth = 1) +
  annotate("text", x = overall$mean_index, y = Inf, label = paste0("Mean = ", round(overall$mean_index, 2)),
           vjust = 1.8, hjust = -0.05, color = "#d62828", size = 3.8) +
  scale_x_continuous(limits = c(1,4), breaks = 1:4) +
  labs(
    title = "Distribusi Indeks Kepuasan Pengguna",
    subtitle = "Garis putus-putus menunjukkan nilai rata-rata indeks",
    x = "Indeks Kepuasan (1-4)",
    y = "Jumlah responden"
  ) +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", color = "#0b3954"))

5.4 4.4 Peta Prioritas Perbaikan

mean_cut <- mean(item_summary$mean_score, na.rm = TRUE)
sd_cut <- mean(item_summary$sd_score, na.rm = TRUE)

item_summary |>
  mutate(
    prioritas = case_when(
      mean_score < mean_cut & sd_score > sd_cut ~ "Prioritas Tinggi",
      mean_score < mean_cut & sd_score <= sd_cut ~ "Perlu Penguatan",
      mean_score >= mean_cut & sd_score > sd_cut ~ "Jaga Konsistensi",
      TRUE ~ "Pertahankan Kinerja"
    )
  ) |>
  ggplot(aes(x = sd_score, y = mean_score, color = prioritas, label = item_label)) +
  geom_hline(yintercept = mean_cut, linetype = "dashed", color = "#6c757d") +
  geom_vline(xintercept = sd_cut, linetype = "dashed", color = "#6c757d") +
  geom_point(size = 3.8, alpha = 0.95) +
  ggrepel::geom_text_repel(size = 3.2, max.overlaps = 20) +
  scale_color_manual(values = c(
    "Prioritas Tinggi" = "#d62828",
    "Perlu Penguatan" = "#f77f00",
    "Jaga Konsistensi" = "#277da1",
    "Pertahankan Kinerja" = "#2a9d8f"
  )) +
  labs(
    title = "Peta Prioritas Dimensi",
    subtitle = "Sumbu Y: rata-rata skor, Sumbu X: variasi penilaian (SD)",
    x = "Standar deviasi",
    y = "Rata-rata skor",
    color = "Status"
  ) +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", color = "#0b3954"), legend.position = "bottom")

6 5. Reliabilitas Instrumen (Cronbach’s Alpha)

score_mat <- df |> select(all_of(score_cols))

if(ncol(score_mat) >= 2){
  a <- psych::alpha(score_mat)
  alpha_val <- a$total$raw_alpha

  interpretasi_alpha <- case_when(
    alpha_val >= 0.9 ~ "Sangat baik (excellent)",
    alpha_val >= 0.8 ~ "Baik (good)",
    alpha_val >= 0.7 ~ "Cukup (acceptable)",
    alpha_val >= 0.6 ~ "Marginal",
    TRUE ~ "Rendah"
  )

  tibble(
    `Jumlah item` = ncol(score_mat),
    `Cronbach's alpha` = round(alpha_val, 3),
    Interpretasi = interpretasi_alpha
  ) |>
    kableExtra::kbl(caption = "Reliabilitas internal instrumen") |>
    kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover"))

  a$alpha.drop |>
    as.data.frame() |>
    rownames_to_column("Item") |>
    mutate(Item = nice_item(str_remove(Item, "_score$"))) |>
    select(Item, raw_alpha) |>
    rename(`Alpha jika item dihapus` = raw_alpha) |>
    mutate(`Alpha jika item dihapus` = round(`Alpha jika item dihapus`, 3)) |>
    kableExtra::kbl(caption = "Diagnostik: alpha jika item dihapus") |>
    kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover"))
} else {
  cat("Tidak cukup item untuk mengukur reliabilitas.")
}
Diagnostik: alpha jika item dihapus
Item Alpha jika item dihapus
Kualitas etika lulusan tersebut 0.860
Tingkat keahlian statistika yang dimiliki oleh lulusan tersebut 0.853
Tingkat penguasaan bahasa asing oleh lulusan tersebut 0.858
Tingkat penguasaan teknologi informasi oleh lulusan terkait 0.853
Tingkat kemampuan berkomunikasi dari lulusan tersebut 0.848
Kemampuan lulusan dalam bekerja sama dengan rekan rekan kerjanya 0.861
Kemampuan lulusan tersebut dalam pengembangan diri 0.832

7 6. Temuan Kunci dan Rekomendasi

top_items <- item_summary |> slice_max(mean_score, n = min(3, nrow(item_summary)))
bottom_items <- item_summary |> slice_min(mean_score, n = min(3, nrow(item_summary)))

cat('<div class="callout"><strong>Temuan utama:</strong><br/>')

Temuan utama:

cat(glue::glue('- Rata-rata indeks kepuasan agregat: <strong>{round(overall$mean_index,3)}</strong> ({kategori_indeks}).<br/>'))
  • Rata-rata indeks kepuasan agregat: 3.471 (Tinggi).
cat(glue::glue('- Dimensi terkuat: <strong>{paste(top_items$item_label, collapse = "; ")}</strong>.<br/>'))
  • Dimensi terkuat: Kualitas etika lulusan tersebut; Kemampuan lulusan dalam bekerja sama dengan rekan rekan kerjanya; Kemampuan lulusan tersebut dalam pengembangan diri.
cat(glue::glue('- Dimensi prioritas perbaikan: <strong>{paste(bottom_items$item_label, collapse = "; ")}</strong>.<br/>'))
  • Dimensi prioritas perbaikan: Tingkat penguasaan bahasa asing oleh lulusan tersebut; Tingkat kemampuan berkomunikasi dari lulusan tersebut; Tingkat keahlian statistika yang dimiliki oleh lulusan tersebut; Tingkat penguasaan teknologi informasi oleh lulusan terkait.
cat('- Fokus perbaikan diarahkan pada dimensi skor rendah dengan proporsi Low-2 Box tertinggi.</div>')
  • Fokus perbaikan diarahkan pada dimensi skor rendah dengan proporsi Low-2 Box tertinggi.

7.1 6.1 Rekomendasi tindak lanjut (RTL)

  1. Penguatan kompetensi teknis berbasis kasus nyata: tingkatkan porsi studi kasus lintas sektor (pemerintahan, industri, kesehatan, keuangan), termasuk validasi data dan reproduksibilitas analisis.
  2. Penguatan komunikasi analitik: wajibkan latihan presentasi insight untuk audiens non-teknis agar hasil analisis lebih berdampak pada keputusan organisasi.
  3. Penguatan profesionalisme kerja: integrasikan etika data, manajemen proyek analitik, dan pembiasaan kolaborasi lintas fungsi.
  4. Monitoring mutu berkala: jadikan Top-2 Box, Low-2 Box, dan Indeks Kepuasan sebagai KPI semesteran untuk evaluasi kurikulum berbasis bukti.
  5. Closed-loop improvement: kaitkan hasil survei dengan rencana aksi prodi (siapa melakukan apa, target waktu, dan ukuran keberhasilan).

8 Penutup

Laporan ini dirancang untuk mendukung siklus peningkatan mutu berkelanjutan secara terukur. Hasil analisis menampilkan gambaran komprehensif mengenai tingkat kepuasan pengguna, kekuatan utama lulusan, serta area prioritas perbaikan yang dapat langsung ditindaklanjuti oleh program studi.