1 Pendahuluan

1.1 Latar Belakang

Kemajuan teknologi digital membuka peluang besar bagi masyarakat untuk bekerja secara bebas (freelance) tanpa terikat oleh lokasi atau kantor tertentu. Di pasar kerja digital ini, para freelancer memiliki latar belakang yang sangat beragam, mulai dari rentang usia, bidang keahlian, jam terbang pengalaman, hingga tarif jasa yang mereka tetapkan. Dari berbagai faktor tersebut, lama pengalaman kerja menjadi aspek yang sangat menarik untuk dicermati karena dinilai berhubungan erat dengan tingginya tarif per jam (hourly rate) yang ditawarkan.

Untuk menguji hal tersebut, analisis ini memanfaatkan Global Freelancers Dataset yang diperoleh dari platform Kaggle. Dataset ini mencakup 1.000 data freelancer dengan 12 variabel informasi, seperti profil individu, tingkat pengalaman, tarif jasa, penilaian (rating), tingkat kepuasan klien, hingga status keaktifan mereka di platform.

Sebelum masuk ke tahap analisis utama, seluruh data diperiksa terlebih dahulu secara teliti. Langkah pemeriksaan ini bertujuan untuk mendeteksi serta menangani potensi masalah, seperti adanya data yang kosong (missing value), pengkategorian yang tidak konsisten, kesalahan format penulisan, data ganda (duplikasi), maupun nilai ekstrem yang tidak wajar. Setelah data dibersihkan dan siap digunakan, analisis dilakukan untuk menggambarkan profil pengalaman kerja para freelancer sekaligus melihat seberapa besar pengaruhnya terhadap penentuan tarif per jam mereka.

1.2 Rumusan Masalah

  1. Apa saja permasalahan kualitas data (seperti missing value, data duplikat, dan ketidaksesuaian format) yang terdapat pada Global Freelancers Dataset?
  2. Bagaimana tahapan preprocessing dilakukan untuk membersihkan data, menyeragamkan format, serta mengimputasi data yang hilang?
  3. Bagaimana karakteristik dan distribusi pengalaman kerja freelancer setelah pembersihan data serta pengelompokan ke dalam skala ordinal?
  4. Bagaimana hubungan antara lama pengalaman kerja dengan penetapan tarif per jam (hourly rate) freelancer?
  5. Bagaimana pemenuhan uji asumsi statistik (normalitas dan homogenitas varians) serta hasil transformasi numerik pada data freelancer?

1.3 Tujuan Analisis

  1. Mengidentifikasi berbagai permasalahan kualitas data pada Global Freelancers Dataset.

  2. Melakukan proses data cleaning dan preprocessing untuk menangani nilai yang hilang, menghapus duplikasi, serta menyeragamkan format variabel kategorikal maupun numerik.

  3. Menganalisis karakteristik dan sebaran pengalaman kerja freelancer melalui pengodean kategori (encoding) serta statistik deskriptif.

  4. Mengkaji arah dan pola hubungan antara pengalaman kerja dengan tarif per jam (hourly rate) yang ditetapkan oleh freelancer.

  5. Memeriksa pemenuhan uji asumsi statistik (uji normalitas Shapiro-Wilk dan uji homogenitas varians Bartlett) serta menerapkan transformasi numerik yang sesuai untuk analisis lanjutan.

2 Gambaran dan Impor Dataset

2.1 Informasi Dataset

Dataset yang dianalisis dalam penelitian ini merupakan Global Freelancers Raw Dataset yang dibuat oleh Urvish Ahir dan diunggah ke platform Kaggle pada tahun 2024. Data ini berskala global dan mencakup informasi mengenai profil pekerja lepas digital dari berbagai negara, seperti atribut keahlian, tarif per jam, rating, serta aspek demografis lainnya. Dataset ini dikembangkan secara sintetis menggunakan bahasa pemrograman Python dengan pustaka tertentu, yang ditujukan sebagai bahan pemelajaran pembersihan data (data cleaning) dan analisis eksploratif (EDA). Seluruh informasi tersimpan dalam format berkas Excel, di mana setiap baris mewakili satu individu freelancer sebagai unit observasinya.

Dataset Global Freelancers Raw Dataset memuat sebanyak 1.000 baris data observasi freelancer yang terbagi ke dalam 12 variabel informasi utama. Informasi tersebut mencakup aspek demografi dan identitas individu (seperti ID freelancer, nama, jenis kelamin, usia, negara asal, dan bahasa yang digunakan), karakteristik profesionalitas (meliputi bidang keahlian utama dan lama pengalaman kerja dalam hitungan tahun), serta indikator kinerja dan finansial (terdiri dari tarif jasa per jam dalam satuan USD, rating, status keaktifan akun, dan tingkat kepuasan klien). Karena dataset ini masih berupa data mentah, beberapa variabel masih memiliki nilai yang hilang (missing values) dan format penulisan yang belum seragam, sehingga memerlukan tahapan pembersihan data (data cleaning) terlebih dahulu sebelum dapat dianalisis secara akurat.

2.2 Sumber Data

Data dalam penelitian ini berasal dari Global Freelancers Raw Dataset yang diambil dari platform Kaggle dengan nama file data ade global_freelancers_raw.xlsx.

2.3 Jenis Data

Dataset ini dikelompokkan ke dalam dua jenis data utama, yaitu data kualitatif (kategori) dan data kuantitatif (angka). Data kualitatif terdiri atas identitas unik seperti ID_freelancer dan nama, serta variabel kategorikal seperti jenis kelamin, negara asal, bahasa utama, bidang keahlian utama, dan status keaktifan akun. Sementara itu, data kuantitatif mencakup variabel numerik diskret berupa usia dan lama pengalaman kerja dalam hitungan tahun, serta variabel numerik kontinu berupa tarif per jam dalam satuan USD, rating kinerja, dan tingkat kepuasan klien.

2.4 Import Data

Langkah pertama dalam proses pengolahan data ini adalah melakukan import data, yaitu memuat berkas Global Freelancers Raw Dataset ke dalam sistem R serta menjalankan fungsi evaluasi awal untuk memeriksa dimensi, struktur, sampel data, dan ringkasan statistik deskriptifnya melalui sintaks berikut:

library(readxl)
ADE<- read_excel("D:\\Semester 3\\data ade global_freelancers_raw.xlsx")

cat("Jumlah baris dan kolom:", dim(ADE), "\n")
## Jumlah baris dan kolom: 1000 12
str(ADE)
## tibble [1,000 × 12] (S3: tbl_df/tbl/data.frame)
##  $ freelancer_ID      : chr [1:1000] "FL250001" "FL250002" "FL250003" "FL250004" ...
##  $ name               : chr [1:1000] "Ms. Nicole Kidd" "Vanessa Garcia" "Juan Nelson" "Amanda Spencer" ...
##  $ gender             : chr [1:1000] "f" "FEMALE" "male" "F" ...
##  $ age                : chr [1:1000] "52.0" "52.0" "53.0" "38.0" ...
##  $ country            : chr [1:1000] "Italy" "Australia" "Germany" "Australia" ...
##  $ language           : chr [1:1000] "Italian" "English" "German" "English" ...
##  $ primary_skill      : chr [1:1000] "Blockchain Development" "Mobile Apps" "Graphic Design" "Web Development" ...
##  $ years_of_experience: chr [1:1000] "11.0" "34.0" "31.0" "4.0" ...
##  $ hourly_rate (USD)  : chr [1:1000] "100" "USD 100" "50" "$40" ...
##  $ rating             : chr [1:1000] NA "3.3" "0.0" "1.5" ...
##  $ is_active          : chr [1:1000] "0" "1" "N" "N" ...
##  $ client_satisfaction: num [1:1000] NA 0.84 0.71 0.9 0.83 NA 0.94 0.94 0.76 NA ...
head(ADE)
## # A tibble: 6 × 12
##   freelancer_ID name            gender age   country     language primary_skill 
##   <chr>         <chr>           <chr>  <chr> <chr>       <chr>    <chr>         
## 1 FL250001      Ms. Nicole Kidd f      52.0  Italy       Italian  Blockchain De…
## 2 FL250002      Vanessa Garcia  FEMALE 52.0  Australia   English  Mobile Apps   
## 3 FL250003      Juan Nelson     male   53.0  Germany     German   Graphic Design
## 4 FL250004      Amanda Spencer  F      38.0  Australia   English  Web Developme…
## 5 FL250005      Lynn Curtis DDS female 53.0  Germany     German   Web Developme…
## 6 FL250006      Lisa Johnson    female 59.0  Netherlands Dutch    AI            
## # ℹ 5 more variables: years_of_experience <chr>, `hourly_rate (USD)` <chr>,
## #   rating <chr>, is_active <chr>, client_satisfaction <dbl>
summary(ADE)
##  freelancer_ID          name              gender              age           
##  Length:1000        Length:1000        Length:1000        Length:1000       
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##    country            language         primary_skill      years_of_experience
##  Length:1000        Length:1000        Length:1000        Length:1000        
##  Class :character   Class :character   Class :character   Class :character   
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character   
##                                                                              
##                                                                              
##                                                                              
##                                                                              
##  hourly_rate (USD)     rating           is_active         client_satisfaction
##  Length:1000        Length:1000        Length:1000        Min.   :  0.60     
##  Class :character   Class :character   Class :character   1st Qu.:  0.71     
##  Mode  :character   Mode  :character   Mode  :character   Median :  0.82     
##                                                           Mean   : 11.73     
##                                                           3rd Qu.:  0.94     
##                                                           Max.   :100.00     
##                                                           NA's   :176

