Pendahuluan

Dokumen ini menyajikan analisis content error antara data SE dan PES untuk variabel kategorik dan numerik, baik pada level nasional maupun wilayah tertentu. Untuk pengelolaan versi (version control) yang lebih baik, silakan melakukan clone repository dari Git BPS: https://git.bps.go.id/handy.geraldy/content-pes-se2026


1. Load Utilities & Packages

source("utils/01_utils_pairing.R")
source("utils/02_utils_content_error.R")
source("utils/03_utils_export.R")

pacman::p_load(readxl, rio)

Keterangan Utilities:

01_utils_pairing.R

berisi fungsi untuk:
- melakukan pairing unit analisis (usaha) antara data Pairs, SE, dan PES - membersihkan missing value hasil matching
- mengonversi variabel numerik menjadi kategorik (binary)
- menghasilkan dataset siap tabulasi content error

attach_se_pes = function(pair, se, pes, dropna = TRUE) {
  
  # Standarisasi nama kolom nilai
  se = se %>%
    rename(
      id_se  = 1,
      var_se = 2
    )
  
  pes = pes %>%
    rename(
      id_pes  = 1,
      var_pes = 2
    )
  
  # Matching pairs dengan SE dan PES
  out = pair %>%
    left_join(se,  by = "id_se") %>%
    left_join(pes, by = "id_pes")
  
  # Drop observasi tanpa nilai di SE dan PES
  if (dropna) {
    out = out %>%
      filter(!(is.na(var_se) & is.na(var_pes)))
  }
  
  out
}

numeric_to_binary = function(df, threshold) {
  
  df %>%
    mutate(
      growth = if_else(
        var_pes == 0,
        0,
        100 * (var_se - var_pes) / var_pes
      ),
      
      var_se  = as.integer(growth >= 0),
      var_pes = as.integer(
        (growth >= 0 & growth <= threshold) |
          (growth < -threshold)
      )
    ) %>%
    select(-growth)
}


build_content_table = function(pair, se, pes, group,
                          varnames = "var",
                          dropna = TRUE,
                          num_to_bin = NULL,
                          type = c("categoric", "numeric")) {
  # default categoric
  type = match.arg(type)
  # Validasi
  if (!is.null(num_to_bin) && type != "categoric") {
    stop("num_to_bin hanya boleh digunakan untuk type = 'categoric'")
  }
  
  # =======================================================
  # 1. Matching & cleaning dasar
  # =======================================================
  data = attach_se_pes(pair, se, pes, dropna)
  
  # =======================================================
  # 2a. Pendekatan numerik (regresi)
  # =======================================================
  if (type == 'numeric') {
    return(
      data %>% select(all_of(group), var_se, var_pes)
    )
  }
  
  # =======================================================
  # 2b. Konversi numerik → kategorik
  # =======================================================
  if (!is.null(num_to_bin)) {
    data = numeric_to_binary(data, num_to_bin)
  }
  
  # =======================================================
  # 3. Perlakuan NA untuk kategorik
  #    (NA = kategori eksplisit)
  # =======================================================
  data = data %>%
    mutate(
      var_se  = replace_na(as.character(var_se),  "KOSONG"),
      var_pes = replace_na(as.character(var_pes), "KOSONG")
    )
  
  # =======================================================
  # 4. Tabulasi frekuensi SE × PES
  # =======================================================
  # Gabungkan domain SE dan PES
  levels_all = union(
    unique(data$var_se),
    unique(data$var_pes)
  )
  
  # Pisahkan KOSONG
  has_kosong = "KOSONG" %in% levels_all
  
  levels_sorted = levels_all[levels_all != "KOSONG"]
  
  # Urutkan level selain KOSONG
  levels_sorted = if (all(!is.na(suppressWarnings(as.numeric(levels_sorted))))) {
    # jika numerik tersimpan sebagai character
    levels_sorted[order(as.numeric(levels_sorted))]
  } else {
    # jika benar-benar kategorik
    sort(levels_sorted)
  }
  
  # Tambahkan KOSONG di akhir (jika ada)
  if (has_kosong) {
    levels_sorted = c(levels_sorted, "KOSONG")
  }
  
  # Terapkan ke data
  data = data %>%
    mutate(
      var_se  = factor(var_se,  levels = levels_sorted),
      var_pes = factor(var_pes, levels = levels_sorted)
    )
  # Tabulasi frekuensi SE × PES
  data %>%
    # Hitung frekuensi pasangan SE–PES per group
    count(across(all_of(c(group, "var_se", "var_pes"))), name = "cnt") %>%
    
    # Lengkapi semua kombinasi (0,0), (0,1), (1,0), (1,1)
    complete(
      nesting(!!sym(group)),
      var_se,
      var_pes,
      fill = list(cnt = 0)
    ) %>%
    
    # Standarisasi nama variabel
    rename(
      !!paste0(varnames, "_se")  := var_se,
      !!paste0(varnames, "_pes") := var_pes
    )
}

