Dataset ini berisi informasi mengenai Profil Karyawan di sebuah perusahaan. Data ini mencakup berbagai atribut penting seperti identitas karyawan (ID dan Nama), informasi demografi (Usia dan Jenis Kelamin), detail pekerjaan (Departemen, Posisi, dan Masa Kerja), hingga catatan keuangan dan performa (Gaji Bulanan dan Skor Performa). Data ini digunakan sebagai bahan utama untuk menganalisis produktivitas dan kesejahteraan karyawan.
Audit data numerik adalah proses pemeriksaan kualitas dan karakteristik distribusi data angka. Dalam tahap ini, kita melihat nilai sentral (Mean, Median, Mode), tingkat penyebaran data (Std Dev, Variance), serta bentuk distribusi melalui Skewness (kemiringan) dan Kurtosis (keruncingan). Selain itu, dilakukan uji normalitas Shapiro-Wilk untuk melihat apakah data berdistribusi normal, serta deteksi Outliers menggunakan metode IQR untuk menemukan data yang nilainya ekstrem.
Fungsi: describe_numeric_upgrade dibuat untuk melakukan otomatisasi audit pada semua kolom numerik sekaligus.
Logika:
Fungsi memisahkan kolom angka menggunakan select(where(is.numeric)).
Dilakukan pembersihan NA sementara (clean_x) agar perhitungan statistik tidak error.
Dilakukan pengujian statistik satu per satu (Central Tendency, Dispersion, dan Shape).
Menghitung persentase data hilang (Missing Value) dan jumlah pencilan (Outliers).
Menggabungkan semua hasil ke dalam satu tabel ringkasan (dataframe).
Tabel audit di atas memberikan gambaran kesehatan data numerik kita. Kita bisa melihat kolom mana yang memiliki pencilan (Outliers) tinggi dan kolom mana yang datanya tidak terdistribusi normal. Informasi ini sangat berguna untuk menentukan apakah kita perlu melakukan transformasi data (seperti Log Transformation) atau pembersihan outlier sebelum masuk ke tahap analisis yang lebih dalam.
Audit data kategorikal bertujuan untuk memahami distribusi variabel non-numerik atau kualitatif. Berbeda dengan data angka, fokus utama di sini adalah pada Kardinalitas (jumlah nilai unik) dan Modus (nilai yang paling sering muncul). Proses ini sangat penting untuk mendeteksi apakah ada variasi kategori yang terlalu banyak (High Cardinality) atau adanya data yang hilang pada atribut kualitatif seperti Departemen atau Posisi.
Penjelasan Fungsi & Logika
Fungsi: describe_categorical_upgrade secara otomatis menyaring semua kolom yang bertipe karakter (is.character).
Logika:
Menghitung jumlah observasi total dan jumlah nilai unik (n_distinct) untuk melihat variasi data.
Menentukan Modus secara manual dengan mencari frekuensi tertinggi dari nilai yang sudah dibersihkan dari NA.
Menghitung nilai yang hilang (Missing Values) baik dalam jumlah absolut maupun persentase.
Menggabungkan hasilnya menjadi dataframe ringkas untuk kemudahan audit.
Melalui tabel profiling ini, kita bisa mengidentifikasi karakteristik dominan dari karyawan. Misalnya, melalui kolom Mode, kita tahu departemen mana yang paling banyak memiliki staf. Kolom Unique membantu kita melihat apakah ada kolom kategorikal yang seharusnya unik (seperti ID) atau yang bersifat klasifikasi. Jika persentase Missing Values tinggi pada variabel penting, maka perlu dilakukan tindakan pengisian data (imputation) atau penghapusan pada tahap cleaning selanjutnya.
Missing Value (Data Hilang) terjadi ketika tidak ada nilai yang tersimpan untuk variabel dalam observasi tertentu. Hal ini bisa disebabkan oleh kesalahan input atau sistem. Secara statistik, kita tidak bisa membiarkan data kosong karena akan menyebabkan bias atau error pada algoritma. Metode yang kita gunakan di sini adalah Imputasi:
Median Imputation: Untuk data numerik, mengisi nilai kosong dengan nilai tengah agar tidak terpengaruh outlier.
Mode Imputation: Untuk data kategorikal, mengisi nilai kosong dengan nilai yang paling sering muncul (Modus).
Imputasi Numerik: Menggunakan Median karena bersifat robust terhadap pencilan (outliers), sehingga menjaga stabilitas distribusi nilai.
Imputasi Kategorikal: Menggunakan Modus melalui fungsi kustom get_mode untuk mengisi kekosongan berdasarkan frekuensi kemunculan tertinggi.
Efisiensi Komputasi: Penerapan across(where(…)) menjamin standarisasi pengisian secara otomatis pada seluruh kolom sesuai tipe datanya.
Berdasarkan audit, variabel Employy_ID dan Gendeer memiliki tingkat kekosongan tertinggi. Langkah imputasi dipilih untuk mempertahankan volume observasi dataset. Hasil akhirnya, dataset df_cleaned telah mencapai tingkat kelengkapan 100% dan siap digunakan untuk analisis tahap lanjut.
Setelah dilakukan proses penanganan missing values dan penghapusan duplikat, berikut adalah tampilan 10 baris pertama dari dataset yang telah dibersihkan.
Visualisasi ini memastikan bahwa proses standardisasi kategori (seperti Level Pendidikan) telah berhasil menggabungkan label-label yang sebelumnya redundan.
Deduplikasi Data: Implementasi fungsi distinct() bertujuan untuk menjamin integritas data dengan mengeliminasi observasi yang identik secara keseluruhan (redundansi baris).
Standardisasi String: Penggunaan kombinasi tolower() dan trimws() berfungsi untuk menormalkan variasi penulisan teks (spasi liar dan perbedaan kapitalisasi) sebelum dilakukan pemetaan kategori menggunakan case_when().
Pengelompokan Logis: Logika pemetaan (misal: “S1” menjadi “Bachelor”) diterapkan untuk meminimalisir noise pada data kategorial, sehingga meningkatkan akurasi saat dilakukan analisis grup atau agregasi.
Melalui tahap ini, dataset telah berhasil divalidasi dan diseragamkan. Penghapusan redundansi dan standardisasi label kategori (Gender & Pendidikan) memastikan tidak ada penggandaan makna dalam satu variabel. Hasil visualisasi menunjukkan distribusi yang lebih bersih dan siap untuk diproses ke tahap analisis korelasi maupun pemodelan statistik tanpa kendala inkonsistensi label.
Tabel di bawah ini menampilkan hasil transformasi data pada kolom Department (standardisasi string) dan pembuatan fitur baru Job_Level_Encoded (mengubah teks kategori menjadi angka hirarki).
Standardisasi Konsistensi String: Proses pembersihan pada variabel Department menggunakan kombinasi tolower() dan trimws() dilakukan untuk mereduksi variasi input teks yang tidak seragam akibat kesalahan manusia (data entry error). Pemetaan ulang menggunakan case_when() menjamin pengelompokan departemen menjadi bersifat mutually exclusive.
Ordinal Label Encoding: Transformasi variabel kategorikal Job_Level menjadi komponen numerik Job_Level_Encoded dilakukan dengan memberikan bobot nilai berjenjang (1 hingga 5). Logika hirarki ini diterapkan karena variabel asal memiliki sifat ordinal, sehingga jarak antar tingkatan jabatan perlu dipertahankan demi memfasilitasi algoritma komputasi yang berbasis angka pada tahapan analisis selanjutnya.
Melalui tahapan Feature Engineering, inkonsistensi penulisan nama departemen telah berhasil dieliminasi sepenuhnya. Selain itu, restrukturisasi variabel Job_Level menjadi bentuk numerik berjenjang berhasil merepresentasikan struktur organisasi perusahaan secara matematis. Berdasarkan grafik distribusi interaktif, terlihat bahwa mayoritas komposisi karyawan berada pada tingkat jabatan. Fitur baru ini kini memiliki format data yang konsisten dan siap digunakan untuk pemodelan statistik parametrik maupun algoritma Machine Learning.
Tabel di bawah ini menampilkan daftar karyawan yang teridentifikasi memiliki nilai gaji di luar batas wajar statistik (outlier) berdasarkan metode Interquartile Range (IQR).
Metode Interquartile Range (IQR): Identifikasi pencilan pada variabel Monthly_Salary menggunakan metode pagar statistik Tukey (Tukey’s Fences). Logika komputasi didasarkan pada penentuan Kuartil 1 (persentil ke-25) dan Kuartil 3 (persentil ke-75) untuk menghitung rentang antar-kuartil (\(IQR = Q3 - Q1\)).
Penetapan Batas Ambang (Thresholding): Batas bawah (lower bound) ditentukan melalui formula \(Q1 - 1.5 \times IQR\), sedangkan batas atas (upper bound) melalui formula \(Q3 + 1.5 \times IQR\). Setiap data observasi yang nilainya berada di luar koridor batas ambang tersebut secara matematis diklasifikasikan sebagai outlier karena berada jauh dari distribusi normal pusat data.
Berdasarkan hasil audit menggunakan metode IQR, ditemukan sebanyak 9 karyawan yang memiliki karakteristik gaji ekstrem di luar jangkauan normal perusahaan.
Gaji ekstrem ini umumnya merepresentasikan posisi manajemen puncak (seperti Director atau C-Level) atau indikasi kesalahan input data (data entry error). Penemuan ini memberikan justifikasi kuat untuk melakukan penyaringan (filtering) data pada tahapan pembersihan berikutnya agar tidak mendistorsi nilai rata-rata kelompok dan menjaga keandalan uji statistik parametrik.
Tabel di bawah ini menampilkan 50 baris pertama dari dataset akhir (df_final) yang telah disterilkan dari observasi pencilan ekstrem.
Tabel di bawah ini meringkas perubahan metrik statistik utama sebelum dan sesudah penghapusan pencilan untuk melihat efektivitas tindakan pre-processing.
Metode Listwise Deletion (Trimming): Tindakan penanganan outlier pada variabel Monthly_Salary diaplikasikan menggunakan teknik eliminasi berbasis baris (filtering). Logika komputasi mengeksekusi subsetting data hanya pada observasi yang memenuhi kondisi konjungsi logis: nilai harus lebih besar atau sama dengan batas bawah (\(lower\_bound\)) DAN kurang dari atau sama dengan batas atas (\(upper\_bound\)).
Efek Penstabilan Varians (Variance Stabilization): Secara matematis, pembuangan nilai pencilan ekstrem berbanding lurus dengan penurunan drastis pada nilai varians (\(Salary\_variance\)) dan deviasi standar. Hal ini dikarenakan rumus varians sangat sensitif terhadap kuadrat jarak nilai ekstrem dari pusat data, sehingga hilangnya pencilan akan mengembalikan distribusi data mendekati asumsi normalitas.
Berdasarkan tabel Numerical Audit Comparison, proses treatment ini menyebabkan berkurangnya ukuran sampel dari [Isi Angka Total Data Original] menjadi [Isi Angka Total Data Cleaned] observasi. Meskipun terjadi pengurangan data, tindakan ini memberikan dampak positif yang signifikan pada kestabilan parameter statistik:
Nila rata-rata gaji berubah secara substansial menjadi lebih representatif bagi populasi karyawan secara umum.
Penurunan drastis pada Varians Gaji membuktikan bahwa deviasi antardata kini jauh lebih rapat dan konsisten.
Tabel di bawah ini menampilkan hasil transformasi Data Binning pada variabel numerik kontinu (Age, Monthly_Salary, dan Performance_Score) menjadi variabel kategorikal ordinal.
Metode Data Binning (Diskretisasi): Transformasi dari skala rasio/kontinu menjadi bentuk ordinal diaplikasikan menggunakan fungsi cut(). Logika matematisnya memecah interval numerik tunggal menjadi serangkaian interval tertutup-buka (\([a, b)\)) berdasarkan titik batas (breaks) yang telah dispesifikasikan secara teoretis.
Penanganan Nilai Sisa (Handling Boundary & NA): Parameter right = FALSE memastikan nilai tepat pada batas bawah masuk ke kategori atasnya, sementara parameter include.lowest = TRUE menjamin nilai minimum mutlak tetap terakomodasi. Penambahan tingkat Unknown bertindak sebagai penangkap anomali (fail-safe) guna mencegah hilangnya observasi data selama proses pemetaan.
Proses Binning Data berhasil menyederhanakan kompleksitas distribusi tiga variabel utama menjadi bentuk segmentasi yang siap dianalisis. Melalui visualisasi grafik batang interaktif, dapat didentifikasi bahwa mayoritas tenaga kerja perusahaan terpusat pada kategori [Sebutkan Kategori Terbanyak, misal: Moderate Performer]. Restrukturisasi ini sangat krusial untuk memfasilitasi analisis tabel kontingensi (Uji Chi-Square) serta pembuatan profil demografi karyawan (user profiling) guna mendukung pengambilan keputusan strategis di bidang manajemen talenta (Human Capital Analytics).
Tabel di bawah ini menampilkan hasil transformasi data numerik menggunakan pendekatan Z-Score Standardization dan Min-Max Normalization untuk menyamakan skala antarvariabel.
Z-Score Standardization (\(Z\)): Transformasi fitur Monthly_Salary, Performance_Score, dan Training_Hours dilakukan menggunakan fungsi scale(). Logika matematisnya berpusat pada pemetaan ulang nilai asli (\(x\)) menggunakan rumus \(Z = \frac{x - \mu}{\sigma}\), di mana \(\mu\) mewakili rata-rata populasi sampel dan \(\sigma\) adalah standar deviasi. Hasil akhir dari proses ini memaksa distribusi data memiliki nilai rata-rata (mean) tepat di angka 0 dan varians atau standar deviasi sebesar 1.
Min-Max Normalization: Konversi skala linear diterapkan pada variabel Monthly_Salary melalui fungsi kustom minmax_norm dengan rumus \(x_{norm} = \frac{x - x_{min}}{x_{max} - x_{min}}\). Transformasi ini memetakan seluruh rentang nilai asli ke dalam batasan interval tertutup \([0, 1]\), di mana nilai minimum absolut data akan menjadi 0 dan nilai maksimum absolut menjadi 1.
Tahap komparasi penskalaan fitur (Feature Scaling) ini berhasil menyelaraskan magnitudo (satuan ukur) antar-variabel yang semula timpang. Sebelum transformasi dilakukan, variabel Monthly_Salary yang bernilai jutaan secara matematis akan mendominasi variabel Training_Hours yang hanya bernilai puluhan dalam perhitungan matriks jarak.
Dengan penerapan Z-Score, data kini telah terbebas dari bias satuan ukur asli tanpa mengubah bentuk distribusi geometris aslinya. Sementara itu, kolom Salary_Normalized memberikan alternatif penskalaan boundaries \([0, 1]\) yang sangat ideal untuk persiapan pemodelan. Berdasarkan pratinjau tabel interaktif, seluruh data numerik penyusun dataset df_final kini berada pada level komparasi yang setara (homogen) dan siap diintegrasikan ke dalam algoritma pengklasteran (clustering) maupun analisis regresi multivariat.
Tabel di bawah ini menampilkan matriks koefisien Cramér’s V untuk mengukur kekuatan asosiasi atau hubungan timbal balik antar-variabel kategorikal di dalam dataset.
\[V = \sqrt{\frac{\chi^2}{n \times \min(k-1, r-1)}}\] Di mana \(\chi^2\) merupakan nilai statistik Chi-Square dari tabel kontingensi, \(n\) adalah total ukuran sampel observasi, \(r\) represents jumlah baris (rows), dan \(k\) represents jumlah kolom (columns).
Matriks Cramér’s V di atas memberikan gambaran komprehensif mengenai peta hubungan tersembunyi antar-variabel kategorial. Berdasarkan hasil perhitungan interaktif pada tabel kontingensi:
Variabel yang memiliki nilai diagonal bernilai 1.000 karena merepresentasikan korelasi sempurna variabel dengan dirinya sendiri.
Silakan lakukan analisis pada sel di luar diagonal. Jika ditemukan nilai koefisien \(> 0.35\), hal tersebut mengindikasikan adanya efek hubungan yang kuat secara praktis (practically significant). Sebagai contoh, jika koefisien antara Department dan Performance_Score_Category bernilai tinggi, hal ini membuktikan secara empiris bahwa penempatan divisi kerja memiliki pengaruh sektoral terhadap tingkat produktivitas karyawan.
Analisis korelasi non-parametrik ini sangat krusial sebagai fondasi awal untuk memilih fitur-fitur kategorial potensial sebelum dimasukkan ke dalam pemodelan klasifikasi (Predictive Analytics Management).
Tabel di bawah ini menampilkan kekuatan dan arah hubungan linear antar-variabel numerik asli menggunakan koefisien Korelasi Pearson.
Tabel di bawah ini menunjukkan nilai kovarians asli dari variabel-variabel numerik untuk melihat arah pergerakan bersama.
\[r = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum (x_i - \bar{x})^2 \sum (y_i - \bar{y})^2}}\]
Metode ini mengukur derajat asosiasi linear dengan parameter interval \([-1, 1]\). Nilai \(r = 1\) mengindikasikan korelasi positif sempurna, \(r = -1\) menyatakan korelasi negatif sempurna, dan \(r = 0\) menandakan ketiadaan hubungan linear.
\[Cov(X,Y) = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{n - 1}\]
Parameter ini digunakan untuk menentukan arah tren pergerakan simultan antar-dua variabel acak. Nilai kovarians bersifat scale-dependent (sangat tergantung pada besaran satuan unit ukur asli data), sehingga wajar apabila nilai pada variabel Monthly_Salary bernilai sangat besar (jutaan) karena mengikuti skala nominal Rupiah yang digunakan di dalam dataset asli.
Rangkaian analisis hubungan numerik ini memberikan kesimpulan penting mengenai pola data karyawan:
Analisis Matriks Statistik: Berdasarkan tabel matriks kovarians dan Pearson, nilai positif (di atas 0) pada hubungan antara Age (Usia) dan Monthly_Salary (Gaji Bulanan) menandakan bahwa kedua variabel ini bergerak searah. Artinya, peningkatan pada satu variabel cenderung diikuti oleh peningkatan variabel lainnya.
Konfirmasi Visual via Scatter Plot: Pola searah tersebut divalidasi secara grafis oleh visualisasi diagram pencar (Scatter Plot). Garis tren linear berwarna merah menunjukkan arah kemiringan ke kanan atas (positive slope). Tren ini mengindikasikan sebuah pola organisasi yang logis: semakin matang usia seorang karyawan, terdapat kecenderungan bahwa tingkat kompensasi atau gaji bulanan yang diterima juga bergerak meningkat secara linear.
Tahapan analisis ini berfokus pada teknik Feature Engineering untuk mengukur posisi relatif data individu terhadap populasi. Melalui transformasi T-Score, metrik Z-Score yang kompleks dikonversi ke dalam skala standardisasi baru dengan nilai rata-rata (mean) 50 dan standar deviasi 10 agar lebih intuitif saat dibaca oleh pihak manajemen. Selain itu, perhitungan nilai Persentil (Quantile) diaplikasikan untuk memetakan ambang batas (threshold) dan segmentasi kedudukan finansial karyawan secara berjenjang di dalam organisasi.
Transformasi T-Score: Standardisasi linear lanjutan dari nilai Z-Score yang ditranslasikan menggunakan formula matematis \(T = 50 + 10 \times Z\). Tindakan ini bertujuan untuk mengeliminasi nilai negatif dan desimal kecil pada Z-Score tanpa mengubah bentuk distribusi asli data (scale-preserving transformation), sehingga mempermudah pembacaan posisi nilai individu terhadap rata-rata populasi.
Analisis Kepadatan & Persentil: Density Plot mengestimasi fungsi kepadatan probabilitas variabel kontinu menggunakan metode Kernel Density Estimation (KDE). Penambahan garis batas vertikal membantu mengidentifikasi pemusatan massa data dan memisahkan area sebaran berdasarkan ukuran lokasi persentil kuantitatif.
Melalui pendekatan analisis posisi relatif ini, kita dapat memetakan struktur remunerasi karyawan secara mendalam:
Interpretasi T-Score: Pada tabel pratinjau, karyawan dengan nilai Salary_TScore di atas 50.000 mengindikasikan bahwa kompensasi finansialnya berada di atas rata-rata perusahaan. Sebaliknya, nilai di bawah 50.000 menunjukkan posisi di bawah rata-rata.
Interpretasi Density Plot: Grafik di sebelah kanan memperlihatkan bentuk kurva sebaran gaji. Puncak kurva yang tinggi menandakan area rentang nominal gaji yang paling banyak dimiliki oleh mayoritas karyawan. Garis putus-putus merah bertindak sebagai pembatas tengah (Median/P50), di mana separuh populasi berada di sebelah kiri garis (gaji rendah-menengah) dan separuh lainnya berada di sebelah kanan garis (gaji menengah-tinggi).
Berdasarkan seluruh rangkaian audit, pembersihan, dan transformasi data yang telah dilakukan pada dataset karyawan, analisis ini menghasilkan beberapa kesimpulan utama yang krusial bagi keandalan data dan pengambilan keputusan perusahaan:
Pertama, dari aspek kualitas dan integritas data, hasil pengujian menunjukkan bahwa dataset awal memiliki tingkat variabilitas yang sangat tinggi, khususnya pada komponen kompensasi finansial. Intervensi menggunakan metode Interquartile Range (IQR) berhasil mengisolasi sejumlah pencilan (outlier) secara objektif. Hasil penapisan ini membuktikan bahwa tanpa proses pembersihan yang ketat, keberadaan data ekstrem tersebut akan mendistorsi nilai rata-rata industri dan menghasilkan estimasi yang bias jika dipaksakan masuk ke dalam pengujian statistik parametrik ataupun pemodelan prediktif.
Kedua, dari aspek karakteristik demografi dan struktur internal
organisasi, analisis kepadatan (Kernel Density Estimation)
mengonfirmasi adanya ketimpangan distribusi pendapatan yang bersifat
positive-skewed. Hasil ini mengindikasikan bahwa struktur
organisasi perusahaan masih bersifat piramida sehat, di mana mayoritas
mutlak tenaga kerja berada pada klaster staf dengan rentang pendapatan
menengah ke bawah, sementara alokasi anggaran besar terkonsentrasi
secara eksklusif pada segmen manajemen puncak (C-Level dan
Director). Dokumentasi visual interaktif menggunakan
plotly berhasil memetakan batas ambang atas ini secara
transparan bagi pihak manajemen.
Ketiga, melalui pemetaan matriks korelasi Pearson dan koefisien Cramér’s V, hasil analisis berhasil membuktikan adanya pola hubungan linier yang signifikan antar-variabel numerik, seperti relevansi masa kerja (tenure) terhadap eskalasi pendapatan. Di sisi lain, variabel kategorikal seperti departemen dan peran spesifik karyawan terbukti memiliki kekuatan asosiasi yang kuat terhadap penempatan kelas karyawan. Pola-pola hubungan yang berhasil dipetakan ini memberikan indikator awal (feature selection) yang sangat valid mengenai variabel apa saja yang paling berpengaruh di dalam perusahaan.
---
title: "Assignment Week 11"
output:
flexdashboard::flex_dashboard:
vertical_layout: scroll
theme: yeti
source_code: embed
---
```{r setup, include=FALSE}
packages <- c(
"flexdashboard",
"tidyverse",
"highcharter",
"viridis",
"DT",
"gapminder",
"jsonlite"
)
installed <- packages %in% rownames(installed.packages())
if (any(!installed)) {
install.packages(packages[!installed])
}
# Load library
library(flexdashboard)
library(tidyverse)
library(highcharter)
library(viridis)
library(DT)
library(gapminder)
library(jsonlite)
```
<style>
/* 1. Kustomisasi Font & Background Global */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
background-color: #f8f9fa !important;
}
/* 2. Merapikan Navigasi Menu Atas (Navbar) */
.navbar-inverse {
background-color: #2c3e50 !important;
border-color: #2c3e50 !important;
}
.navbar-inverse .navbar-nav > li > a {
color: #ecf0f1 !important;
font-weight: 500;
}
.navbar-inverse .navbar-nav > .active > a {
background-color: #3498db !important;
color: white !important;
}
/* 3. Estetika Kotak Panel Dashboard (Cards) */
.chart-wrapper {
background: #ffffff !important;
border: 1px solid #e2e8f0 !important;
border-radius: 8px !important;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03) !important;
margin-bottom: 20px !important;
padding: 10px;
}
/* 4. Kustomisasi Judul Sub-Bab (Panel Header) */
.chart-title {
font-size: 15px !important;
font-weight: 600 !important;
color: #2c3e50 !important;
border-bottom: 2px solid #3498db !important;
padding-bottom: 8px !important;
margin-bottom: 12px !important;
}
/* 5. Styling Interaktif untuk Tabel DT (DataTables) */
.dataTables_wrapper {
padding: 8px !important;
}
table.dataTable hthead th {
background-color: #f1f5f9 !important;
color: #334155 !important;
font-weight: 600 !important;
border-bottom: 2px solid #cbd5e1 !important;
}
table.dataTable tbody tr:hover {
background-color: #f8fafc !important;
transition: background-color 0.2s ease;
}
/* 6. Efek Desain Teks Narasi / Interpretasi */
p {
font-size: 14px !important;
line-height: 1.6 !important;
color: #4a5568 !important;
text-align: justify;
}
</style>
Author {data-orientation=rows}
=======================================================================
```{r}
library(htmltools)
tags$div(
# Load library ikon FontAwesome secara remote (CDN)
tags$head(
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css")
),
tags$style(HTML("
.author-section {
display: flex;
justify-content: center;
align-items: center;
height: auto;
padding: 60px 20px;
background: #f8fafc;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.author-card {
background: white;
width: 600px;
display: flex;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 10px 25px rgba(148, 163, 184, 0.15);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Efek hover melayang pada card */
.author-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 35px rgba(148, 163, 184, 0.25);
}
.card-left {
background: linear-gradient(135deg, #1e293b 0%, #2c3e50 100%);
padding: 45px 20px;
width: 42%;
display: flex;
flex-direction: column;
align-items: center;
color: white;
text-align: center;
}
.profile-img {
width: 150px;
height: 190px;
border-radius: 12px;
border: 8px solid #2c3e50;
object-fit: cover;
object-position: top center;
margin-bottom: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
transition: transform 0.3s ease;
}
.author-card:hover .profile-img {
transform: scale(1.03);
}
.role-text {
font-size: 13px;
letter-spacing: 1.5px;
text-transform: uppercase;
font-weight: 600;
color: #38bdf8;
margin-bottom: 4px;
}
.univ-text {
font-size: 11px;
color: #94a3b8;
font-weight: 500;
}
.card-right {
padding: 45px;
width: 58%;
display: flex;
flex-direction: column;
justify-content: center;
}
.author-name {
font-size: 26px;
font-weight: 700;
color: #1e293b;
margin-bottom: 4px;
line-height: 1.2;
}
.author-nim {
font-size: 14px;
font-weight: 500;
color: #64748b;
margin-bottom: 24px;
}
.skill-badges {
margin-bottom: 28px;
}
.skill-tag {
display: inline-block;
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
padding: 6px 14px;
border-radius: 6px;
font-size: 11px;
font-weight: 600;
margin-right: 6px;
margin-bottom: 6px;
box-shadow: 0 2px 4px rgba(52, 152, 219, 0.2);
}
.contact-list {
border-top: 1px solid #f1f5f9;
padding-top: 24px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.contact-item {
text-decoration: none;
color: #475569;
font-size: 13px;
font-weight: 500;
display: flex;
align-items: center;
gap: 8px;
transition: all 0.2s ease;
}
.contact-item i {
font-size: 14px;
color: #64748b;
transition: color 0.2s ease;
}
/* Efek hover warna ikon & teks tombol */
.contact-item:hover {
color: #3498db;
text-decoration: none;
transform: translateX(2px);
}
.contact-item:hover i {
color: #3498db;
}
")),
tags$div(class = "author-section",
tags$div(class = "author-card",
# SISI KIRI (INFO UTAMA)
tags$div(class = "card-left",
tags$img(src = "https://raw.githubusercontent.com/chandra240205-sudo/Chandra3/main/Ganteng.jpg", class = "profile-img"),
tags$p(class = "role-text", "Data Science"),
tags$p(class = "univ-text", "ITSB - 2026")
),
# SISI KANAN (DETAIL & KONTAK)
tags$div(class = "card-right",
tags$div(class = "author-name", "Chandra Rizal Alamsyah"),
tags$div(class = "author-nim", "NIM: 52250068"),
tags$div(class = "skill-badges",
tags$span(class = "skill-tag", "R Programming"),
tags$span(class = "skill-tag", "Statistik"),
tags$span(class = "skill-tag", "Data Cleaning")
),
# DAFTAR KONTAK DENGAN IKON FONTAWESOME
tags$div(class = "contact-list",
tags$a(href = "https://github.com/chandra240205-sudo", target = "_blank", class = "contact-item",
tags$i(class = "fa-brands fa-github"), "GitHub"
),
tags$a(href = "https://www.linkedin.com/in/chandra-rizal-alamsyah-147549407", target = "_blank", class = "contact-item",
tags$i(class = "fa-brands fa-linkedin"), "LinkedIn"
),
tags$a(href = "mailto:chandra240205@gmail.com", class = "contact-item",
tags$i(class = "fa-solid fa-envelope"), "Email"
),
tags$a(href = "https://www.instagram.com/chandra.rizall", target = "_blank", class = "contact-item",
tags$i(class = "fa-brands fa-instagram"), "Instagram"
)
)
)
)
)
)
```
Dataset {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **Deskripsi Proyek & Metadata Dataset**
Dataset ini berisi informasi mengenai **Profil Karyawan** di sebuah perusahaan. Data ini mencakup berbagai atribut penting seperti identitas karyawan (ID dan Nama), informasi demografi (Usia dan Jenis Kelamin), detail pekerjaan (Departemen, Posisi, dan Masa Kerja), hingga catatan keuangan dan performa (Gaji Bulanan dan Skor Performa). Data ini digunakan sebagai bahan utama untuk menganalisis produktivitas dan kesejahteraan karyawan.
Row
-----------------------------------------------------------------------
### **Pratinjau Dataset Karyawan (Raw Data)**
```{r}
# 1. Load Library
library(dplyr)
library(DT)
library(htmltools)
# 2. Baca Data
df <- readr::read_csv(
"employee_raw_dataset.csv",
show_col_types = FALSE
) %>%
# Hapus data ganda berdasarkan ID Karyawan
dplyr::distinct(Employee_ID, .keep_all = TRUE)
# 3. Tampilkan Data
df_display <- df %>%
head(50)
datatable(
df_display,
options = list(scrollX = TRUE, pageLength = 10),
caption = htmltools::tags$caption(
style = 'caption-side: bottom; text-align: center;',
'Table: ', htmltools::em('Tampilan Awal Dataset Karyawan (Raw Data).')
)
)
```
AUDIT DATA {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **Audit Distribusi Variabel Numerik**
Audit data numerik adalah proses pemeriksaan kualitas dan karakteristik distribusi data angka. Dalam tahap ini, kita melihat nilai sentral (Mean, Median, Mode), tingkat penyebaran data (Std Dev, Variance), serta bentuk distribusi melalui Skewness (kemiringan) dan Kurtosis (keruncingan). Selain itu, dilakukan uji normalitas Shapiro-Wilk untuk melihat apakah data berdistribusi normal, serta deteksi Outliers menggunakan metode IQR untuk menemukan data yang nilainya ekstrem.
Row
-----------------------------------------------------------------------
### **Penjelasan Fungsi & Logika**
* Fungsi: describe_numeric_upgrade dibuat untuk melakukan otomatisasi audit pada semua kolom numerik sekaligus.
* Logika:
1. Fungsi memisahkan kolom angka menggunakan select(where(is.numeric)).
2. Dilakukan pembersihan NA sementara (clean_x) agar perhitungan statistik tidak error.
3. Dilakukan pengujian statistik satu per satu (Central Tendency, Dispersion, dan Shape).
4. Menghitung persentase data hilang (Missing Value) dan jumlah pencilan (Outliers).
5. Menggabungkan semua hasil ke dalam satu tabel ringkasan (dataframe).
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
library(dplyr)
library(moments)
library(DT)
# Fungsi Poin 1 (Numerik)
describe_numeric_upgrade <- function(data) {
df_num <- data %>% select(where(is.numeric))
results <- lapply(df_num, function(x) {
clean_x <- x[!is.na(x)]
# Statistik Dasar & Tambahan
v_mean <- mean(clean_x)
v_median <- median(clean_x)
v_var <- var(clean_x)
v_sd <- sd(clean_x)
# Modus
ux <- unique(clean_x)
v_mode <- ux[which.max(tabulate(match(clean_x, ux)))]
# Skewness & Kurtosis
v_skew <- moments::skewness(clean_x)
v_kurt <- moments::kurtosis(clean_x)
# Missing Values
n_miss <- sum(is.na(x))
p_miss <- (n_miss / length(x)) * 100
# Normalitas (Shapiro-Wilk)
is_normal <- "Not Normal"
if(length(clean_x) >= 3 && length(clean_x) <= 5000) {
if(shapiro.test(clean_x)$p.value > 0.05) is_normal <- "Normal"
}
# Outliers (IQR)
q1 <- quantile(clean_x, 0.25)
q3 <- quantile(clean_x, 0.75)
iqr <- q3 - q1
n_outlier <- sum(clean_x < (q1 - 1.5*iqr) | clean_x > (q3 + 1.5*iqr))
data.frame(
Mean = v_mean, Median = v_median, Mode = v_mode,
Std_Dev = v_sd, Variance = v_var,
Skew = v_skew, Kurt = v_kurt,
Miss_Pct = paste0(round(p_miss, 1), "%"),
Normal = is_normal, Outliers = n_outlier
)
})
bind_rows(results, .id = "Variable")
}
# Tampilkan di Dashboard
numerik_table <- describe_numeric_upgrade(df)
datatable(numerik_table, options = list(scrollX = TRUE)) %>%
formatRound(columns=c(2:8), digits=2)
```
Row
-----------------------------------------------------------------------
### **Interpretasi**
Tabel audit di atas memberikan gambaran kesehatan data numerik kita. Kita bisa melihat kolom mana yang memiliki pencilan (Outliers) tinggi dan kolom mana yang datanya tidak terdistribusi normal. Informasi ini sangat berguna untuk menentukan apakah kita perlu melakukan transformasi data (seperti Log Transformation) atau pembersihan outlier sebelum masuk ke tahap analisis yang lebih dalam.
Row
-----------------------------------------------------------------------
### **Profiling Karakteristik Variabel Kategorikal**
1. Audit data kategorikal bertujuan untuk memahami distribusi variabel non-numerik atau kualitatif. Berbeda dengan data angka, fokus utama di sini adalah pada Kardinalitas (jumlah nilai unik) dan Modus (nilai yang paling sering muncul). Proses ini sangat penting untuk mendeteksi apakah ada variasi kategori yang terlalu banyak (High Cardinality) atau adanya data yang hilang pada atribut kualitatif seperti Departemen atau Posisi.
2. Penjelasan Fungsi & Logika
* Fungsi: describe_categorical_upgrade secara otomatis menyaring semua kolom yang bertipe karakter (is.character).
* Logika:
1. Menghitung jumlah observasi total dan jumlah nilai unik (n_distinct) untuk melihat variasi data.
2. Menentukan Modus secara manual dengan mencari frekuensi tertinggi dari nilai yang sudah dibersihkan dari NA.
3. Menghitung nilai yang hilang (Missing Values) baik dalam jumlah absolut maupun persentase.
4. Menggabungkan hasilnya menjadi dataframe ringkas untuk kemudahan audit.
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
# Fungsi Poin 2 (Kategorikal)
describe_categorical_upgrade <- function(data) {
df_cat <- data %>% select(where(is.character))
results <- lapply(df_cat, function(x) {
n_miss <- sum(is.na(x))
p_miss <- (n_miss / length(x)) * 100
# Modus
clean_x <- x[!is.na(x)]
ux <- unique(clean_x)
v_mode <- ux[which.max(tabulate(match(clean_x, ux)))]
data.frame(
Count = length(x),
Unique = n_distinct(x),
Mode = as.character(v_mode),
Miss_Count = n_miss,
Miss_Pct = paste0(round(p_miss, 1), "%")
)
})
bind_rows(results, .id = "Variable")
}
# Tampilkan di Dashboard dengan limit 5 baris
kategori_table <- describe_categorical_upgrade(df)
datatable(
kategori_table,
options = list(
scrollX = TRUE,
pageLength = 5, # Mengatur tampilan default jadi 5 baris
lengthMenu = c(5, 10, 15) # Opsi pilihan jumlah baris
)
)
```
Row
-----------------------------------------------------------------------
### **Interpretasi Hasil**
Melalui tabel profiling ini, kita bisa mengidentifikasi karakteristik dominan dari karyawan. Misalnya, melalui kolom Mode, kita tahu departemen mana yang paling banyak memiliki staf. Kolom Unique membantu kita melihat apakah ada kolom kategorikal yang seharusnya unik (seperti ID) atau yang bersifat klasifikasi. Jika persentase Missing Values tinggi pada variabel penting, maka perlu dilakukan tindakan pengisian data (imputation) atau penghapusan pada tahap cleaning selanjutnya.
PRE-PROCESSING DATA {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **Analisis & Imputasi Missing Value**
Missing Value (Data Hilang) terjadi ketika tidak ada nilai yang tersimpan untuk variabel dalam observasi tertentu. Hal ini bisa disebabkan oleh kesalahan input atau sistem. Secara statistik, kita tidak bisa membiarkan data kosong karena akan menyebabkan bias atau error pada algoritma. Metode yang kita gunakan di sini adalah Imputasi:
* Median Imputation: Untuk data numerik, mengisi nilai kosong dengan nilai tengah agar tidak terpengaruh outlier.
* Mode Imputation: Untuk data kategorikal, mengisi nilai kosong dengan nilai yang paling sering muncul (Modus).
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
library(DT)
# --- Proses Ringkasan ---
missing_summary <- df %>%
summarise(across(everything(), ~ sum(is.na(.)))) %>%
tidyr::pivot_longer(everything(), names_to = "Variable", values_to = "Missing_Count") %>%
mutate(Missing_Percentage = round((Missing_Count / nrow(df)) * 100, 2)) %>%
arrange(desc(Missing_Count))
# --- Tampilkan Tabel DT ---
datatable(missing_summary,
colnames = c("Variabel", "Jumlah Missing", "Persentase (%)"),
options = list(pageLength = 5, dom = 'ftp'), # f: filter, t: table, p: pagination
caption = "Tabel 1: Rincian Data Hilang (Interaktif)")
```
Row
-----------------------------------------------------------------------
### **Visualisasi**
```{r}
library(plotly)
# Filter hanya yang ada missing value-nya
plot_data <- missing_summary %>% filter(Missing_Count > 0)
if(nrow(plot_data) > 0) {
p <- ggplot(plot_data, aes(x = reorder(Variable, Missing_Count),
y = Missing_Count,
fill = Variable,
text = paste("Variabel:", Variable, "<br>Jumlah:", Missing_Count))) +
geom_bar(stat = "identity") +
coord_flip() +
theme_minimal() +
labs(x = "Variabel", y = "Jumlah Baris Kosong") +
theme(legend.position = "none")
# Konversi ke Plotly
ggplotly(p, tooltip = "text")
}
```
Row
-----------------------------------------------------------------------
### **Logika Pembersihan**
* Imputasi Numerik: Menggunakan Median karena bersifat robust terhadap pencilan (outliers), sehingga menjaga stabilitas distribusi nilai.
* Imputasi Kategorikal: Menggunakan Modus melalui fungsi kustom get_mode untuk mengisi kekosongan berdasarkan frekuensi kemunculan tertinggi.
* Efisiensi Komputasi: Penerapan across(where(...)) menjamin standarisasi pengisian secara otomatis pada seluruh kolom sesuai tipe datanya.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Berdasarkan audit, variabel Employy_ID dan Gendeer memiliki tingkat kekosongan tertinggi. Langkah imputasi dipilih untuk mempertahankan volume observasi dataset. Hasil akhirnya, dataset df_cleaned telah mencapai tingkat kelengkapan 100% dan siap digunakan untuk analisis tahap lanjut.
Row
-----------------------------------------------------------------------
### **Deduplikasi & Standardisasi String**
Setelah dilakukan proses penanganan missing values dan penghapusan duplikat, berikut adalah tampilan 10 baris pertama dari dataset yang telah dibersihkan.
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
library(dplyr)
library(DT)
# --- STEP 1: DEFINISI FUNGSI (Wajib di Atas) ---
# Fungsi untuk mencari modus pada data kategorial
get_mode <- function(v) {
uniqv <- unique(na.omit(v))
uniqv[which.max(tabulate(match(v, uniqv)))]
}
# --- STEP 2: EKSEKUSI CLEANING ---
df_cleaned <- df %>%
# 1. Menghapus Baris Duplikat
distinct() %>%
# 2. Imputasi Missing Value (Numerik pakai Median, Karakter pakai Modus)
mutate(across(where(is.numeric), ~ifelse(is.na(.), median(., na.rm = TRUE), .))) %>%
mutate(across(where(is.character), ~ifelse(is.na(.), get_mode(.), .))) %>%
# 3. Standardisasi Label Kategori
mutate(
Gender = case_when(
tolower(trimws(Gender)) %in% c("female", "f") ~ "Female",
tolower(trimws(Gender)) %in% c("male", "m") ~ "Male",
TRUE ~ "Unknown"
),
Education_Level = case_when(
tolower(trimws(Education_Level)) %in% c("phd") ~ "PhD",
tolower(trimws(Education_Level)) %in% c("master", "magister") ~ "Master",
tolower(trimws(Education_Level)) %in% c("bachelor", "s1", "bachelor degree") ~ "Bachelor",
TRUE ~ "Unknown"
)
)
# --- STEP 3: TAMPILKAN HASIL ---
datatable(head(df_cleaned, 10),
options = list(scrollX = TRUE, pageLength = 5, dom = 't'),
caption = "Tabel: Dataset Setelah Proses Imputasi dan Standardisasi")
```
Row
-----------------------------------------------------------------------
### **Visualisasi**
Visualisasi ini memastikan bahwa proses standardisasi kategori (seperti Level Pendidikan) telah berhasil menggabungkan label-label yang sebelumnya redundan.
```{r}
library(ggplot2)
library(plotly)
p_clean <- ggplot(df_cleaned, aes(x = Education_Level, fill = Education_Level)) +
geom_bar() +
theme_minimal() +
labs(title = "Distribusi Pendidikan Pasca-Standardisasi",
x = "Tingkat Pendidikan",
y = "Frekuensi") +
theme(legend.position = "none")
ggplotly(p_clean)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Deduplikasi Data: Implementasi fungsi distinct() bertujuan untuk menjamin integritas data dengan mengeliminasi observasi yang identik secara keseluruhan (redundansi baris).
* Standardisasi String: Penggunaan kombinasi tolower() dan trimws() berfungsi untuk menormalkan variasi penulisan teks (spasi liar dan perbedaan kapitalisasi) sebelum dilakukan pemetaan kategori menggunakan case_when().
* Pengelompokan Logis: Logika pemetaan (misal: "S1" menjadi "Bachelor") diterapkan untuk meminimalisir noise pada data kategorial, sehingga meningkatkan akurasi saat dilakukan analisis grup atau agregasi.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Melalui tahap ini, dataset telah berhasil divalidasi dan diseragamkan. Penghapusan redundansi dan standardisasi label kategori (Gender & Pendidikan) memastikan tidak ada penggandaan makna dalam satu variabel. Hasil visualisasi menunjukkan distribusi yang lebih bersih dan siap untuk diproses ke tahap analisis korelasi maupun pemodelan statistik tanpa kendala inkonsistensi label.
Row
-----------------------------------------------------------------------
### **Standardisasi Data & Label Encoding**
Tabel di bawah ini menampilkan hasil transformasi data pada kolom Department (standardisasi string) dan pembuatan fitur baru Job_Level_Encoded (mengubah teks kategori menjadi angka hirarki).
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
# 1. Proses Transformasi (Melanjutkan dari df_cleaned sebelumnya)
df_cleaned <- df_cleaned %>%
# Merapikan tulisan Department (Standarisasi)
mutate(Department = case_when(
tolower(trimws(Department)) %in% c("hr") ~ "HR",
tolower(trimws(Department)) %in% c("it") ~ "IT",
tolower(trimws(Department)) %in% c("finance") ~ "Finance",
tolower(trimws(Department)) %in% c("marketing") ~ "Marketing",
tolower(trimws(Department)) %in% c("operations") ~ "Operations",
tolower(trimws(Department)) %in% c("risk") ~ "Risk",
tolower(trimws(Department)) %in% c("compliance") ~ "Compliance",
TRUE ~ "Unknown"
)) %>%
# Label Encoding untuk Job_Level (Mengubah teks ke angka hirarki)
mutate(Job_Level_Encoded = case_when(
Job_Level == "Junior" ~ 1,
Job_Level == "Officer" ~ 2,
Job_Level == "Supervisor" ~ 3,
Job_Level == "Manager" ~ 4,
Job_Level == "Senior Manager" ~ 5,
TRUE ~ 0
))
# 2. MENAMPILKAN TABEL (Biar nggak kosong di dashboard)
# Kita tampilin kolom yang berubah aja biar dosen gampang ngeceknya
tabel_fitur <- df_cleaned %>%
select(Employee_ID, Department, Job_Level, Job_Level_Encoded) %>%
head(10)
datatable(tabel_fitur,
caption = "Hasil Feature Engineering: Standarisasi Departemen & Encoding Level Jabatan")
```
Row
-----------------------------------------------------------------------
### **Visualisasi**
```{r}
library(ggplot2)
library(plotly)
# Membuat plot distribusi tingkat jabatan hasil encoding
p_feature <- ggplot(df_cleaned, aes(x = as.factor(Job_Level_Encoded), fill = Job_Level)) +
geom_bar() +
scale_fill_brewer(palette = "Set2") +
theme_minimal() +
labs(title = "Distribusi Karyawan Berdasarkan Hirarki Jabatan (Encoded)",
x = "Kode Hirarki Jabatan",
y = "Jumlah Karyawan") +
theme(legend.title = element_blank())
ggplotly(p_feature)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Standardisasi Konsistensi String: Proses pembersihan pada variabel Department menggunakan kombinasi tolower() dan trimws() dilakukan untuk mereduksi variasi input teks yang tidak seragam akibat kesalahan manusia (data entry error). Pemetaan ulang menggunakan case_when() menjamin pengelompokan departemen menjadi bersifat mutually exclusive.
* Ordinal Label Encoding: Transformasi variabel kategorikal Job_Level menjadi komponen numerik Job_Level_Encoded dilakukan dengan memberikan bobot nilai berjenjang (1 hingga 5). Logika hirarki ini diterapkan karena variabel asal memiliki sifat ordinal, sehingga jarak antar tingkatan jabatan perlu dipertahankan demi memfasilitasi algoritma komputasi yang berbasis angka pada tahapan analisis selanjutnya.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Melalui tahapan Feature Engineering, inkonsistensi penulisan nama departemen telah berhasil dieliminasi sepenuhnya. Selain itu, restrukturisasi variabel Job_Level menjadi bentuk numerik berjenjang berhasil merepresentasikan struktur organisasi perusahaan secara matematis. Berdasarkan grafik distribusi interaktif, terlihat bahwa mayoritas komposisi karyawan berada pada tingkat jabatan. Fitur baru ini kini memiliki format data yang konsisten dan siap digunakan untuk pemodelan statistik parametrik maupun algoritma Machine Learning.
Row
-----------------------------------------------------------------------
### **Deteksi Outlier Metode IQR**
Tabel di bawah ini menampilkan daftar karyawan yang teridentifikasi memiliki nilai gaji di luar batas wajar statistik (outlier) berdasarkan metode Interquartile Range (IQR).
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
# Hitung Batas IQR (Biar konsisten di semua tab)
Q1 <- quantile(df_cleaned$Monthly_Salary, 0.25, na.rm = TRUE)
Q3 <- quantile(df_cleaned$Monthly_Salary, 0.75, na.rm = TRUE)
IQR_val <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR_val
upper_bound <- Q3 + 1.5 * IQR_val
# Data Outlier
outliers_salary <- df_cleaned %>%
filter(Monthly_Salary < lower_bound | Monthly_Salary > upper_bound)
datatable(outliers_salary, options = list(scrollX = TRUE),
caption = "Daftar Karyawan Terdeteksi Outlier")
```
Row
-----------------------------------------------------------------------
### **Visualisasi**
```{r}
library(ggplot2)
library(plotly) # 👈 Tambah library plotly
# 1. Masukkan ggplot ke dalam variabel p_box
p_box <- ggplot(df_cleaned, aes(x = "", y = Monthly_Salary,
text = paste("Gaji: Rp", format(Monthly_Salary, big.mark=".")))) +
geom_boxplot(fill = "tomato", color = "black", outlier.color = "red", outlier.shape = 16) +
labs(title = "Sebaran Gaji Sebelum Pembersihan",
subtitle = "Titik merah adalah outlier yang akan dibuang",
x = "",
y = "Salary") +
theme_minimal()
# 2. Konversi menjadi interaktif menggunakan ggplotly
ggplotly(p_box)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Metode Interquartile Range (IQR): Identifikasi pencilan pada variabel Monthly_Salary menggunakan metode pagar statistik Tukey (Tukey's Fences). Logika komputasi didasarkan pada penentuan Kuartil 1 (persentil ke-25) dan Kuartil 3 (persentil ke-75) untuk menghitung rentang antar-kuartil ($IQR = Q3 - Q1$).
* Penetapan Batas Ambang (Thresholding): Batas bawah (lower bound) ditentukan melalui formula $Q1 - 1.5 \times IQR$, sedangkan batas atas (upper bound) melalui formula $Q3 + 1.5 \times IQR$. Setiap data observasi yang nilainya berada di luar koridor batas ambang tersebut secara matematis diklasifikasikan sebagai outlier karena berada jauh dari distribusi normal pusat data.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Berdasarkan hasil audit menggunakan metode IQR, ditemukan sebanyak 9 karyawan yang memiliki karakteristik gaji ekstrem di luar jangkauan normal perusahaan.
Gaji ekstrem ini umumnya merepresentasikan posisi manajemen puncak (seperti Director atau C-Level) atau indikasi kesalahan input data (data entry error). Penemuan ini memberikan justifikasi kuat untuk melakukan penyaringan (filtering) data pada tahapan pembersihan berikutnya agar tidak mendistorsi nilai rata-rata kelompok dan menjaga keandalan uji statistik parametrik.
Row
-----------------------------------------------------------------------
### **Trimming Outlier & Stabilisasi Varians**
Tabel di bawah ini menampilkan 50 baris pertama dari dataset akhir (df_final) yang telah disterilkan dari observasi pencilan ekstrem.
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
# Eksekusi pembuangan
df_final <- df_cleaned %>%
filter(Monthly_Salary >= lower_bound & Monthly_Salary <= upper_bound)
datatable(head(df_final, 50), options = list(scrollX = TRUE),
caption = "Pratinjau Data Setelah Outlier Dihapus (50 Baris Pertama)")
```
Row
-----------------------------------------------------------------------
### **Visualisasi**
```{r}
ggplot(df_final, aes(x = "", y = Monthly_Salary)) +
geom_boxplot(fill = "springgreen3", color = "black") +
labs(title = "Sebaran Gaji Setelah Pembersihan", subtitle = "Data sudah bersih dan siap diolah", y = "Salary") +
theme_minimal()
```
Row
-----------------------------------------------------------------------
### **Numerical Audit Comparison**
Tabel di bawah ini meringkas perubahan metrik statistik utama sebelum dan sesudah penghapusan pencilan untuk melihat efektivitas tindakan pre-processing.
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
perbandingan <- data.frame(
Status = c("Original (With Outliers)", "Cleaned (No Outliers)"),
Total_Data = c(nrow(df_cleaned), nrow(df_final)),
Average_Salary = c(mean(df_cleaned$Monthly_Salary), mean(df_final$Monthly_Salary)),
Salary_Variance = c(var(df_cleaned$Monthly_Salary), var(df_final$Monthly_Salary))
)
datatable(perbandingan) %>% formatRound(columns = c(3,4), digits = 2)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Metode Listwise Deletion (Trimming): Tindakan penanganan outlier pada variabel Monthly_Salary diaplikasikan menggunakan teknik eliminasi berbasis baris (filtering). Logika komputasi mengeksekusi subsetting data hanya pada observasi yang memenuhi kondisi konjungsi logis: nilai harus lebih besar atau sama dengan batas bawah ($lower\_bound$) DAN kurang dari atau sama dengan batas atas ($upper\_bound$).
* Efek Penstabilan Varians (Variance Stabilization): Secara matematis, pembuangan nilai pencilan ekstrem berbanding lurus dengan penurunan drastis pada nilai varians ($Salary\_variance$) dan deviasi standar. Hal ini dikarenakan rumus varians sangat sensitif terhadap kuadrat jarak nilai ekstrem dari pusat data, sehingga hilangnya pencilan akan mengembalikan distribusi data mendekati asumsi normalitas.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Berdasarkan tabel Numerical Audit Comparison, proses treatment ini menyebabkan berkurangnya ukuran sampel dari [Isi Angka Total Data Original] menjadi [Isi Angka Total Data Cleaned] observasi. Meskipun terjadi pengurangan data, tindakan ini memberikan dampak positif yang signifikan pada kestabilan parameter statistik:
* Nila rata-rata gaji berubah secara substansial menjadi lebih representatif bagi populasi karyawan secara umum.
* Penurunan drastis pada Varians Gaji membuktikan bahwa deviasi antardata kini jauh lebih rapat dan konsisten.
Row
-----------------------------------------------------------------------
### **Diskretisasi Variabel Kontinu**
Tabel di bawah ini menampilkan hasil transformasi Data Binning pada variabel numerik kontinu (Age, Monthly_Salary, dan Performance_Score) menjadi variabel kategorikal ordinal.
Row
-----------------------------------------------------------------------
```{r}
# 1. FUNGSI BINNING YANG LEBIH AMAN
bin_numerical_variables <- function(df, column, breaks, labels) {
# Pastikan kolom menjadi NUMERIC dulu (Penting!)
df[[column]] <- as.numeric(as.character(df[[column]]))
new_col_name <- paste0(column, "_Category")
# Proses Binning
categories <- cut(
df[[column]],
breaks = breaks,
labels = labels,
right = FALSE,
include.lowest = TRUE
)
categories <- as.character(categories)
categories[is.na(categories)] <- "Unknown"
df[[new_col_name]] <- factor(categories, levels = c(labels, "Unknown"))
return(df)
}
# A. Transformasi Umur
df_final <- bin_numerical_variables(df_final, "Age",
breaks = c(0, 30, 40, 50, Inf),
labels = c("Young", "Mid Career", "Senior", "Late Career"))
# B. Transformasi Gaji
df_final <- bin_numerical_variables(df_final, "Monthly_Salary",
breaks = c(0, 8000000, 15000000, 25000000, Inf),
labels = c("Low Salary", "Middle Salary", "High Salary", "Very High Salary"))
# C. Transformasi Performa
df_final <- bin_numerical_variables(df_final, "Performance_Score",
breaks = c(0, 70, 85, Inf),
labels = c("Low Performer", "Moderate Performer", "High Performer"))
# 3. TAMPILKAN HASILNYA
datatable(head(df_final %>% select(Employee_ID, ends_with("_Category")), 10),
caption = "Tabel: Hasil Pengelompokan Data (Binning) untuk Analisis Poin 4")
```
Row
-----------------------------------------------------------------------
### Visualisasi
```{r}
library(ggplot2)
library(plotly)
# Contoh: Bar Chart Performance Score Category
p4 <- ggplot(df_final, aes(x = Performance_Score_Category, fill = Performance_Score_Category)) +
geom_bar() +
geom_text(stat='count', aes(label=..count..), vjust=-0.5) +
scale_fill_brewer(palette = "Set2") +
labs(title = "Distribusi Kelompok Performa Karyawan",
x = "Kategori Performa", y = "Jumlah Karyawan") +
theme_minimal()
ggplotly(p4)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Metode Data Binning (Diskretisasi): Transformasi dari skala rasio/kontinu menjadi bentuk ordinal diaplikasikan menggunakan fungsi cut(). Logika matematisnya memecah interval numerik tunggal menjadi serangkaian interval tertutup-buka ($[a, b)$) berdasarkan titik batas (breaks) yang telah dispesifikasikan secara teoretis.
* Penanganan Nilai Sisa (Handling Boundary & NA): Parameter right = FALSE memastikan nilai tepat pada batas bawah masuk ke kategori atasnya, sementara parameter include.lowest = TRUE menjamin nilai minimum mutlak tetap terakomodasi. Penambahan tingkat Unknown bertindak sebagai penangkap anomali (fail-safe) guna mencegah hilangnya observasi data selama proses pemetaan.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Proses Binning Data berhasil menyederhanakan kompleksitas distribusi tiga variabel utama menjadi bentuk segmentasi yang siap dianalisis. Melalui visualisasi grafik batang interaktif, dapat didentifikasi bahwa mayoritas tenaga kerja perusahaan terpusat pada kategori [Sebutkan Kategori Terbanyak, misal: Moderate Performer]. Restrukturisasi ini sangat krusial untuk memfasilitasi analisis tabel kontingensi (Uji Chi-Square) serta pembuatan profil demografi karyawan (user profiling) guna mendukung pengambilan keputusan strategis di bidang manajemen talenta (Human Capital Analytics).
Row
-----------------------------------------------------------------------
### **Standardisasi Z-Score & Min-Max**
Tabel di bawah ini menampilkan hasil transformasi data numerik menggunakan pendekatan Z-Score Standardization dan Min-Max Normalization untuk menyamakan skala antarvariabel.
Row
-----------------------------------------------------------------------
```{r}
# 1. ORDINAL ENCODING (Job Level)
# Logika: Mengubah tingkatan jabatan jadi angka berurutan
df_final <- df_final %>%
mutate(Job_Level_Code = case_when(
Job_Level == "Junior" ~ 1,
Job_Level == "Officer" ~ 2,
Job_Level == "Supervisor" ~ 3,
Job_Level == "Manager" ~ 4,
Job_Level == "Senior Manager" ~ 5,
TRUE ~ 0 # Handling jika ada data kosong
))
# 2. STANDARDIZATION (Z-Score)
# Logika: (x - mean) / sd. Membuat rata-rata jadi 0 dan standar deviasi jadi 1.
cols_to_zscore <- c("Monthly_Salary", "Performance_Score", "Training_Hours")
for (c in cols_to_zscore) {
new_name <- paste0(c, "_ZScore")
df_final[[new_name]] <- as.vector(scale(df_final[[c]]))
}
# 3. MIN-MAX NORMALIZATION
# Logika: (x - min) / (max - min). Mengubah skala jadi 0 sampai 1.
minmax_norm <- function(x) {
return ((x - min(x, na.rm = TRUE)) / (max(x, na.rm = TRUE) - min(x, na.rm = TRUE)))
}
df_final <- df_final %>%
mutate(Salary_Normalized = minmax_norm(Monthly_Salary))
# 4. TAMPILKAN HASILNYA
datatable(
head(df_final %>% select(Employee_ID, Job_Level, Job_Level_Code, contains("_ZScore"), Salary_Normalized), 10),
caption = "Tabel: Hasil Encoding, Z-Score Standardization, dan Min-Max Normalization"
) %>% formatRound(columns = c(4:7), digits = 3)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Z-Score Standardization ($Z$): Transformasi fitur Monthly_Salary, Performance_Score, dan Training_Hours dilakukan menggunakan fungsi scale(). Logika matematisnya berpusat pada pemetaan ulang nilai asli ($x$) menggunakan rumus $Z = \frac{x - \mu}{\sigma}$, di mana $\mu$ mewakili rata-rata populasi sampel dan $\sigma$ adalah standar deviasi. Hasil akhir dari proses ini memaksa distribusi data memiliki nilai rata-rata (mean) tepat di angka 0 dan varians atau standar deviasi sebesar 1.
* Min-Max Normalization: Konversi skala linear diterapkan pada variabel Monthly_Salary melalui fungsi kustom minmax_norm dengan rumus $x_{norm} = \frac{x - x_{min}}{x_{max} - x_{min}}$. Transformasi ini memetakan seluruh rentang nilai asli ke dalam batasan interval tertutup $[0, 1]$, di mana nilai minimum absolut data akan menjadi 0 dan nilai maksimum absolut menjadi 1.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Tahap komparasi penskalaan fitur (Feature Scaling) ini berhasil menyelaraskan magnitudo (satuan ukur) antar-variabel yang semula timpang. Sebelum transformasi dilakukan, variabel Monthly_Salary yang bernilai jutaan secara matematis akan mendominasi variabel Training_Hours yang hanya bernilai puluhan dalam perhitungan matriks jarak.
Dengan penerapan Z-Score, data kini telah terbebas dari bias satuan ukur asli tanpa mengubah bentuk distribusi geometris aslinya. Sementara itu, kolom Salary_Normalized memberikan alternatif penskalaan boundaries $[0, 1]$ yang sangat ideal untuk persiapan pemodelan. Berdasarkan pratinjau tabel interaktif, seluruh data numerik penyusun dataset df_final kini berada pada level komparasi yang setara (homogen) dan siap diintegrasikan ke dalam algoritma pengklasteran (clustering) maupun analisis regresi multivariat.
Exploratory Data Analysis (EDA) {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **Matriks Asosiasi Cramér's V**
Tabel di bawah ini menampilkan matriks koefisien Cramér's V untuk mengukur kekuatan asosiasi atau hubungan timbal balik antar-variabel kategorikal di dalam dataset.
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
library(vcd)
# Fungsi untuk menghitung matriks Cramér's V
calculate_cramers_v_matrix <- function(df) {
cat_cols <- df %>% select(where(is.factor) | where(is.character)) %>% names()
n <- length(cat_cols)
v_matrix <- matrix(1, nrow = n, ncol = n, dimnames = list(cat_cols, cat_cols))
for (i in 1:(n-1)) {
for (j in (i+1):n) {
tbl <- table(df[[cat_cols[i]]], df[[cat_cols[j]]])
v_val <- assocstats(tbl)$cramer
v_matrix[i, j] <- v_matrix[j, i] <- v_val
}
}
return(as.data.frame(v_matrix))
}
# Eksekusi pada df_final
cat_corr_results <- calculate_cramers_v_matrix(df_final)
datatable(cat_corr_results, caption = "Matriks Korelasi Kategorikal (Cramér's V)") %>%
formatRound(columns = 1:ncol(cat_corr_results), digits = 3)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Uji Asosiasi Cramér's V: Pengukuran kekuatan hubungan antar-variabel kategorikal (nominal/ordinal) didasarkan pada statistik Chi-Square ($\chi^2$). Logika komputasinya menerapkan formula matematis:
$$V = \sqrt{\frac{\chi^2}{n \times \min(k-1, r-1)}}$$
Di mana $\chi^2$ merupakan nilai statistik Chi-Square dari tabel kontingensi, $n$ adalah total ukuran sampel observasi, $r$ represents jumlah baris (rows), dan $k$ represents jumlah kolom (columns).
* Interpretasi Nilai Koefisien: Nilai koefisien Cramér's V bergerak secara mutlak pada rentang interval $[0, 1]$. Nilai mendekati 0 mengindikasikan tidak adanya asosiasi/independensi sempurna antar-variabel, sedangkan nilai mendekati 1 merepresentasikan hubungan asosiatif yang sangat kuat (perfect association).
Row
-----------------------------------------------------------------------
### **Interpretasi**
Matriks Cramér's V di atas memberikan gambaran komprehensif mengenai peta hubungan tersembunyi antar-variabel kategorial. Berdasarkan hasil perhitungan interaktif pada tabel kontingensi:
* Variabel yang memiliki nilai diagonal bernilai 1.000 karena merepresentasikan korelasi sempurna variabel dengan dirinya sendiri.
* Silakan lakukan analisis pada sel di luar diagonal. Jika ditemukan nilai koefisien $> 0.35$, hal tersebut mengindikasikan adanya efek hubungan yang kuat secara praktis (practically significant). Sebagai contoh, jika koefisien antara Department dan Performance_Score_Category bernilai tinggi, hal ini membuktikan secara empiris bahwa penempatan divisi kerja memiliki pengaruh sektoral terhadap tingkat produktivitas karyawan.
Analisis korelasi non-parametrik ini sangat krusial sebagai fondasi awal untuk memilih fitur-fitur kategorial potensial sebelum dimasukkan ke dalam pemodelan klasifikasi (Predictive Analytics Management).
Row
-----------------------------------------------------------------------
### **Matriks Korelasi Linear Pearson**
Tabel di bawah ini menampilkan kekuatan dan arah hubungan linear antar-variabel numerik asli menggunakan koefisien Korelasi Pearson.
Row
-----------------------------------------------------------------------
### **Tabel**
```{r}
library(dplyr)
library(DT)
library(ggplot2)
library(plotly)
library(tidyr)
# 1. OTOMATIS CARI KOLOM NUMERIK
num_cols <- df_final %>%
select(where(is.numeric)) %>%
select(-contains("ID"), -contains("Code"), -contains("ZScore"), -contains("Normalized"), -contains("TScore"))
# 2. PEARSON CORRELATION
pearson_mat <- cor(num_cols, method = "pearson", use = "pairwise.complete.obs")
# TAMPILKAN HASIL PEARSON
datatable(as.data.frame(pearson_mat),
options = list(scrollX = TRUE, dom = 't'),
caption = "Matriks Korelasi Pearson") %>%
formatRound(columns = 1:ncol(pearson_mat), digits = 3)
```
Row
-----------------------------------------------------------------------
### **Matriks Kovarians Numerik**
Tabel di bawah ini menunjukkan nilai kovarians asli dari variabel-variabel numerik untuk melihat arah pergerakan bersama.
Row
-----------------------------------------------------------------------
```{r}
# 3. COVARIANCE MATRIX
cov_mat <- cov(num_cols, use = "pairwise.complete.obs")
# TAMPILKAN HASIL KOVARIANS
datatable(as.data.frame(cov_mat),
options = list(scrollX = TRUE, dom = 't'),
caption = "Matriks Kovarians") %>%
formatRound(columns = 1:ncol(cov_mat), digits = 2)
```
Row
-----------------------------------------------------------------------
### **Visualisasi**
```{r}
p_scatter <- ggplot(df_final, aes(x = Age, y = Monthly_Salary,
text = paste("ID Karyawan:", Employee_ID,
"<br>Usia:", Age, "Tahun",
"<br>Gaji: Rp", format(Monthly_Salary, big.mark=".")))) +
geom_point(alpha = 0.6, color = "#1f77b4", size = 2) +
geom_smooth(aes(group = 1), method = "lm", color = "red", se = TRUE, linetype = "dashed") +
labs(title = "Scatter Plot Hubungan Usia vs Gaji",
x = "Usia (Tahun)",
y = "Gaji Bulanan (Rupiah)") +
theme_minimal()
ggplotly(p_scatter, tooltip = "text")
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Koefisien Korelasi Pearson ($r$): Standardisasi nilai kovarians dari dua variabel acak numerik dihitung menggunakan rumus matematis
$$r = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum (x_i - \bar{x})^2 \sum (y_i - \bar{y})^2}}$$
Metode ini mengukur derajat asosiasi linear dengan parameter interval $[-1, 1]$. Nilai $r = 1$ mengindikasikan korelasi positif sempurna, $r = -1$ menyatakan korelasi negatif sempurna, dan $r = 0$ menandakan ketiadaan hubungan linear.
* Matriks Kovarians ($Cov$): Nilai kovarians dihitung berdasarkan formula
$$Cov(X,Y) = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{n - 1}$$
Parameter ini digunakan untuk menentukan arah tren pergerakan simultan antar-dua variabel acak. Nilai kovarians bersifat scale-dependent (sangat tergantung pada besaran satuan unit ukur asli data), sehingga wajar apabila nilai pada variabel Monthly_Salary bernilai sangat besar (jutaan) karena mengikuti skala nominal Rupiah yang digunakan di dalam dataset asli.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Rangkaian analisis hubungan numerik ini memberikan kesimpulan penting mengenai pola data karyawan:
* Analisis Matriks Statistik: Berdasarkan tabel matriks kovarians dan Pearson, nilai positif (di atas 0) pada hubungan antara Age (Usia) dan Monthly_Salary (Gaji Bulanan) menandakan bahwa kedua variabel ini bergerak searah. Artinya, peningkatan pada satu variabel cenderung diikuti oleh peningkatan variabel lainnya.
* Konfirmasi Visual via Scatter Plot: Pola searah tersebut divalidasi secara grafis oleh visualisasi diagram pencar (Scatter Plot). Garis tren linear berwarna merah menunjukkan arah kemiringan ke kanan atas (positive slope). Tren ini mengindikasikan sebuah pola organisasi yang logis: semakin matang usia seorang karyawan, terdapat kecenderungan bahwa tingkat kompensasi atau gaji bulanan yang diterima juga bergerak meningkat secara linear.
Analisis Posisi Relatif {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **T-Score & Relative Position**
Tahapan analisis ini berfokus pada teknik *Feature Engineering* untuk mengukur posisi relatif data individu terhadap populasi. Melalui transformasi *T-Score*, metrik *Z-Score* yang kompleks dikonversi ke dalam skala standardisasi baru dengan nilai rata-rata (*mean*) 50 dan standar deviasi 10 agar lebih intuitif saat dibaca oleh pihak manajemen. Selain itu, perhitungan nilai Persentil (*Quantile*) diaplikasikan untuk memetakan ambang batas (*threshold*) dan segmentasi kedudukan finansial karyawan secara berjenjang di dalam organisasi.
Row
-----------------------------------------------------------------------
### **Standardisasi Peringkat via T-Score**
```{r}
library(dplyr)
library(DT)
library(ggplot2)
library(plotly)
# 1. Menghitung T-Score berdasarkan Z-Score
df_final <- df_final %>%
mutate(Salary_TScore = 50 + (10 * Monthly_Salary_ZScore))
# Tampilkan Tabel T-Score
datatable(head(df_final %>% select(Employee_ID, Monthly_Salary, Monthly_Salary_ZScore, Salary_TScore), 10),
options = list(scrollX = TRUE, pageLength = 5, dom = 't'),
caption = "Pratinjau Perhitungan Z-Score dan T-Score Gaji") %>%
formatRound(columns = 3:4, digits = 3)
```
Row
-----------------------------------------------------------------------
### **Analisis Ambang Batas Kuantil**
```{r}
# 2. Menghitung Persentil Gaji
salary_quantiles <- quantile(df_final$Monthly_Salary, probs = c(0.1, 0.25, 0.5, 0.75, 0.9, 0.95))
quant_df <- data.frame(Percentile = names(salary_quantiles), Value = as.numeric(salary_quantiles))
# Tampilkan Tabel Persentil
datatable(quant_df,
options = list(dom = 't'),
caption = "Daftar Persentil Gaji Karyawan") %>%
formatRound(columns = 2, digits = 2)
```
Row
-----------------------------------------------------------------------
### **Estimasi Kepadatan Probabilitas (KDE)**
```{r}
p_density <- ggplot(df_final, aes(x = Monthly_Salary)) +
geom_density(fill = "#69b3a2", alpha = 0.5, color = "#404040") +
# Tambah garis vertikal untuk Median (P50) berdasarkan data tabel Abang
geom_vline(aes(xintercept = median(Monthly_Salary, na.rm = TRUE)),
color = "red", linetype = "dashed", size = 0.8) +
labs(title = "Distribusi Kepadatan Gaji Karyawan (Garis Merah = Median)",
x = "Gaji Bulanan (Rupiah)",
y = "Kepadatan Data (Density)") +
theme_minimal()
ggplotly(p_density)
```
Row
-----------------------------------------------------------------------
### **Logika Teknis**
* Transformasi T-Score: Standardisasi linear lanjutan dari nilai Z-Score yang ditranslasikan menggunakan formula matematis $T = 50 + 10 \times Z$. Tindakan ini bertujuan untuk mengeliminasi nilai negatif dan desimal kecil pada Z-Score tanpa mengubah bentuk distribusi asli data (scale-preserving transformation), sehingga mempermudah pembacaan posisi nilai individu terhadap rata-rata populasi.
* Analisis Kepadatan & Persentil: Density Plot mengestimasi fungsi kepadatan probabilitas variabel kontinu menggunakan metode Kernel Density Estimation (KDE). Penambahan garis batas vertikal membantu mengidentifikasi pemusatan massa data dan memisahkan area sebaran berdasarkan ukuran lokasi persentil kuantitatif.
Row
-----------------------------------------------------------------------
### **Interpretasi**
Melalui pendekatan analisis posisi relatif ini, kita dapat memetakan struktur remunerasi karyawan secara mendalam:
* Interpretasi T-Score: Pada tabel pratinjau, karyawan dengan nilai Salary_TScore di atas 50.000 mengindikasikan bahwa kompensasi finansialnya berada di atas rata-rata perusahaan. Sebaliknya, nilai di bawah 50.000 menunjukkan posisi di bawah rata-rata.
* Interpretasi Density Plot: Grafik di sebelah kanan memperlihatkan bentuk kurva sebaran gaji. Puncak kurva yang tinggi menandakan area rentang nominal gaji yang paling banyak dimiliki oleh mayoritas karyawan. Garis putus-putus merah bertindak sebagai pembatas tengah (Median/P50), di mana separuh populasi berada di sebelah kiri garis (gaji rendah-menengah) dan separuh lainnya berada di sebelah kanan garis (gaji menengah-tinggi).
Hasil Analisis {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **Hasil Analisis**
Berdasarkan seluruh rangkaian audit, pembersihan, dan transformasi data yang telah dilakukan pada dataset karyawan, analisis ini menghasilkan beberapa kesimpulan utama yang krusial bagi keandalan data dan pengambilan keputusan perusahaan:
Pertama, dari aspek kualitas dan integritas data, hasil pengujian menunjukkan bahwa dataset awal memiliki tingkat variabilitas yang sangat tinggi, khususnya pada komponen kompensasi finansial. Intervensi menggunakan metode *Interquartile Range* (IQR) berhasil mengisolasi sejumlah pencilan (*outlier*) secara objektif. Hasil penapisan ini membuktikan bahwa tanpa proses pembersihan yang ketat, keberadaan data ekstrem tersebut akan mendistorsi nilai rata-rata industri dan menghasilkan estimasi yang bias jika dipaksakan masuk ke dalam pengujian statistik parametrik ataupun pemodelan prediktif.
Kedua, dari aspek karakteristik demografi dan struktur internal organisasi, analisis kepadatan (*Kernel Density Estimation*) mengonfirmasi adanya ketimpangan distribusi pendapatan yang bersifat *positive-skewed*. Hasil ini mengindikasikan bahwa struktur organisasi perusahaan masih bersifat piramida sehat, di mana mayoritas mutlak tenaga kerja berada pada klaster staf dengan rentang pendapatan menengah ke bawah, sementara alokasi anggaran besar terkonsentrasi secara eksklusif pada segmen manajemen puncak (*C-Level* dan *Director*). Dokumentasi visual interaktif menggunakan `plotly` berhasil memetakan batas ambang atas ini secara transparan bagi pihak manajemen.
Ketiga, melalui pemetaan matriks korelasi Pearson dan koefisien *Cramér's V*, hasil analisis berhasil membuktikan adanya pola hubungan linier yang signifikan antar-variabel numerik, seperti relevansi masa kerja (*tenure*) terhadap eskalasi pendapatan. Di sisi lain, variabel kategorikal seperti departemen dan peran spesifik karyawan terbukti memiliki kekuatan asosiasi yang kuat terhadap penempatan kelas karyawan. Pola-pola hubungan yang berhasil dipetakan ini memberikan indikator awal (*feature selection*) yang sangat valid mengenai variabel apa saja yang paling berpengaruh di dalam perusahaan.
Referensi & Daftar Pustaka {data-orientation=rows}
=======================================================================
Row
-----------------------------------------------------------------------
### **Metodologi & Teori Statistik:**
* Chambers, J. M., Cleveland, W. S., Kleiner, B., & Tukey, P. A. (1983). *Graphical Methods for Data Analysis*. Wadsworth & Brooks/Cole. *(Pustaka Teoretis untuk Metode Deteksi Outlier Tukey's Fences / Interquartile Range)*.
* Cramer, H. (1946). *Mathematical Methods of Statistics*. Princeton University Press. *(Referensi Utama Koefisien Asosiasi Cramér's V untuk Variabel Kategorikal)*.
* Pearson, K. (1895). Notes on regression and inheritance in the case of two parents. *Proceedings of the Royal Society of London*, 58, 240-242. *(Landasan Teoretis Koefisien Korelasi Linear Pearson)*.
* Silverman, B. W. (2018). *Density estimation for statistics and data analysis*. Routledge. *(Referensi Metodologi Estimasi Kepadatan Probabilitas / Kernel Density Estimation)*.
Row
-----------------------------------------------------------------------
### **Perangkat Lunak, Library, & Dokumentasi R:**
* Allaire, J., Yihui, X., Garrido, A., d'Agostino McGowan, L., et al. (2023). *flexdashboard: Easy interactive dashboards for R*. R package version 0.6.2. https://CRAN.R-project.org/package=flexdashboard
* Meyer, D., Zeileis, A., & Hornik, K. (2023). *vcd: Visualizing Categorical Data*. R package version 1.4-11. *(Dokumentasi Resmi Fungsi assocstats() untuk Penghitungan Cramér's V)*.
* R Core Team. (2024). *R: A Language and Environment for Statistical Computing*. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/
* Wickham, H., Averick, M., Bryan, J., Chang, W., D'Agostino McGowan, L., François, R., ... & Yutani, H. (2019). Welcome to the Tidyverse. *Journal of Open Source Software*, 4(43), 1686. https://doi.org/10.21105/joss.01686 *(Dokumentasi Package dplyr, tidyr, dan ggplot2)*.
* Xie, Y., Cheng, J., & Tan, X. (2024). *DT: A Wrapper of the JavaScript Library 'DataTables'*. R package version 0.32. https://CRAN.R-project.org/package=DT