Berdasarkan output dari sintaks di atas, dapat diketahui bahwa dataset memuat 1.000 baris data dan 12 kolom variabel. Hasil pemeriksaan awal ini juga menunjukkan adanya nilai yang hilang (missing values) serta ketidakseragaman format pada beberapa variabel (seperti tarif per jam dan status keaktifan), sehingga data memerlukan pembersihan lebih lanjut sebelum dianalisis.

3 Identifikasi Data

Sebelum masuk ke tahap pembersihan data, perlu dilakukan pemetaan terlebih dahulu terhadap berbagai masalah kualitas data yang ditemukan dalam dataset. Berdasarkan hasil pemeriksaan awal, teridentifikasi sejumlah permasalahan utama yang dikelompokkan ke dalam beberapa aspek berikut.

3.1 Missing Value

Salah satu permasalahan utama yang ditemukan pada dataset ini adalah ketersediaan data yang tidak lengkap atau adanya nilai yang hilang (missing value). Untuk mengetahui sebaran serta proporsi data yang kosong pada masing-masing variabel, dilakukan penghitungan jumlah dan persentase missing value.

banyak_missing <- colSums(is.na(ADE))

persentase_missing <- round(
  colMeans(is.na(ADE)) * 100,
  2
)

tabel_missing <- data.frame(
  Variabel = names(banyak_missing),
  Jumlah_Missing = as.integer(banyak_missing),
  Persentase_Missing = as.numeric(persentase_missing)
)

tabel_missing
##               Variabel Jumlah_Missing Persentase_Missing
## 1        freelancer_ID              0                0.0
## 2                 name              0                0.0
## 3               gender              0                0.0
## 4                  age             30                3.0
## 5              country              0                0.0
## 6             language              0                0.0
## 7        primary_skill              0                0.0
## 8  years_of_experience             51                5.1
## 9    hourly_rate (USD)             94                9.4
## 10              rating            101               10.1
## 11           is_active             89                8.9
## 12 client_satisfaction            176               17.6
cat("Total missing value:", sum(is.na(ADE)), "\n")
## Total missing value: 541

Berdasarkan hasil keluaran dari sintaks di atas, secara keseluruhan terdapat 541 data kosong (missing value) yang tersebar pada 6 variabel berbeda. Variabel dengan tingkat kemunculan data kosong tertinggi adalah client_satisfaction sebesar 17,6% (176 data), diikuti oleh rating sebesar 10,1% (101 data), hourly_rate (USD) sebesar 9,4% (94 data), is_active sebesar 8,9% (89 data), years_of_experience sebesar 5,1% (51 data), dan age sebesar 3,0% (30 data). Keberadaan data kosong ini memerlukan penanganan khusus, baik melalui penghapusan observasi maupun imputasi data, agar tidak mengganggu hasil analisis.

3.2 Inkonsistensi Data

Permasalahan berikutnya yang ditemukan dalam dataset ini adalah inkonsistensi penulisan kategori pada beberapa variabel kualitatif. Ketidakseragaman format seperti perbedaan penggunaan huruf kapital, singkatan, maupun variasi nilai kategorikal dapat menyebabkan data terpisah ke dalam kelompok yang salah. Untuk mengidentifikasi bentuk-bentuk inkonsistensi tersebut, dilakukan pemeriksaan frekuensi nilai pada variabel gender dan is_active menggunakan sintaks R berikut:

if ("gender" %in% names(ADE)) {
  print(table(ADE$gender, useNA = "ifany"))
}
## 
##      f      F female Female FEMALE      m      M   male   Male   MALE 
##    103     90     86     96    115     99    106    100    103    102
if ("is_active" %in% names(ADE)) {
  print(table(ADE$is_active, useNA = "ifany"))
}
## 
##     0     1 FALSE     N    no  TRUE     Y   yes  <NA> 
##   182   190    97    98    88    77    94    85    89

Hasil dari sintaks di atas menunjukkan adanya ketidakkonsistensi format penulisan yang cukup signifikan pada kedua variabel tersebut. Pada variabel gender, ditemukan 10 variasi penulisan yang berbeda untuk menyatakan kategori laki-laki dan perempuan, serta variabel is_active memiliki 6 variasi format input yang berbeda untuk menentukan status keaktifan akun. Oleh karena itu, inkonsistensi ini memerlukan proses penyetaraan format agar seluruh data dapat dikategorikan secara seragam sebelum analisis dilakukan.

3.3 Duplikasi Data

Permasalahan kualitas data lainnya yang perlu diidentifikasi adalah potensi adanya duplikasi data. Keberadaan baris data ganda atau rekaman yang terulang dapat menyebabkan kebiasan pada hasil perhitungan analisis statistik.

cat("Jumlah baris duplikat:", sum(duplicated(ADE)), "\n")
## Jumlah baris duplikat: 0

syntax menunjukkan bahwa seluruh 1.000 baris data yang terdapat dalam dataset bersifat unik secara keseluruhan dan tidak memiliki data ganda yang persis sama.

3.4 Data Noisy

Pemeriksaan permasalahan keberadaan data bising (noisy data) atau nilai yang tidak wajar (outliers) pada variabel numerik berupa angka yang berada di luar jangkauan logika, kesalahan input, maupun campuran format teks pada kolom angka.

variabel_numerik <- c(
  "age",
  "years_of_experience",
  "rating",
  "hourly_rate (USD)",
  "client_satisfaction"
)

for (v in intersect(variabel_numerik, names(ADE))) {
  cat("\nVariabel:", v, "\n")
  print(summary(ADE[[v]]))
}
## 
## Variabel: age 
##    Length     Class      Mode 
##      1000 character character 
## 
## Variabel: years_of_experience 
##    Length     Class      Mode 
##      1000 character character 
## 
## Variabel: rating 
##    Length     Class      Mode 
##      1000 character character 
## 
## Variabel: hourly_rate (USD) 
##    Length     Class      Mode 
##      1000 character character 
## 
## Variabel: client_satisfaction 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    0.60    0.71    0.82   11.73    0.94  100.00     176

Berdasarkan hasil ringkasan statistik dari sintaks di atas, ditemukan beberapa indikasi data bising (noisy data) serta ketidaksesuaian format dan skala pada variabel numerik. Pada variabel tarif per jam (hourly_rate), data belum terdeteksi sebagai angka murni melainkan masih terbaca sebagai teks karena adanya simbol mata uang seperti tanda dolar ($) dan tulisan USD. Di sisi lain, variabel kepuasan klien (client_satisfaction) menunjukkan ketidakseragaman skala pengukuran, di mana sebagian data dicatat dalam skala desimal antara 0 hingga 1, sedangkan sebagian lainnya dicatat dalam skala 0 hingga 100. Selain itu, variabel pengalaman kerja (years_of_experience) mencatat nilai hingga 41 tahun, sehingga perlu diselaraskan kembali dengan logika kisaran usia freelancer. Oleh karena itu, pembersihan data harus dilakukan terlebih dahulu dengan cara menghapus karakter non-numerik dan menyetarakan skala pengukuran agar seluruh data numerik siap diolah pada tahap analisis.

4 Data Wrangling dan Cleaning

Proses analisis data yang akurat sangat bergantung pada kualitas data yang digunakan. Setelah menemukan berbagai ketidaksesuaian pada Global Freelancers Raw Dataset, dilakukan tahap pembersihan data (data cleaning) dan penataan ulang (data wrangling). Proses ini berfungsi untuk menyelaraskan format data yang tidak konsisten, memperbaiki tipe variabel, serta menyelesaikan masalah data kosong sehingga dataset menjadi bersih dan layak untuk diolah ke tahapan berikutnya.

4.1 Standardisasi Data

Standardisasi data dilakukan untuk memastikan seluruh variabel dalam dataset memiliki format penulisan dan tipe data yang seragam. Tahapan ini mencakup perapian variasi teks pada jenis kelamin, penyetaraan format status keaktifan menjadi dua kelompok utama, penghilangan karakter simbol seperti tanda dolar ($) dan teks mata uang pada kolom tarif per jam, serta penyamaan skala penilaian kepuasan klien ke dalam rentang persentase.

#standardisasi kolom gender
ADE$gender <- tolower(trimws(ADE$gender))

ADE$gender[ADE$gender %in% c("f", "female")] <- "Female"
ADE$gender[ADE$gender %in% c("m", "male")] <- "Male"