02_utils_content_error.R

berisi fungsi untuk menghitung indikator content error berdasarkan hasil matching SE dan PES, meliputi:
- Tabulasi silang (cross-tab) SE vs PES
- Indikator dasar (NDR, IOI) per kelas
- Indikator agregat (AIOI, GDR, ROA)
- Indikator numeric (MSE, RMSE, MAE, SMAPE, R2)

categoric_error = function(dataset, se_var, pes_var, group = NULL, freq_var = 'cnt') {
  
  # Standarisasi nama kolom frekuensi
  dataset = dataset %>% rename(Freq = {{freq_var}})
  
  # Default grouping nasional
  if (is.null(group)) {
    dataset = dataset %>% mutate(group = "Nasional")
    group = "group"
  }
  
  # =======================================================
  # 1. Cross-tab SE × PES
  # =======================================================
  ctab = dataset %>%
    group_by(across(all_of(c(group, se_var, pes_var)))) %>%
    summarise(Freq = sum(Freq), .groups = "drop") %>%
    pivot_wider(
      names_from  = all_of(pes_var),
      values_from = Freq,
      values_fill = 0
    )
  
  # =======================================================
  # 2. Komponen dasar
  # =======================================================
  
  # Total SE per kelas
  vrt = dataset %>%
    group_by(across(all_of(c(group, se_var)))) %>%
    summarise(vrt = sum(Freq), .groups = "drop")
  
  # Total PES per kelas
  hrz = dataset %>%
    group_by(across(all_of(c(group, pes_var)))) %>%
    summarise(hrz = sum(Freq), .groups = "drop") %>%
    rename(!!se_var := !!sym(pes_var))
  
  # Diagonal (SE == PES)
  dig = dataset %>%
    filter(.data[[se_var]] == .data[[pes_var]]) %>%
    group_by(across(all_of(c(group, se_var)))) %>%
    summarise(dig = sum(Freq), .groups = "drop")
  
  # =======================================================
  # 3. Indikator dasar per kelas
  # =======================================================
  basic = vrt %>%
    left_join(hrz, by = c(group, se_var)) %>%
    left_join(dig, by = c(group, se_var)) %>%
    replace_na(list(hrz = 0, dig = 0)) %>%
    group_by(across(all_of(group))) %>%
    mutate(
      n   = sum(vrt),
      vh  = vrt * hrz,
      NDR = 100 * (vrt - hrz) / n,
      IOI = 100 * (vrt + hrz - 2 * dig) /
        ((1 / n) * (vrt * (n - hrz) + hrz * (n - vrt)))
    ) %>%
    ungroup()
  
  # =======================================================
  # 4. Indikator agregat
  # =======================================================
  agg = basic %>%
    group_by(across(all_of(group))) %>%
    summarise(
      n      = first(n),
      dig    = sum(dig),
      vh     = sum(vh),
      AIOI = (n - dig) / (n - (1 / n) * vh) * 100,
      GDR    = (1 - (dig / n)) * 100,
      ROA    = dig / n * 100,
      .groups = "drop"
    )
  
  # Output
  list(
    ctab  = ctab,
    basic = basic,
    agg   = agg
  )
}