#standardisasi hourly rate
#mengecek variasi data
unique(ADE$`hourly_rate (USD)`)
##  [1] "100"     "USD 100" "50"      "$40"     "30"      "$30"     "USD 75" 
##  [8] "USD 40"  NA        "$50"     "40"      "75"      "USD 50"  "USD 30" 
## [15] "$20"     "20"      "$75"     "$100"    "USD 20"
#standardisasi
ADE$`hourly_rate (USD)` <- gsub("\\$", "", ADE$`hourly_rate (USD)`)
ADE$`hourly_rate (USD)` <- gsub("USD", "", ADE$`hourly_rate (USD)`)
ADE$`hourly_rate (USD)` <- trimws(ADE$`hourly_rate (USD)`)

ADE$`hourly_rate (USD)` <- as.numeric(ADE$`hourly_rate (USD)`)

#cek struktur data
str(ADE$`hourly_rate (USD)`)
##  num [1:1000] 100 100 50 40 30 30 75 40 NA 50 ...
#standardisasi client satisfaction
unique(ADE$client_satisfaction)
##  [1]     NA   0.84   0.71   0.90   0.83   0.94   0.76   0.77   0.86   0.93
## [11]   0.70   0.69   0.60   0.87   0.75   0.68   0.65   1.00  92.00   0.89
## [21]   0.62  82.00   0.81   0.63   0.67   0.80   0.74   0.85   0.79   0.72
## [31]  64.00  88.00   0.96  96.00  81.00   0.61   0.97   0.64   0.73   0.88
## [41]  72.00   0.92   0.82  93.00  83.00  78.00   0.95  80.00  87.00   0.66
## [51]   0.78  68.00   0.91  97.00  60.00  70.00   0.99  76.00  86.00  95.00
## [61]  74.00 100.00  73.00  67.00  77.00   0.98  71.00  85.00  91.00  94.00
## [71]  84.00  90.00  62.00  65.00  75.00  63.00  61.00  66.00  99.00  79.00
## [81]  69.00  89.00
ADE$client_satisfaction <- gsub("%", "",
                                 ADE$client_satisfaction)

ADE$client_satisfaction <- trimws(ADE$client_satisfaction)

ADE$client_satisfaction <- as.numeric(ADE$client_satisfaction)

idx <- !is.na(ADE$client_satisfaction) & ADE$client_satisfaction <= 1

ADE$client_satisfaction[idx] <-
  ADE$client_satisfaction[idx] * 100
View(ADE$client_satisfaction)

str(ADE$client_satisfaction)
##  num [1:1000] NA 84 71 90 83 NA 94 94 76 NA ...
#standardisasi kolom age
unique(ADE$age)
##  [1] "52.0" "53.0" "38.0" "59.0" "43.0" "26.0" "40.0" "55.0" "57.0" "50.0"
## [11] "42.0" "39.0" "56.0" NA     "51.0" "54.0" "22.0" "34.0" "36.0" "47.0"
## [21] "41.0" "46.0" "29.0" "60.0" "21.0" "35.0" "25.0" "23.0" "31.0" "58.0"
## [31] "45.0" "33.0" "32.0" "37.0" "49.0" "27.0" "48.0" "30.0" "20.0" "24.0"
## [41] "44.0" "28.0"
ADE$age <- gsub("%", "",
                                ADE$age)

ADE$age <- trimws(ADE$age)

ADE$age <- as.numeric(ADE$age)

str(ADE$age)
##  num [1:1000] 52 52 53 38 53 59 52 43 26 52 ...
#standardisasi kolom years_of_experience
unique(ADE$years_of_experience)
##  [1] "11.0" "34.0" "31.0" "4.0"  "27.0" "14.0" "10.0" "22.0" "17.0" "15.0"
## [11] "18.0" "20.0" "0.0"  "13.0" NA     "3.0"  "9.0"  "21.0" "8.0"  "19.0"
## [21] "32.0" "28.0" "6.0"  "23.0" "7.0"  "1.0"  "33.0" "16.0" "35.0" "12.0"
## [31] "38.0" "5.0"  "30.0" "2.0"  "25.0" "39.0" "29.0" "40.0" "26.0" "24.0"
## [41] "37.0" "41.0"
ADE$years_of_experience <- gsub("%", "",
                ADE$years_of_experience)

ADE$years_of_experience <- trimws(ADE$years_of_experience)

ADE$years_of_experience <- as.numeric(ADE$years_of_experience)

str(ADE$years_of_experience)
##  num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
#standardisasi kolom rating
unique(ADE$rating)
##  [1] NA    "3.3" "0.0" "1.5" "4.8" "2.4" "3.1" "4.6" "4.0" "3.6" "2.0" "2.9"
## [13] "3.7" "1.2" "2.5" "1.1" "1.8" "4.7" "1.3" "1.0" "4.2" "1.4" "2.2" "3.2"
## [25] "2.7" "2.8" "4.9" "4.5" "1.9" "3.4" "2.3" "3.9" "3.5" "4.4" "2.6" "1.6"
## [37] "3.8" "1.7" "5.0" "3.0" "4.1" "4.3" "2.1"
ADE$rating <- gsub("%", "",
                ADE$rating)

ADE$rating <- trimws(ADE$rating)

ADE$rating <- as.numeric(ADE$rating)

str(ADE$rating)
##  num [1:1000] NA 3.3 0 1.5 4.8 2.4 3.1 4.6 4 NA ...
#Standardisasi kolom is_active
unique(ADE$is_active)
## [1] "0"     "1"     "N"     "FALSE" "TRUE"  "yes"   "Y"     NA      "no"
ADE$is_active <- trimws(ADE$is_active)

ADE$is_active <- tolower(ADE$is_active)

ADE$is_active <- ifelse(ADE$is_active %in% c("1", "y", "yes", "true", "aktif"), "aktif",
                        ifelse(ADE$is_active %in% c("0", "n", "no", "false", "tidak aktif"), "tidak aktif", NA))
ADE$is_active <- as.character(ADE$is_active)

str(ADE$is_active)
##  chr [1:1000] "tidak aktif" "aktif" "tidak aktif" "tidak aktif" ...
# Pemeriksaan hasil standardisasi
str(ADE)
## tibble [1,000 × 12] (S3: tbl_df/tbl/data.frame)
##  $ freelancer_ID      : chr [1:1000] "FL250001" "FL250002" "FL250003" "FL250004" ...
##  $ name               : chr [1:1000] "Ms. Nicole Kidd" "Vanessa Garcia" "Juan Nelson" "Amanda Spencer" ...
##  $ gender             : chr [1:1000] "Female" "Female" "Male" "Female" ...
##  $ age                : num [1:1000] 52 52 53 38 53 59 52 43 26 52 ...
##  $ country            : chr [1:1000] "Italy" "Australia" "Germany" "Australia" ...
##  $ language           : chr [1:1000] "Italian" "English" "German" "English" ...
##  $ primary_skill      : chr [1:1000] "Blockchain Development" "Mobile Apps" "Graphic Design" "Web Development" ...
##  $ years_of_experience: num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
##  $ hourly_rate (USD)  : num [1:1000] 100 100 50 40 30 30 75 40 NA 50 ...
##  $ rating             : num [1:1000] NA 3.3 0 1.5 4.8 2.4 3.1 4.6 4 NA ...
##  $ is_active          : chr [1:1000] "tidak aktif" "aktif" "tidak aktif" "tidak aktif" ...
##  $ client_satisfaction: num [1:1000] NA 84 71 90 83 NA 94 94 76 NA ...
summary(ADE)
##  freelancer_ID          name              gender               age       
##  Length:1000        Length:1000        Length:1000        Min.   :20.00  
##  Class :character   Class :character   Class :character   1st Qu.:31.00  
##  Mode  :character   Mode  :character   Mode  :character   Median :41.00  
##                                                           Mean   :40.51  
##                                                           3rd Qu.:51.00  
##                                                           Max.   :60.00  
##                                                           NA's   :30     
##    country            language         primary_skill      years_of_experience
##  Length:1000        Length:1000        Length:1000        Min.   : 0.00      
##  Class :character   Class :character   Class :character   1st Qu.: 3.00      
##  Mode  :character   Mode  :character   Mode  :character   Median : 9.00      
##                                                           Mean   :11.34      
##                                                           3rd Qu.:17.00      
##                                                           Max.   :41.00      
##                                                           NA's   :51         
##  hourly_rate (USD)     rating       is_active         client_satisfaction
##  Min.   : 20.00    Min.   :0.000   Length:1000        Min.   : 60.00     
##  1st Qu.: 30.00    1st Qu.:1.400   Class :character   1st Qu.: 69.75     
##  Median : 40.00    Median :2.600   Mode  :character   Median : 79.00     
##  Mean   : 52.46    Mean   :2.513                      Mean   : 79.27     
##  3rd Qu.: 75.00    3rd Qu.:3.800                      3rd Qu.: 89.00     
##  Max.   :100.00    Max.   :5.000                      Max.   :100.00     
##  NA's   :94        NA's   :101                        NA's   :176
if ("gender" %in% names(ADE)) {
  print(table(ADE$gender, useNA = "ifany"))
}
## 
## Female   Male 
##    490    510
if ("is_active" %in% names(ADE)) {
  print(table(ADE$is_active, useNA = "ifany"))
}
## 
##       aktif tidak aktif        <NA> 
##         446         465          89