numeric_error = function(dataset, se_var, pes_var, group = NULL) {
  
  if (is.null(group)) {
    dataset = dataset %>% mutate(.group_tmp = "Nasional")
    group = ".group_tmp"
  }
  
  # -------------------------------------------------
  # 1. Statistik dasar (tanpa filter pairwise)
  # -------------------------------------------------
  base_stat = dataset %>%
    group_by(across(all_of(group))) %>%
    summarise(
      n_matched = n(),
      .groups = "drop"
    )
  
  # -------------------------------------------------
  # 2. Statistik PAIRWISE (SE & PES sama-sama tidak NA)
  # -------------------------------------------------
  pairwise_stat = dataset %>%
    filter(
      !is.na(.data[[se_var]]),
      !is.na(.data[[pes_var]])
    ) %>%
    group_by(across(all_of(group))) %>%
    summarise(
      n_valid = n(),
      
      Mean_SE  = mean(.data[[se_var]]),
      Mean_PES = mean(.data[[pes_var]]),
      
      MSE   = mse(.data[[se_var]], .data[[pes_var]]),
      RMSE  = rmse(.data[[se_var]], .data[[pes_var]]),
      MAE   = mae(.data[[se_var]], .data[[pes_var]]),
      SMAPE = smape(.data[[se_var]], .data[[pes_var]]),
      R2    = if_else(n_valid < 2, NA_real_,
                      R2_Score(.data[[se_var]], .data[[pes_var]])),
      
      .groups = "drop"
    )
  
  # -------------------------------------------------
  # 3. Join & finalisasi
  # -------------------------------------------------
  base_stat %>%
    left_join(pairwise_stat, by = group) %>%
    mutate(
      n_valid    = replace_na(n_valid, 0L),
      prop_valid = n_valid / n_matched
    ) %>% 
    relocate(prop_valid, .after = n_valid)
}

03_utils_export.R

berisi fungsi untuk mengekspor hasil analisis content error ST–PES ke dalam format Excel

library(dplyr)
library(openxlsx)

write_sheet = function(
    wb, sheet, title, data, start = 3,
    style_title, style_body
) {
  addWorksheet(wb, sheet)
  
  writeData(wb, sheet, title, startRow = 1)
  writeData(wb, sheet, data, startRow = start)
  
  addStyle(
    wb, sheet, style_title,
    rows = 1, cols = 1, gridExpand = TRUE
  )
  
  if (nrow(data) > 0) {
    addStyle(
      wb, sheet, style_body,
      rows = start:(start + nrow(data)),
      cols = 1:ncol(data),
      gridExpand = TRUE
    )
  }
}

write_categoric = function(wb, res, level, var, s1, s2) {
  
  write_sheet(
    wb,
    paste(level, "Tabulasi"),
    paste0("Tabel Tabulasi ", var, " tingkat ", level),
    res$ctab,
    style_title = s1,
    style_body  = s2
  )
  
  write_sheet(
    wb,
    paste(level, "Kelas"),
    paste0("Tabel Indikator NDR dan IOI untuk ", var, " tingkat ", level),
    res$basic,
    style_title = s1,
    style_body  = s2
  )
  
  write_sheet(
    wb,
    paste(level, "Agregat"),
    paste0("Tabel Indikator Agregat IOI, GDR, dan ROA untuk ", var, " tingkat ", level),
    res$agg,
    style_title = s1,
    style_body  = s2
  )
}

write_numeric = function(wb, res, level, var, s1, s2) {
  
  write_sheet(
    wb,
    level,
    paste0(
      "Tabel Indikator Numeric Error ",
      var, " tingkat ", level
    ),
    res,
    style_title = s1,
    style_body  = s2
  )
}

prep_basis_agg = function(basic, agg, kategori,
                          master_prov = NULL,
                          group_var = NULL,
                          national = FALSE) {
  
  df = basic %>%
    select(-c(vrt, hrz, dig, vh, n)) %>%
    left_join(agg, by = if (national) "group" else group_var) %>%
    relocate(n, .after = var_se) %>%
    left_join(kategori, by = c("var_se" = "kode"))
  
  if (!national) {
    df = df %>%
      left_join(master_prov, by = "kdprov") %>%
      mutate(Provinsi = paste0("[", .data[[group_var]], "] ", nmprov)) %>%
      select(!!group_var, Provinsi, label, n, NDR, IOI, AIOI, GDR, ROA)
  } else {
    df = df %>%
      mutate(Provinsi = "INDONESIA") %>%
      select(Provinsi, label, n, NDR, IOI, AIOI, GDR, ROA)
  }
  
  cols = c("NDR","IOI","AIOI","GDR","ROA")
  df[cols] = lapply(df[cols], round, 2)
  
  df
}

na_to_na_char = function(x) {
  ifelse(is.na(x), "N/A", x)
}

write_categoric_lampiran_block = function(
    wb, sheet, data, start_row,
    bold = FALSE,
    s_left, s_right,
    s_left_bold, s_right_bold
) {
  
  n = nrow(data)
  end_row = start_row + n - 1
  
  # =========================
  # 0. Tangani NA → "N/A"
  # =========================
  IOI  = ifelse(is.na(data$IOI),  "N/A", data$IOI)
  AIOI = ifelse(is.na(data$AIOI), "N/A", data$AIOI)
  
  # =========================
  # 1. Tulis kolom per-baris
  # =========================
  writeData(wb, sheet, data$label, startRow = start_row, startCol = 2, colNames = FALSE)
  writeData(wb, sheet, data$NDR,   startRow = start_row, startCol = 4, colNames = FALSE)
  writeData(wb, sheet, IOI,        startRow = start_row, startCol = 5, colNames = FALSE)
  
  # =========================
  # 2. Tulis kolom block
  # =========================
  writeData(wb, sheet, data$Provinsi[1], startRow = start_row, startCol = 1)
  writeData(wb, sheet, data$n[1],        startRow = start_row, startCol = 3)
  writeData(wb, sheet, AIOI[1],           startRow = start_row, startCol = 6)
  writeData(wb, sheet, data$GDR[1],       startRow = start_row, startCol = 7)
  writeData(wb, sheet, data$ROA[1],       startRow = start_row, startCol = 8)
  
  # =========================
  # 3. Merge per kolom
  # =========================
  for (cl in c(1, 3, 6, 7, 8)) {
    mergeCells(wb, sheet, cols = cl, rows = start_row:end_row)
  }
  
  # =========================
  # 4. Style
  # =========================
  addStyle(wb, sheet,
           if (bold) s_left_bold else s_left,
           rows = start_row:end_row, cols = 1:2,
           gridExpand = TRUE, stack = TRUE)
  
  addStyle(wb, sheet,
           if (bold) s_right_bold else s_right,
           rows = start_row:end_row, cols = 3:8,
           gridExpand = TRUE, stack = TRUE)
  
  end_row + 1
}

write_categoric_lampiran = function(
    wb,
    nasional, provinsi,
    kategori, master_prov,
    var, title
) {
  
  # =========================
  # Data preparation
  # =========================
  df_prov = prep_basis_agg(
    provinsi$basic, provinsi$agg,
    kategori, master_prov,
    group_var = "kdprov"
  )
  
  df_nas = prep_basis_agg(
    nasional$basic, nasional$agg,
    kategori, national = TRUE
  )
  
  list_prov = unique(df_prov$kdprov)
  
  # =========================
  # Sheet & styles
  # =========================
  sheet = "Lampiran"
  addWorksheet(wb, sheet)
  
  s_title = createStyle(textDecoration = "BOLD", wrapText = TRUE)
  s_header = createStyle(
    border = "TopBottomLeftRight",
    textDecoration = "BOLD",
    halign = "center",
    fgFill = "#D9D9D9"
  )
  s_left = createStyle(border = "TopBottomLeftRight", halign = "left", valign = "top", wrapText = TRUE)
  s_right = createStyle(border = "TopBottomLeftRight", halign = "right", valign = "top")
  s_left_bold = createStyle(border = "TopBottomLeftRight", halign = "left", valign = "top", wrapText = TRUE, textDecoration = "BOLD")
  s_right_bold = createStyle(border = "TopBottomLeftRight", halign = "right", valign = "top", textDecoration = "BOLD")
  
  # =========================
  # Title & header
  # =========================
  mergeCells(wb, sheet, cols = 1:8, rows = 1)
  writeData(wb, sheet, title, startRow = 1)
  addStyle(wb, sheet, s_title, rows = 1, cols = 1, gridExpand = TRUE)
  
  headers = c("PROVINSI","KATEGORI","n","NDR","IOI","AIOI","GDR","ROA")
  # Baris 3: nama kolom
  for (i in seq_along(headers)) {
    writeData(
      wb, sheet,
      headers[i],
      startRow = 3,
      startCol = i,
      colNames = FALSE
    )
  }
  
  # Baris 4: nomor kolom
  for (i in seq_along(headers)) {
    writeData(
      wb, sheet,
      paste0("(", i, ")"),
      startRow = 4,
      startCol = i,
      colNames = FALSE
    )
  }
  
  addStyle(wb, sheet, s_header, rows = 3:4, cols = 1:8, gridExpand = TRUE)
  
  # =========================
  # Provinsi blocks
  # =========================
  row = 5
  for (p in list_prov) {
    temp = df_prov %>%
      filter(kdprov == p) %>%
      select(-kdprov)
    
    row = write_categoric_lampiran_block(
      wb, sheet, temp, row,
      bold = FALSE,
      s_left, s_right, s_left_bold, s_right_bold
    )
  }
  
  # =========================
  # Nasional block
  # =========================
  write_categoric_lampiran_block(
    wb, sheet, df_nas, row,
    bold = TRUE,
    s_left, s_right, s_left_bold, s_right_bold
  )
  
  setColWidths(wb, sheet, 1:8, c(14,22,7,7,7,7,7,7))
}