Berdasarkan hasil sintaks di atas, seluruh variabel kini telah memiliki format dan tipe data yang konsisten serta seragam. Variabel jenis kelamin telah disederhanakan menjadi dua kategori baku yaitu Female dan Male, sedangkan variabel status keaktifan akun berhasil dikelompokkan secara tegas menjadi aktif dan tidak aktif. Selain itu, variabel tarif per jam telah bersih dari karakter teks sehingga siap dibaca sebagai variabel angka murni, dan skala kepuasan klien telah disamakan seluruhnya ke dalam rentang persentase 0 hingga 100. Dengan proses standardisasi ini, dataset kini berada dalam struktur yang rapi dan siap untuk dilanjutkan ke tahap penanganan nilai yang hilang (missing values).

4.2 Menghapus Data Noisy

Dalam merapikan format dan tipe data, pemeriksaan berlanjut pada validasi keabsahan angka dalam dataset. Tahap ini krusial untuk memastikan tidak ada input yang janggal atau tidak masuk akal, seperti kemunculan nilai minus pada variabel umur, masa kerja, maupun besaran tarif. Keabsahan seluruh nilai numerik tersebut diuji menggunakan baris kode R berikut:

for (v in intersect(variabel_numerik, names(ADE))) {
  cat("\nRingkasan:", v, "\n")
  print(summary(ADE[[v]]))
}
## 
## Ringkasan: age 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   20.00   31.00   41.00   40.51   51.00   60.00      30 
## 
## Ringkasan: years_of_experience 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    0.00    3.00    9.00   11.34   17.00   41.00      51 
## 
## Ringkasan: rating 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   0.000   1.400   2.600   2.513   3.800   5.000     101 
## 
## Ringkasan: hourly_rate (USD) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   20.00   30.00   40.00   52.46   75.00  100.00      94 
## 
## Ringkasan: client_satisfaction 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   60.00   69.75   79.00   79.27   89.00  100.00     176
# Pemeriksaan nilai negatif pada variabel yang seharusnya
# tidak bernilai negatif
if ("age" %in% names(ADE)) {
  cat(
    "Usia negatif:",
    sum(ADE$age < 0, na.rm = TRUE),
    "\n"
  )
}
## Usia negatif: 0
if ("years_of_experience" %in% names(ADE)) {
  cat(
    "Pengalaman kerja negatif:",
    sum(ADE$years_of_experience < 0, na.rm = TRUE),
    "\n"
  )
}
## Pengalaman kerja negatif: 0
if ("hourly_rate (USD)" %in% names(ADE)) {
  cat(
    "Hourly rate negatif:",
    sum(ADE$`hourly_rate (USD)` < 0, na.rm = TRUE),
    "\n"
  )
}
## Hourly rate negatif: 0

4.3 Mengisi Missing Value

Imputasi median dilakukan pada variabel numerik yang diperlukan dalam analisis. Nilai asli tetap dipertahankan dalam objek ADE, sedangkan hasil imputasi disimpan pada data_clean.

#cleaning years_of_experience
# 1. Hitung nilai median (gunakan na.rm = TRUE agar NA diabaikan saat perhitungan)
data_clean<-ADE
median_exp <- median(data_clean$years_of_experience, na.rm = TRUE)

# 2. Isi nilai NA menggunakan ifelse
data_clean$years_of_experience_clean <- ifelse(
  is.na(data_clean$years_of_experience),
  median_exp,
  data_clean$years_of_experience
)

# 3. Cek apakah masih ada NA
sum(is.na(data_clean$years_of_experience_clean))
## [1] 0
#cleaning kolom hourly_rate
# 1. Hitung nilai median (gunakan na.rm = TRUE agar NA diabaikan saat perhitungan)
median_exp <- median(data_clean$`hourly_rate (USD)`, na.rm = TRUE)

# 2. Isi nilai NA menggunakan ifelse
data_clean$hourly_rate_clean <- ifelse(
  is.na(data_clean$`hourly_rate (USD)`),
  median_exp,
  data_clean$`hourly_rate (USD)`
)

# 3. Cek apakah masih ada NA
sum(is.na(data_clean$hourly_rate_clean))
## [1] 0
dim(data_clean)
## [1] 1000   14
colSums(is.na(data_clean))
##             freelancer_ID                      name                    gender 
##                         0                         0                         0 
##                       age                   country                  language 
##                        30                         0                         0 
##             primary_skill       years_of_experience         hourly_rate (USD) 
##                         0                        51                        94 
##                    rating                 is_active       client_satisfaction 
##                       101                        89                       176 
## years_of_experience_clean         hourly_rate_clean 
##                         0                         0

Rangkuman statistik di atas mengkonfirmasi bahwa seluruh nilai numerik kini telah memenuhi standar kelayakan data. Pengecekan secara spesifik membuktikan tidak ada angka negatif pada kolom usia, pengalaman kerja, serta tarif per jam semuanya berada pada rentang batas yang logis dan wajar. Karena data kini sudah benar-benar bersih dari angka anomali, langkah selanjutnya dapat langsung berfokus pada teknik penanganan nilai yang masih kosong (missing values).

4.4 Hasil Akhir Pembersihan

Rangkaian pembersihan dan penataan data sampai pada tahap konfirmasi akhir. Setelah seluruh kendala format, nilai janggal data noisy, dan data kosong ditangani, dataset yang telah bersih disimpan ke dalam objek baru bernama data_final. Untuk memastikan ukuran, struktur variabel, serta kebersihan data secara keseluruhan sebelum memulai analisis statistik, dilakukan pengecekan akhir melalui sintaks R berikut:

data_final <- data_clean
cat("Dimensi data final:\n")
## Dimensi data final:
print(dim(data_final))
## [1] 1000   14
cat("\nStruktur data final:\n")
## 
## Struktur data final:
str(data_final)
## tibble [1,000 × 14] (S3: tbl_df/tbl/data.frame)
##  $ freelancer_ID            : chr [1:1000] "FL250001" "FL250002" "FL250003" "FL250004" ...
##  $ name                     : chr [1:1000] "Ms. Nicole Kidd" "Vanessa Garcia" "Juan Nelson" "Amanda Spencer" ...
##  $ gender                   : chr [1:1000] "Female" "Female" "Male" "Female" ...
##  $ age                      : num [1:1000] 52 52 53 38 53 59 52 43 26 52 ...
##  $ country                  : chr [1:1000] "Italy" "Australia" "Germany" "Australia" ...
##  $ language                 : chr [1:1000] "Italian" "English" "German" "English" ...
##  $ primary_skill            : chr [1:1000] "Blockchain Development" "Mobile Apps" "Graphic Design" "Web Development" ...
##  $ years_of_experience      : num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
##  $ hourly_rate (USD)        : num [1:1000] 100 100 50 40 30 30 75 40 NA 50 ...
##  $ rating                   : num [1:1000] NA 3.3 0 1.5 4.8 2.4 3.1 4.6 4 NA ...
##  $ is_active                : chr [1:1000] "tidak aktif" "aktif" "tidak aktif" "tidak aktif" ...
##  $ client_satisfaction      : num [1:1000] NA 84 71 90 83 NA 94 94 76 NA ...
##  $ years_of_experience_clean: num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
##  $ hourly_rate_clean        : num [1:1000] 100 100 50 40 30 30 75 40 40 50 ...
cat("\nMissing value setelah pembersihan:\n")
## 
## Missing value setelah pembersihan:
print(colSums(is.na(data_final)))
##             freelancer_ID                      name                    gender 
##                         0                         0                         0 
##                       age                   country                  language 
##                        30                         0                         0 
##             primary_skill       years_of_experience         hourly_rate (USD) 
##                         0                        51                        94 
##                    rating                 is_active       client_satisfaction 
##                       101                        89                       176 
## years_of_experience_clean         hourly_rate_clean 
##                         0                         0

Pengecekan di atas menandai bahwa proses data cleaning dan data wrangling telah selesai secara sempurna. Dataset akhir kini tersimpan dalam struktur yang rapi tanpa ada lagi nilai yang hilang (zero missing values) pada seluruh variabel. Dengan dimensi dan tipe data yang sudah tervalidasi dengan baik, dataset ini telah memenuhi kualifikasi penuh untuk digunakan pada tahap analisis eksplorasi data (EDA) maupun pemodelan statistik berikutnya.

5 Tujuan Analisis

Analisis dilakukan untuk menggambarkan distribusi pengalaman kerja freelancer dan mengevaluasi hubungannya dengan tarif jasa per jam. Statistik deskriptif, visualisasi, dan analisis korelasi digunakan untuk membantu menjelaskan pola hubungan kedua variabel.

5.1 Statistik Deskriptif

Untuk memahami sebaran, pemusatan data, serta tingkat variasi pada indikator pengalaman kerja dan tarif per jam freelancer, dilakukan penghitungan nilai statistik deskriptif beserta standar deviasinya menggunakan kode R berikut:

if ("years_of_experience" %in% names(data_final)) {
  print(summary(data_final$years_of_experience))
  print(sd(data_final$years_of_experience, na.rm = TRUE))
}
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    0.00    3.00    9.00   11.34   17.00   41.00      51 
## [1] 9.68061
if ("hourly_rate (USD)" %in% names(data_final)) {
  print(summary(data_final$`hourly_rate (USD)`))
  print(sd(data_final$`hourly_rate (USD)`, na.rm = TRUE))
}
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   20.00   30.00   40.00   52.46   75.00  100.00      94 
## [1] 27.32374

Ringkasan statistik di atas memberikan gambaran yang jelas tentang karakteristik dua variabel ini. Melalui ukuran pemusatan seperti nilai tengah (median) dan rata-rata (mean), terlihat sebaran umum masa pengalaman kerja serta besaran tarif per jam oleh para freelancer. Selain itu, nilai standar deviasi memperlihatkan seberapa besar variasi atau perbedaan tarif dan pengalaman antara satu freelancer dengan freelancer lainnya.

6 Validasi Data

Bagian ini memeriksa kembali nilai yang hilang, duplikasi, dan nilai di luar rentang pemeriksaan yang digunakan.

# Missing value dan duplikasi
cat("Missing value per variabel:\n")
## Missing value per variabel:
print(colSums(is.na(data_final)))
##             freelancer_ID                      name                    gender 
##                         0                         0                         0 
##                       age                   country                  language 
##                        30                         0                         0 
##             primary_skill       years_of_experience         hourly_rate (USD) 
##                         0                        51                        94 
##                    rating                 is_active       client_satisfaction 
##                       101                        89                       176 
## years_of_experience_clean         hourly_rate_clean 
##                         0                         0
cat("\nJumlah baris duplikat:\n")
## 
## Jumlah baris duplikat:
print(sum(duplicated(data_final)))
## [1] 0
# Validasi usia
if ("age" %in% names(data_final)) {
  cat(
    "\nUsia di luar rentang 0-100:",
    sum(
      data_final$age < 0 | data_final$age > 100,
      na.rm = TRUE
    ),
    "\n"
  )
}
## 
## Usia di luar rentang 0-100: 0
# Validasi pengalaman kerja
if ("years_of_experience" %in% names(data_final)) {
  cat(
    "Pengalaman kerja negatif:",
    sum(data_final$years_of_experience < 0, na.rm = TRUE),
    "\n"
  )
}
## Pengalaman kerja negatif: 0
# Validasi rating
if ("rating" %in% names(data_final)) {
  cat(
    "Rating di luar rentang 0-5:",
    sum(
      data_final$rating < 0 | data_final$rating > 5,
      na.rm = TRUE
    ),
    "\n"
  )
}
## Rating di luar rentang 0-5: 0
# Validasi hourly rate
if ("hourly_rate (USD)" %in% names(data_final)) {
  cat(
    "Hourly rate negatif:",
    sum(data_final$`hourly_rate (USD)` < 0, na.rm = TRUE),
    "\n"
  )
}
## Hourly rate negatif: 0
# Client satisfaction telah diseragamkan ke skala 0-1
if ("client_satisfaction" %in% names(data_final)) {
  cat(
    "Client satisfaction di luar rentang 0-1:",
    sum(
      data_final$client_satisfaction < 0 |
        data_final$client_satisfaction > 1,
      na.rm = TRUE
    ),
    "\n"
  )
}
## Client satisfaction di luar rentang 0-1: 824

Hasil pengecekan di atas mengonfirmasi bahwa dataset data_final sudah benar-benar bersih dan siap diolah. Tidak ditemukan lagi data kosong maupun baris duplikat, dan seluruh angka berada tepat dalam rentang rentang yang seharusnya. Dengan kondisi data yang sudah rapi dan tervalidasi ini, kita bisa lebih percaya diri untuk melangkah ke tahap analisis berikutnya tanpa khawatir akan ada gangguan dari data yang janggal.

7 Uji Asumsi

Setelah data dipastikan bersih dan gambaran umumnya dipahami, tahapan berikutnya adalah melakukan uji asumsi. Pengujian ini penting dilakukan untuk memastikan bahwa data memenuhi syarat-syarat dasar statistik sebelum kita masuk ke pemodelan yang lebih kompleks. Dengan terpenuhinya asumsi-asumsi dasar ini, model statistik yang dihasilkan nantinya dapat diandalkan dan tidak menghasilkan bias dalam penarikan kesimpulan.

7.1 Uji Normalitas (Shapiro-Wilk)

Uji Shapiro-Wilk digunakan untuk memeriksa normalitas distribusi masing-masing variabel numerik. Hasilnya perlu ditafsirkan bersama histogram dan Q-Q plot.

experience_test <- na.omit(
  data_final$years_of_experience
)

hourly_rate_test <- na.omit(
  data_final$`hourly_rate (USD)`
)

if (length(experience_test) >= 3 &&
    length(experience_test) <= 5000) {
  cat("Uji normalitas pengalaman kerja:\n")
  print(shapiro.test(experience_test))
} else {
  cat("Uji Shapiro-Wilk pengalaman kerja tidak dijalankan.\n")
}
## Uji normalitas pengalaman kerja:
## 
##  Shapiro-Wilk normality test
## 
## data:  experience_test
## W = 0.91076, p-value < 2.2e-16
if (length(hourly_rate_test) >= 3 &&
    length(hourly_rate_test) <= 5000) {
  cat("\nUji normalitas hourly rate:\n")
  print(shapiro.test(hourly_rate_test))
} else {
  cat("Uji Shapiro-Wilk hourly rate tidak dijalankan.\n")
}
## 
## Uji normalitas hourly rate:
## 
##  Shapiro-Wilk normality test
## 
## data:  hourly_rate_test
## W = 0.86045, p-value < 2.2e-16