export_categoric_error = function(
    nasional, provinsi,
    kategori, master_prov,
    var, folder = ""
) {
  
  wb = createWorkbook()
  
  s_title = createStyle(textDecoration = "BOLD")
  s_body  = createStyle(border = "TopBottomLeftRight")
  
  # =========================
  # Sheet utama
  # =========================
  write_categoric(wb, nasional, "Nasional", var, s_title, s_body)
  write_categoric(wb, provinsi, "Provinsi", var, s_title, s_body)
  
  # =========================
  # Lampiran
  # =========================
  write_categoric_lampiran(
    wb,
    nasional, provinsi,
    kategori, master_prov,
    var,
    title = paste0(
      "Lampiran Indikator Content Error ", var,
      " menurut Provinsi dan Kategori"
    )
  )
  
  # =========================
  # Save
  # =========================
  saveWorkbook(
    wb,
    paste0(folder,"/", Sys.Date(), " Content Error ", var, ".xlsx"),
    overwrite = TRUE
  )
}



export_numeric_error = function(
    nasional, provinsi, var, folder = ""
) {
  
  wb = createWorkbook()
  
  s_title = createStyle(textDecoration = "BOLD")
  s_body  = createStyle(border = "TopBottomLeftRight")
  
  write_numeric(wb, nasional, "Nasional", var, s_title, s_body)
  write_numeric(wb, provinsi, "Provinsi", var, s_title, s_body)
  
  saveWorkbook(
    wb,
    paste0(folder,"/", Sys.Date(), " Numeric Error ", var, ".xlsx"),
    overwrite = TRUE
  )
}

2. Parameter Umum

Sesuaikan dengan direktori masing-masing

PATH_PAIRS = "Data/2026-01-17 Data Pairs GB PES SE.xlsx"
PATH_SE    = "Data/GB CAPI L_20251111.xlsx"
PATH_PES   = "Data/GBPES L.xlsx"

GROUP_VAR  = "kdprov"
OUTPUT_DIR = "OUTPUT"

3. Load & Persiapan Data

3.1 Data Pairing SE–PES

Pastikan terdapat kolom id_pes dan id_se, kolom lain opsional.

pairs = read_excel(PATH_PAIRS, col_types = "text") %>%
transmute(
kdprov         = substr(idsubsls, 1, 2),
idsubsls,
id_pes,
id_se          = id_gb,
nama_usaha_pes,
nama_usaha_gb
)

head(pairs)
## # A tibble: 6 × 6
##   kdprov idsubsls         id_pes              id_se nama_usaha_pes nama_usaha_gb
##   <chr>  <chr>            <chr>               <chr> <chr>          <chr>        
## 1 35     3578190001000300 48fa8621-b309-4b5c… a8de… MONUMEN KAPAL… MONUMEN KAPA…
## 2 35     3578190001000300 09b3c467-7938-4869… 0ab1… HOTEL PLAZA P… HOTEL PLAZA …
## 3 35     3578190001000300 a9709673-1610-4979… e9cc… inti lancar g… Inti lancar …
## 4 35     3578190001000300 a9709673-1610-4979… e9cc… Oriontama Jay… Oriontama ja…
## 5 35     3578190001000300 a9709673-1610-4979… e9cc… Sumber Arta L… Sumber Arta …
## 6 35     3578190001000300 e7732157-c8e8-4ed8… fa6d… HOLLYWOOD      HOLLYWOOD

3.2 Data SE dan PES

Buat kolom id_pes dan id_se