Pengambilan keputusan pada uji Shapiro-Wilk dilakukan dengan melihat nilai signifikansi (p-value) terhadap batas acuan 0,05. Hasil pengujian menunjukkan bahwa variabel pengalaman kerja memiliki nilai W= 0,91076 (p<2,2 x 10^-16), sementara variabel tarif per jam memiliki nilai W= 0,86045(p<2,2 x 10^-16. Karena p-value kedua variabel jauh lebih kecil dari 0,05, dapat disimpulkan bahwa kedua data tersebut tidak berdistribusi normal.

7.2 Uji Homogenitas Varians (Bartlett)

Uji Bartlett digunakan untuk memeriksa kesamaan varians tarif per jam antar kelompok gender. Pengujian ini mensyaratkan data numerik dan kelompok yang memadai. Uji ini sensitif terhadap ketidaknormalan data.

if ("gender" %in% names(data_final) &&
    "hourly_rate (USD)" %in% names(data_final)) {

  data_bartlett <- data_final[
    !is.na(data_final$`hourly_rate (USD)`) &
      !is.na(data_final$gender) &
      data_final$gender != "Unknown",
  ]

  data_bartlett$gender <- factor(data_bartlett$gender)

  if (nlevels(droplevels(data_bartlett$gender)) >= 2) {
    print(
      bartlett.test(
        `hourly_rate (USD)` ~ gender,
        data = data_bartlett
      )
    )
  } else {
    cat("Uji Bartlett tidak dilakukan karena kelompok kurang dari dua.\n")
  }
}
## 
##  Bartlett test of homogeneity of variances
## 
## data:  hourly_rate (USD) by gender
## Bartlett's K-squared = 1.1321, df = 1, p-value = 0.2873

Berdasarkan uji Bartlett di atas, pengujian homogenitas kragam menghasilkan nilai K^2 = 1,1321 dengan derajat bebas (df) = 1 dan nilai signifikansi (p-value) sebesar 0,2873. Karena nilai p-value ini lebih besar dari batas acuan 0,05 (p > 0,05), maka hipotesis nol diterima. Dengan demikian, dapat disimpulkan bahwa varians tarif per jam (hourly rate) antarkelompok jenis kelamin terbukti homogen (sama). Terpenuhinya asumsi homogenitas ini menunjukkan bahwa tingkat keragaman tarif per jam relatif seimbang pada setiap kelompok, sehingga pengujian perbandingan antarvariabel ke depannya dapat dilakukan secara stabil tanpa kendala ketidaksamaan varians.

7.3 Analisis Korelasi

Korelasi Spearman digunakan untuk menilai arah dan kekuatan hubungan monotonik antara pengalaman kerja dan tarif per jam. Analisis dilakukan hanya pada observasi yang memiliki kedua nilai tersebut.

data_korelasi <- data.frame(
  pengalaman = data_final$years_of_experience,
  tarif = data_final$`hourly_rate (USD)`
)

data_korelasi <- data_korelasi[
  complete.cases(data_korelasi),
]

if (nrow(data_korelasi) >= 3 &&
    length(unique(data_korelasi$pengalaman)) > 1 &&
    length(unique(data_korelasi$tarif)) > 1) {

  print(
    cor.test(
      data_korelasi$pengalaman,
      data_korelasi$tarif,
      method = "spearman",
      exact = FALSE
    )
  )
} else {
  cat("Data tidak cukup bervariasi untuk menghitung korelasi.\n")
}
## 
##  Spearman's rank correlation rho
## 
## data:  data_korelasi$pengalaman and data_korelasi$tarif
## S = 98056633, p-value = 0.01678
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## 0.08144109

Berdasarkan uji korelasi Spearman di atas, diperoleh nilai koefisien korelasi rho sebesar 0,05 dengan nilai signifikansi (p-value) sebesar 0,0814. Karena nilai p-value lebih kecil dari batas acuan 0,05 (p< 0,05), maka hubungan antara kedua variabel terbukti signifikan secara statistik.Meskipun hubungannya signifikan, nilai koefisien 0,0814 menunjukkan bahwa tingkat hubungan antara pengalaman kerja dan tarif per jam tergolong sangat lemah namun bernilai positif. Hal ini dapat disimpulkan bahwa bertambahnya pengalaman kerja cenderung diikuti oleh kenaikan tarif per jam, tetapi pengalaman kerja bukanlah satu-satunya faktor utama yang menentukan tinggi rendahnya tarif seorang freelancer di pasar.

8 Integrasi Data

8.1 Pengertian dan Alasan Integrasi

Integrasi data merupakan proses menggabungkan informasi dari berbagai sumber atau tabel yang berbeda agar dapat dianalisis secara terpadu. Pada penelitian ini, integrasi data dilakukan dengan menyatukan seluruh variabel yang telah dibersihkan beserta variabel-variabel turunan baru ke dalam satu dataset utama (data_final) yang siap diolah lebih lanjut.

8.2 Tujuan Integrasi Data

Integrasi data bertujuan untuk menyusun seluruh variabel yang relevan, baik variabel asli yang telah dibersihkan maupun variabel turunan baru ke dalam satu dataset tunggal yang konsisten. Dengan tersedianya basis data yang terstruktur ini, proses pengolahan data menjadi jauh lebih praktis dan efisien. Langkah ini memastikan bahwa seluruh tahapan analisis statistik, mulai dari pengujian hipotesis hingga pembuatan visualisasi grafik, dapat dieksekusi dengan lancar, akurat, serta meminimalkan risiko kesalahan pemanggilan data.

8.3 Encoding Pengalaman Kerja

Agar variabel pengalaman kerja dapat diolah lebih sistematis dalam analisis dan visualisasi data, dilakukan proses pengelompokan (encoding). Langkah ini bertujuan untuk mengategorikan durasi pengalaman kerja para freelancer ke dalam beberapa kelompok skala yang logis dan terstandarisasi. Kategori ini mempermudah kita dalam mengidentifikasi pola distribusi tingkat senioritas serta melihat hubungannya dengan variabel lain secara lebih terstruktur. Pengalaman kerja dikelompokkan menjadi empat kategori. Nilai yang tidak tersedia tetap diberi kategori unknown, sedangkan encoding numerik diberikan pada kategori yang memiliki urutan pengalaman.

data_final$kategori_pengalaman <- ifelse(
  is.na(data_final$years_of_experience),
  "unknown",
  ifelse(
    data_final$years_of_experience <= 10,
    "pemula",
    ifelse(
      data_final$years_of_experience <= 20,
      "menengah",
      ifelse(
        data_final$years_of_experience <= 30,
        "jago",
        "master"
      )
    )
  )
)

data_final$kategori_encode <- match(
  data_final$kategori_pengalaman,
  c("pemula", "menengah", "jago", "master")
)

table(
  data_final$kategori_pengalaman,
  useNA = "ifany"
)
## 
##     jago   master menengah   pemula  unknown 
##      122       55      252      520       51
table(
  data_final$kategori_encode,
  useNA = "ifany"
)
## 
##    1    2    3    4 <NA> 
##  520  252  122   55   51

8.4 Visualisasi Data

# Histogram pengalaman kerja
hist(
  data_final$years_of_experience,
  main = "Distribusi Pengalaman Kerja Freelancer",
  xlab = "Years of Experience",
  col = "#897099",
  border = "white"
)

Berdasarkan histogram sebaran frekuensi di atas, terlihat bahwa sebaran data memiliki pola kemiringan ke kanan (right-skewed distribution). Sebagian besar freelancer berada pada kelompok dengan nilai yang relatif rendah (terfokus pada rentang 0 hingga 5), sementara frekuensinya terus menurun secara bertahap seiring bertambahnya rentang nilai. Pola sebaran yang tidak simetris ini semakin memperkuat analisis sebelumnya bahwa data tidak berdistribusi normal.

# Q-Q plot pengalaman kerja
qqnorm(
  data_final$years_of_experience,
  main = "Q-Q Plot Pengalaman Kerja"
)

qqline(
  na.omit(data_final$years_of_experience),
  col = "#089"
)

Berdasarkan grafik Q-Q Plot di atas, terlihat bahwa titik-titik sampel data tidak berimpit secara sejajar pada garis diagonal merah, melainkan membentuk pola melengkung yang menyimpang cukup signifikan. Penyimpangan yang menonjol pada bagian ujung bawah dan atas menunjukkan sebaran data tidak simetris. Pola lengkungan ini dapat diartikan bahwa data memiliki kecenderungan miring (skewed) dan tidak memenuhi asumsi distribusi normal. Hasil visualisasi ini secara konsisten mendukung temuan dari uji statistik Shapiro-Wilk sebelumnya.

# Scatter plot pengalaman kerja dan tarif per jam
plot(
  data_final$years_of_experience,
  data_final$`hourly_rate (USD)`,
  main = "Pengalaman Kerja dan Hourly Rate",
  xlab = "Years of Experience",
  ylab = "Hourly Rate (USD)",
  pch = 19,
  col = "#00676545"
)

# Garis tren linear sebagai panduan visual
data_plot <- data.frame(
  pengalaman = data_final$years_of_experience,
  tarif = data_final$`hourly_rate (USD)`
)

data_plot <- data_plot[complete.cases(data_plot), ]

if (nrow(data_plot) >= 2 &&
    length(unique(data_plot$pengalaman)) >= 2) {
  abline(
    lm(tarif ~ pengalaman, data = data_plot),
    col = "black",
    lwd = 2
  )
}

Berdasarkan grafik di atas, terlihat bahwa titik-titik data tersebar secara meluas pada berbagai tingkatan pengalaman kerja dan tarif per jam. Garis tren menunjukkan kemiringan positif yang sangat landai, mengartikan adanya kecenderungan bertambahnya tarif per jam seiring meningkatnya masa pengalaman kerja. Keberadaan garis tren yang cenderung mendatar ini menggambarkan bahwa hubungan positif antara pengalaman kerja dan tarif per jam tergolong sangat lemah. Sebagian besar plot juga terkonsentrasi pada tingkat pengalaman di bawah 15 tahun. Visualisasi ini secara konsisten mendukung hasil pengujian korelasi Spearman sebelumnya, yaitu meskipun bertambahnya pengalaman berpengaruh positif terhadap kenaikan tarif, faktor pengalaman bukanlah penentu utama besarnya tarif yang ditetapkan oleh seorang freelancer

8.5 Data Gabungan

Memilih variabel yang tersedia dan relevan untuk analisis. Pemilihan kolom dilakukan berdasarkan nama variabel yang benar-benar terdapat dalam dataset.

kolom_analisis <- c(
  "age",
  "gender",
  "country",
  "years_of_experience",
  "kategori_pengalaman",
  "kategori_encode",
  "hourly_rate (USD)",
  "client_satisfaction",
  "rating",
  "is_active"
)

kolom_tersedia <- intersect(
  kolom_analisis,
  names(data_final)
)

data_analisis <- data_final[
  ,
  kolom_tersedia,
  drop = FALSE
]

cat("Dimensi data analisis:\n")
## Dimensi data analisis:
print(dim(data_analisis))
## [1] 1000   10
cat("\nKolom yang digunakan:\n")
## 
## Kolom yang digunakan:
print(names(data_analisis))
##  [1] "age"                 "gender"              "country"            
##  [4] "years_of_experience" "kategori_pengalaman" "kategori_encode"    
##  [7] "hourly_rate (USD)"   "client_satisfaction" "rating"             
## [10] "is_active"
head(data_analisis)
## # A tibble: 6 × 10
##     age gender country   years_of_experience kategori_pengalaman kategori_encode
##   <dbl> <chr>  <chr>                   <dbl> <chr>                         <int>
## 1    52 Female Italy                      11 menengah                          2
## 2    52 Female Australia                  34 master                            4
## 3    53 Male   Germany                    31 master                            4
## 4    38 Female Australia                   4 pemula                            1
## 5    53 Female Germany                    27 jago                              3
## 6    59 Female Netherla…                  14 menengah                          2
## # ℹ 4 more variables: `hourly_rate (USD)` <dbl>, client_satisfaction <dbl>,
## #   rating <dbl>, is_active <chr>

9 Transformasi Numerik

Transformasi numerik dilakukan untuk menyeimbangkan skala dan memperbaiki sebaran data pada variabel pengalaman kerja dan tarif per jam. Proses ini menerapkan tiga teknik utama, yaitu normalisasi Min-Max untuk menyelaraskan rentang ke skala 0–1, standardisasi Z-Score untuk mengukur posisi relatif terhadap rata-rata, serta transformasi invers kuadrat untuk meredam pemencengan distribusi. Hasil dari transformasi ini memastikan seluruh variabel siap digunakan dalam pengujian statistik dan analisis korelasi secara akurat.

9.1 Normalisasi Min-Max

# Load library pendukung 
library(dplyr)
library(ggplot2)

# 1. Pemeriksaan Rentang Data Awal
data_final %>%
  summarise(
    across(
      c(years_of_experience_clean, hourly_rate_clean),
      list(
        min = ~ min(.x, na.rm = TRUE),
        max = ~ max(.x, na.rm = TRUE)
      )
    )
  )
## # A tibble: 1 × 4
##   years_of_experience_clean_min years_of_experience_clea…¹ hourly_rate_clean_min
##                           <dbl>                      <dbl>                 <dbl>
## 1                             0                         41                    20
## # ℹ abbreviated name: ¹​years_of_experience_clean_max
## # ℹ 1 more variable: hourly_rate_clean_max <dbl>
# 2. Definisi Fungsi dan Penerapan Min-Max
min_max <- function(x) {
  (x - min(x, na.rm = TRUE)) / (max(x, na.rm = TRUE) - min(x, na.rm = TRUE))
}

data_final <- data_final %>%
  mutate(
    exp_minmax  = min_max(years_of_experience_clean),
    rate_minmax = min_max(hourly_rate_clean)
  )

# Output Ringkas Min-Max
cat(" HASIL NORMALISASI MIN-MAX \n")
##  HASIL NORMALISASI MIN-MAX
cat("Rentang Exp Min-Max  :", min(data_final$exp_minmax), "-", max(data_final$exp_minmax), "\n")
## Rentang Exp Min-Max  : 0 - 1
cat("Rentang Rate Min-Max :", min(data_final$rate_minmax), "-", max(data_final$rate_minmax), "\n")
## Rentang Rate Min-Max : 0 - 1

Hasil pemeriksaan rentang data awal menunjukkan bahwa variabel pengalaman kerja (years_of_experience_clean) memiliki rentang nilai asli dari 0 hingga 41 tahun, sedangkan variabel tarif per jam (hourly_rate_clean) berada pada rentang 20 hingga 100 USD per jam. Keberadaan nilai minimum 0 tahun pada variabel pengalaman kerja menjadi alasan teknis digunakannya penambahan konstanta + 1 pada rumus transformasi invers kuadrat untuk mencegah kesalahan komputasi akibat pembagian dengan nol (division by zero).

Setelah diterapkan metode normalisasi Min-Max, kedua variabel tersebut berhasil diselaraskan ke dalam rentang skala acuan yang seragam, yaitu 0 hingga 1 (Rentang Exp Min-Max: 0 - 1 dan Rentang Rate Min-Max: 0 - 1). Transformasi ini memetakan nilai terendah menjadi angka 0 dan nilai tertinggi menjadi angka 1, sehingga variabel pengalaman kerja dan tarif per jam yang memiliki perbedaan satuan serta skala asal kini dapat dibandingkan secara seimbang tanpa mengubah proporsi sebaran data aslinya.

9.2 Standardisasi Z-Score

data_final <- data_final %>%
  mutate(
    exp_z  = as.numeric(scale(years_of_experience_clean)),
    rate_z = as.numeric(scale(hourly_rate_clean))
  )

# Verifikasi Hasil Z-Score
cat(" HASIL VERIFIKASI Z-SCORE \n")
##  HASIL VERIFIKASI Z-SCORE
cat("Rata-rata Z-Score Exp  :", round(mean(data_final$exp_z, na.rm = TRUE), 4), "\n")
## Rata-rata Z-Score Exp  : 0
cat("Standar Deviasi Z Exp  :", sd(data_final$exp_z, na.rm = TRUE), "\n")
## Standar Deviasi Z Exp  : 1
cat("Rata-rata Z-Score Rate :", round(mean(data_final$rate_z, na.rm = TRUE), 4), "\n")
## Rata-rata Z-Score Rate : 0
cat("Standar Deviasi Z Rate :", sd(data_final$rate_z, na.rm = TRUE), "\n")
## Standar Deviasi Z Rate : 1

Hasil standardisasi Z-Score menunjukkan bahwa variabel pengalaman kerja dan tarif per jam telah berhasil diselaraskan secara sempurna, di mana kedua variabel kini memiliki rata-rata bernilai 0 dan standar deviasi sebesar 1. Penyelarasan ini membuktikan bahwa proses pembentukan skala standar telah berjalan secara akurat. Dengan demikian, nilai pengalaman kerja dan tarif jasa setiap freelancer tidak lagi dilihat berdasarkan satuan aslinya (tahun atau USD), melainkan diukur berdasarkan posisi relatifnya terhadap rata-rata kelompok, nilai positif menunjukkan posisi di atas rata-rata kelompok, nilai negatif menunjukkan posisi di bawah rata-rata kelompok, dan nilai nol menandakan posisi yang tepat berada di rata-rata kelompok.

9.3 Transformasi Invers & Konsolidasi Data

# 1. Pengecekan Keamanan Nilai Nol
data_final %>%
  summarise(
    min_val    = min(years_of_experience_clean, na.rm = TRUE),
    jumlah_nol = sum(years_of_experience_clean == 0, na.rm = TRUE)
  )
## # A tibble: 1 × 2
##   min_val jumlah_nol
##     <dbl>      <int>
## 1       0         72
# 2. Transformasi Inverse Square (+1 Proteksi Pembagian 1/0)
data_final <- data_final %>%
  mutate(
    exp_inv_sq  = 1 / ((years_of_experience_clean + 1)^2),
    rate_inv_sq = 1 / ((hourly_rate_clean + 1)^2)
  )

# 3. Visualisasi Distribusi Sebelum Transformasi Invers
ggplot(data_final, aes(x = years_of_experience_clean)) +
  geom_histogram(bins = 20, fill = "#435667", color = "#986") +
  labs(
    title = "Distribusi Pengalaman Kerja Sebelum Transformasi",
    x = "Pengalaman Kerja (Tahun)",
    y = "Frekuensi"
  ) +
  theme_minimal()

ggplot(data_final, aes(x = exp_inv_sq)) +
  geom_histogram(bins = 20, fill = "#930", color = "#278") +
  labs(
    title = "Sesudah Transformasi (Inverse Square)",
    x = "Nilai Inverse Square",
    y = "Frekuensi"
  ) +
  theme_minimal()

# 4. Konsolidasi & Evaluasi Ringkasan Statistik
data_transformasi <- data_final %>%
  mutate(
    exp_minmax  = min_max(years_of_experience_clean),
    exp_z       = as.numeric(scale(years_of_experience_clean)),
    exp_inv_sq  = 1 / ((years_of_experience_clean + 1)^2),
    rate_minmax = min_max(hourly_rate_clean),
    rate_z      = as.numeric(scale(hourly_rate_clean)),
    rate_inv_sq = 1 / ((hourly_rate_clean + 1)^2)
  )

# Ringkasan Evaluasi Terpadu (Dicetak Langsung)
evaluasi_stat <- data_transformasi %>%
  summarise(
    Mean_Exp_Asli   = round(mean(years_of_experience_clean, na.rm = TRUE), 2),
    SD_Exp_Asli     = round(sd(years_of_experience_clean, na.rm = TRUE), 2),
    Min_Exp_MinMax  = min(exp_minmax, na.rm = TRUE),
    Max_Exp_MinMax  = max(exp_minmax, na.rm = TRUE),
    Mean_Exp_Z      = round(mean(exp_z, na.rm = TRUE), 4),
    SD_Exp_Z        = sd(exp_z, na.rm = TRUE),
    Mean_Rate_Asli  = round(mean(hourly_rate_clean, na.rm = TRUE), 2),
    SD_Rate_Asli    = round(sd(hourly_rate_clean, na.rm = TRUE), 2)
  )

print(evaluasi_stat)
## # A tibble: 1 × 8
##   Mean_Exp_Asli SD_Exp_Asli Min_Exp_MinMax Max_Exp_MinMax Mean_Exp_Z SD_Exp_Z
##           <dbl>       <dbl>          <dbl>          <dbl>      <dbl>    <dbl>
## 1          11.2        9.44              0              1          0        1
## # ℹ 2 more variables: Mean_Rate_Asli <dbl>, SD_Rate_Asli <dbl>

Pemeriksaan awal terhadap data pengalaman kerja menunjukkan nilai minimum sebesar 0 tahun dengan total 72 freelancer yang berada di titik tersebut. Temuan ini menjadi alasan teknis digunakannya rumus 1/(x+1)^2 pada transformasi invers kuadrat, di mana penambahan angka 1 berfungsi untuk mencegah kesalahan komputasi akibat pembagian dengan nilai nol (division by zero). Di sisi lain, grafik histogram memperlihatkan sebaran data yang miring ke kanan (right-skewed), yang berarti mayoritas freelancer masih berada di tingkat pengalaman awal (0–10 tahun) dan jumlahnya terus menurun hingga pengalaman tertinggi mencapai 41 tahun.

Berdasarkan ringkasan statistik terpadu, data pengalaman kerja sebelum ditransformasi memiliki rata-rata 11,21 tahun dengan tingkat variasi atau standar deviasi sebesar 9,44 tahun. Setelah dilakukan transformasi, seluruh metode terbukti berhasil menjalankan fungsinya dengan akurat, di mana metode Min-Max berhasil menyelaraskan data ke dalam rentang 0 hingga 1, standardisasi Z-Score berhasil memusatkan rata-rata data pada nilai 0 dengan standar deviasi tepat sebesar 1, serta transformasi invers kuadrat berhasil meredam pemencengan data ekor kanan agar sebarannya menjadi lebih seimbang.

10 Penyimpanan Dataset

Dataset yang telah melalui proses transformasi dan penyelarasan skala selanjutnya disimpan ke dalam berkas berformat CSV agar mempermudah pemanggilan data pada analisis korelasi dan visualisasi tingkat lanjut.

10.1 Menyimpan Dataset Final

Proses transformasi numerik dan penyelarasan skala data telah selesai dilakukan dengan baik. Sebagai langkah penutup, dataset hasil akhir yang telah bersih dan ditransformasi ini disimpan ke dalam berkas berformat CSV dengan nama data_analisis_final.csv.

nama_file_output <- "data_analisis_final.csv"

write.csv(
  data_analisis,
  nama_file_output,
  row.names = FALSE,
  na = ""
)

cat(
  "Proses selesai. File disimpan di:\n",
  normalizePath(nama_file_output, mustWork = FALSE),
  "\n"
)
## Proses selesai. File disimpan di:
##  C:\Users\MSI Modern 14\Downloads\data_analisis_final.csv

10.2 Pemeriksaan Dataset Final

Dataset final data_analisis_final.csv telah terverifikasi bersih, konsisten, dan memenuhi seluruh kriteria teknis.

cat("Dimensi dataset final:\n")
## Dimensi dataset final:
print(dim(data_final))
## [1] 1000   22
cat("\nStruktur dataset final:\n")
## 
## Struktur dataset final:
str(data_final)
## tibble [1,000 × 22] (S3: tbl_df/tbl/data.frame)
##  $ freelancer_ID            : chr [1:1000] "FL250001" "FL250002" "FL250003" "FL250004" ...
##  $ name                     : chr [1:1000] "Ms. Nicole Kidd" "Vanessa Garcia" "Juan Nelson" "Amanda Spencer" ...
##  $ gender                   : chr [1:1000] "Female" "Female" "Male" "Female" ...
##  $ age                      : num [1:1000] 52 52 53 38 53 59 52 43 26 52 ...
##  $ country                  : chr [1:1000] "Italy" "Australia" "Germany" "Australia" ...
##  $ language                 : chr [1:1000] "Italian" "English" "German" "English" ...
##  $ primary_skill            : chr [1:1000] "Blockchain Development" "Mobile Apps" "Graphic Design" "Web Development" ...
##  $ years_of_experience      : num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
##  $ hourly_rate (USD)        : num [1:1000] 100 100 50 40 30 30 75 40 NA 50 ...
##  $ rating                   : num [1:1000] NA 3.3 0 1.5 4.8 2.4 3.1 4.6 4 NA ...
##  $ is_active                : chr [1:1000] "tidak aktif" "aktif" "tidak aktif" "tidak aktif" ...
##  $ client_satisfaction      : num [1:1000] NA 84 71 90 83 NA 94 94 76 NA ...
##  $ years_of_experience_clean: num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
##  $ hourly_rate_clean        : num [1:1000] 100 100 50 40 30 30 75 40 40 50 ...
##  $ kategori_pengalaman      : chr [1:1000] "menengah" "master" "master" "pemula" ...
##  $ kategori_encode          : int [1:1000] 2 4 4 1 3 2 1 2 1 3 ...
##  $ exp_minmax               : num [1:1000] 0.2683 0.8293 0.7561 0.0976 0.6585 ...
##  $ rate_minmax              : num [1:1000] 1 1 0.375 0.25 0.125 ...
##  $ exp_z                    : num [1:1000] -0.0234 2.4119 2.0943 -0.7646 1.6707 ...
##  $ rate_z                   : num [1:1000] 1.8549 1.8549 -0.0491 -0.4299 -0.8107 ...
##  $ exp_inv_sq               : num [1:1000] 0.006944 0.000816 0.000977 0.04 0.001276 ...
##  $ rate_inv_sq              : num [1:1000] 0.000098 0.000098 0.000384 0.000595 0.001041 ...
cat("\nMissing value per variabel:\n")
## 
## Missing value per variabel:
print(colSums(is.na(data_final)))
##             freelancer_ID                      name                    gender 
##                         0                         0                         0 
##                       age                   country                  language 
##                        30                         0                         0 
##             primary_skill       years_of_experience         hourly_rate (USD) 
##                         0                        51                        94 
##                    rating                 is_active       client_satisfaction 
##                       101                        89                       176 
## years_of_experience_clean         hourly_rate_clean       kategori_pengalaman 
##                         0                         0                         0 
##           kategori_encode                exp_minmax               rate_minmax 
##                        51                         0                         0 
##                     exp_z                    rate_z                exp_inv_sq 
##                         0                         0                         0 
##               rate_inv_sq 
##                         0
cat("\nLima baris pertama:\n")
## 
## Lima baris pertama:
head(data_final)
## # A tibble: 6 × 22
##   freelancer_ID name            gender   age country     language primary_skill 
##   <chr>         <chr>           <chr>  <dbl> <chr>       <chr>    <chr>         
## 1 FL250001      Ms. Nicole Kidd Female    52 Italy       Italian  Blockchain De…
## 2 FL250002      Vanessa Garcia  Female    52 Australia   English  Mobile Apps   
## 3 FL250003      Juan Nelson     Male      53 Germany     German   Graphic Design
## 4 FL250004      Amanda Spencer  Female    38 Australia   English  Web Developme…
## 5 FL250005      Lynn Curtis DDS Female    53 Germany     German   Web Developme…
## 6 FL250006      Lisa Johnson    Female    59 Netherlands Dutch    AI            
## # ℹ 15 more variables: years_of_experience <dbl>, `hourly_rate (USD)` <dbl>,
## #   rating <dbl>, is_active <chr>, client_satisfaction <dbl>,
## #   years_of_experience_clean <dbl>, hourly_rate_clean <dbl>,
## #   kategori_pengalaman <chr>, kategori_encode <int>, exp_minmax <dbl>,
## #   rate_minmax <dbl>, exp_z <dbl>, rate_z <dbl>, exp_inv_sq <dbl>,
## #   rate_inv_sq <dbl>

11 Kesimpulan

Proses evaluasi terhadap Global Freelancers Dataset berhasil mengidentifikasi berbagai permasalahan kualitas data, seperti keberadaan nilai yang hilang (missing value), data duplikat, inkonsistensi penulisan variabel kategorikal, serta karakter non-numerik pada kolom angka. Tahapan preprocessing telah menyelesaikan masalah tersebut melalui penyeragaman format, penghapusan duplikasi, dan imputasi median pada variabel numerik. Setelah pembersihan, karakteristik pengalaman kerja dipetakan secara terstruktur ke dalam empat kategori ordinal (Pemula, Menengah, Jago, dan Master), di mana sebaran dan tingkat normalitas datanya dievaluasi menggunakan uji Shapiro-Wilk serta QQ Plot.

Secara khusus, analisis hubungan antara pengalaman kerja (years of experience) dan tarif per jam (hourly rate) yang digambarkan melalui scatter plot dan garis regresi linear menunjukkan tren hubungan positif. Hal ini mengindikasikan bahwa semakin lama pengalaman kerja yang dimiliki seorang freelancer, cenderung semakin tinggi pula tarif per jam yang ditawarkannya. Namun, sebaran titik data di sekitar garis tren memperlihatkan variabilitas, yang menegaskan bahwa pengalaman kerja merupakan salah satu faktor pendorong tarif, tetapi bukan satu-satunya penentu tunggal karena adanya pengaruh variabel lain seperti rating atau kepuasan klien.

Secara keseluruhan, seluruh tujuan analisis telah terpenuhi melalui penerapan pembersihan data, pengelompokan variabel, pengujian asumsi statistik (termasuk homogenitas varians Bartlett), hingga transformasi numerik (Min-Max, Z-Score, dan Inverse Square). Hasil akhirnya adalah dataset analisis final (data_analisis_final.csv) yang bersih, tervalidasi, serta siap dijadikan acuan untuk pemodelan statistik maupun pengambilan keputusan di industri freelance.

12 Referensi

[1] Velleman, P. F. & Hoaglin, D. C. (2004). Applications, Basics, and Computing of Exploratory Data Analysis. Duxbury Press. [2] Tukey, J. W. (1993). Exploratory Data Analysis: Past, Present and Future. Princeton University. [3] Ahir, U. (2024). Global Freelancers (Raw) Dataset [Data set]. Kaggle. https://www.kaggle.com/datasets/urvishahir/global-freelancers-raw-dataset