se_raw = read_excel(PATH_SE) %>%
mutate(id_se = paste0(`Id Assignment`, "-", index1))

pes_raw = read_excel(PATH_PES) %>%
mutate(id_pes = paste0(`Id Assignment`, "-", index1))

4. Analisis Variabel Kategorik

4.1 Pembentukan Variabel

Sesuaikan bagian ini dengan variabel yang akan dianalisis. Pada contoh berikut, variabel yang digunakan adalah kategori KBLI 2 digit, yang diperoleh dengan mengambil dua karakter pertama dari kode KBLI.

Output dari bagian ini berupa dua buah dataframe, yaitu se dan pes, yang masing-masing hanya memuat variabel identitas (id_se / id_pes) dan variabel hasil transformasi (var_se / var_pes), sehingga siap digunakan pada tahapan analisis selanjutnya.

se = se_raw %>%
transmute(
id_se,
var_se = substr(KBLI, 1, 2)
)

pes = pes_raw %>%
transmute(
id_pes,
var_pes = substr(KBLI, 1, 2)
)

4.2 Build Content Table

Pada tahap ini dilakukan pembentukan content table yang merepresentasikan tabulasi silang antara variabel pada data SE dan PES.

Fungsi build_content_table() menerima parameter padanan SE-PES (pairs), data SE dan PES yang telah disederhanakan strukturnya pada tahap sebelumnya. Parameter group digunakan untuk menentukan level agregasi analisis (misalnya provinsi), sedangkan parameter type = "categoric" menunjukkan bahwa variabel yang dianalisis bersifat kategorik.

content = build_content_table(
pairs,
se,
pes,
group = GROUP_VAR,
type  = "categoric"
)

head(content)
## # A tibble: 6 × 4
##   kdprov var_se var_pes   cnt
##   <chr>  <fct>  <fct>   <int>
## 1 31     10     10          1
## 2 31     10     14          0
## 3 31     10     18          0
## 4 31     10     25          0
## 5 31     10     28          0
## 6 31     10     32          0

4.3 Perhitungan Categorical Error

Pada tahap ini dilakukan perhitungan indikator categorical error berdasarkan content table yang telah dibangun sebelumnya. Perhitungan dilakukan menggunakan fungsi categoric_error(), yang menghitung tingkat kesesuaian dan ketidaksesuaian antara kategori variabel pada data SE dan PES.

a. Tingkat Nasional

Perhitungan pada tingkat nasional dilakukan dengan menggabungkan seluruh unit observasi tanpa pengelompokan wilayah. Hal ini dicapai dengan mengatur parameter group = NULL, sehingga fungsi akan menghitung indikator secara agregat nasional. Pada proses ini, dibentuk kolom cnt yang berisi frekuensi pasangan kategori SE–PES melalui parameter freq_var. Output yang dihasilkan berupa tabel ringkasan indikator categorical error nasional, yaitu crosstab, indikator per kategori (basic), dan indikator aggregat nasional (agg)

# Nasional
res_nas = categoric_error(
dataset = content,
se_var  = "var_se",
pes_var = "var_pes",
group   = NULL,
freq_var = "cnt"
)

b. Tingkat Wilayah (Provinsi)

Selain tingkat nasional, perhitungan juga dilakukan pada level wilayah untuk melihat variasi content error antar provinsi. Pada perhitungan ini, parameter group diisi dengan variabel pengelompokan wilayah (misalnya kode provinsi), sehingga indikator dihitung secara terpisah untuk setiap kelompok. Output dari bagian ini serupa dengan output di tingkat nasional, hanya saja dirinci menurut GROUP_VAR

# group (provinsi)
res_group = categoric_error(
content,
se_var = "var_se",
pes_var = "var_pes",
group = GROUP_VAR
)

4.4 Master Kategori & Wilayah

Untuk keperluan penyajian pada buku hasil analisis, kode kategori yang berasal dari kuesioner perlu dikonversi menjadi label kategori yang mudah dibaca. Oleh karena itu, pastikan tersedia master kategori yang memuat minimal dua variabel, yaitu kode dan label.

Pada bagian ini, master kategori dan master wilayah dibaca dari file referensi berikut.

PATH_KATEGORI = "Data/MASTER KBLI2020.xlsx"
PATH_MPROV    = "Data/mprov_25_1.xlsx"

kategori = read_excel(PATH_KATEGORI) %>%
filter(nchar(Kode) == 2) %>%
transmute(
kode  = Kode,
label = Judul
)

master_prov = read_excel(PATH_MPROV, col_types = "text")

4.5 Export Hasil Kategorik

Pada tahap ini, seluruh hasil perhitungan categorical error diekspor ke dalam format output yang siap digunakan untuk pelaporan dan analisis lanjutan. Proses ekspor dilakukan menggunakan fungsi export_categoric_error(), yang menggabungkan hasil perhitungan pada tingkat nasional dan provinsi dengan metadata pendukung (master kategori dan master wilayah).

VAR_LABEL = "KBLI 2 digit"

export_categoric_error(
nasional     = res_nas,
provinsi     = res_group,
kategori     = kategori,
master_prov  = master_prov,
var          = VAR_LABEL,
folder       = OUTPUT_DIR
)

5. Analisis Variabel Numerik

5.1 Pembentukan Variabel

Sesuaikan bagian ini dengan variabel yang akan dianalisis. Pada contoh berikut, variabel yang digunakan adalah kategori Jumlah Tenaga Kerja.

Output dari bagian ini berupa dua buah dataframe, yaitu se dan pes, yang masing-masing hanya memuat variabel identitas (id_se / id_pes) dan variabel hasil transformasi (var_se / var_pes), sehingga siap digunakan pada tahapan analisis selanjutnya.

se = se_raw %>%
transmute(
id_se,
var_se = `Jumlah Tenaga Kerja`
)

pes = pes_raw %>%
transmute(
id_pes,
var_pes = `Jumlah Tenaga Kerja`
)

5.2 Build Content Table

Pada tahap ini dilakukan pembentukan content table yang merepresentasikan tabulasi silang antara variabel pada data SE dan PES.

Fungsi build_content_table() menerima parameter padanan SE-PES (pairs), data SE dan PES yang telah disederhanakan strukturnya pada tahap sebelumnya. Parameter group digunakan untuk menentukan level agregasi analisis (misalnya provinsi), sedangkan parameter type = "numeric" menunjukkan bahwa variabel yang dianalisis bersifat kategorik.

content = build_content_table(
pairs,
se,
pes,
group = GROUP_VAR,
type  = "numeric"
)

5.3 Perhitungan Numeric Error

Pada tahap ini dilakukan perhitungan indikator numerical error berdasarkan content table yang telah dibangun sebelumnya. Perhitungan dilakukan menggunakan fungsi numeric_error(), yang menghitung tingkat kesesuaian dan ketidaksesuaian antara kategori variabel pada data SE dan PES.

a. Tingkat Nasional

Perhitungan pada tingkat nasional dilakukan dengan menggabungkan seluruh unit observasi tanpa pengelompokan wilayah. Hal ini dicapai dengan mengatur parameter group = NULL, sehingga fungsi akan menghitung indikator secara agregat nasional.

Output yang dihasilkan berupa tabel ringkasan indikator numerical error nasional.

# Nasional
res_nas = numeric_error(
dataset = content,
se_var = "var_se",
pes_var = "var_pes"
)

b. Tingkat Wilayah (Provinsi)

Selain tingkat nasional, perhitungan juga dilakukan pada level wilayah untuk melihat variasi content error antar provinsi. Pada perhitungan ini, parameter group diisi dengan variabel pengelompokan wilayah (misalnya kode provinsi), sehingga indikator dihitung secara terpisah untuk setiap kelompok. Output dari bagian ini serupa dengan output di tingkat nasional, hanya saja dirinci menurut GROUP_VAR

# group (provinsi)
res_group = numeric_error(
content,
se_var = "var_se",
pes_var = "var_pes",
group = GROUP_VAR
)

5.4 Export Hasil Numerik

Pada tahap ini, hasil perhitungan numerical error diekspor ke dalam format output yang siap digunakan untuk pelaporan dan analisis lanjutan. Proses ekspor dilakukan menggunakan fungsi export_numeric_error(), yang menggabungkan hasil perhitungan pada tingkat nasional dan provinsi.

VAR_LABEL = "Jumlah Tenaga Kerja"

export_numeric_error(
nasional = res_nas,
provinsi = res_group,
var      = VAR_LABEL,
folder  = OUTPUT_DIR
)