Pasar kerja lepas global kini berkembang pesat seiring meluasnya platform daring yang mempertemukan penyedia jasa dengan klien lintas negara. Data profil pekerja pada platform semacam itu berguna untuk mengetahui siapa saja yang terlibat, seberapa berpengalaman mereka, berapa tarif yang ditetapkan, serta bagaimana klien menilai hasil kerjanya.
Namun, data yang dihimpun dari berbagai sumber jarang langsung dalam
keadaan rapi. Global Freelancers Dataset dari Kaggle yang
digunakan dalam laporan ini, dengan 1.000 baris data dan 12 variabel,
masih tergolong data mentah. Di dalamnya dijumpai nilai kosong,
penulisan kategori yang berbeda-beda untuk makna yang sama, dan angka
yang tercampur simbol seperti $, USD, dan
%. Selain itu, masih perlu dipastikan apakah terdapat baris
ganda dan nilai yang tidak wajar.
Analisis yang dilakukan di atas data seperti itu dapat menghasilkan kesimpulan yang keliru. Oleh karena itu, data terlebih dahulu dibenahi melalui tahapan data wrangling, yaitu pembersihan, transformasi, dan integrasi, hingga terbentuk dataset yang konsisten. Dataset tersebut kemudian digunakan untuk menelaah karakteristik pengalaman kerja dan tarif per jam, memeriksa asumsi statistik, serta melihat keterkaitan antara keduanya.
Data diperoleh dari Kaggle dengan nama Global Freelancers Dataset yang diunggah oleh Urvish Ahir (https://www.kaggle.com/datasets/urvishahir/global-freelancers-raw-dataset). Setiap baris mewakili satu freelancer, dengan 1.000 baris data dan 12 variabel sebagai berikut.
| Variabel | Keterangan | Jenis Data | Skala |
|---|---|---|---|
| freelancer_ID | ID unik freelancer | Kualitatif | Nominal |
| name | Nama freelancer | Kualitatif | Nominal |
| gender | Jenis kelamin | Kualitatif | Nominal |
| age | Usia freelancer | Kuantitatif kontinu | Rasio |
| country | Negara asal | Kualitatif | Nominal |
| language | Bahasa utama | Kualitatif | Nominal |
| primary_skill | Keahlian utama | Kualitatif | Nominal |
| years_of_experience | Lama pengalaman kerja (tahun) | Kuantitatif diskrit | Rasio |
| hourly_rate (USD) | Tarif per jam (USD) | Kuantitatif kontinu | Rasio |
| rating | Rating freelancer (0-5) | Kuantitatif kontinu | Interval |
| is_active | Status keaktifan | Kualitatif | Nominal |
| client_satisfaction | Tingkat kepuasan klien | Kuantitatif kontinu | Rasio |
Tahap pertama adalah memuat file Excel ke dalam R. File diletakkan satu folder dengan dokumen ini, sehingga lokasinya cukup ditulis dengan nama file. Apabila file tidak ditemukan, proses dihentikan dan muncul pesan peringatan.
Setelah data berhasil dimuat, struktur awalnya diperiksa, meliputi jumlah baris dan kolom, nama variabel, tipe data, dan ringkasan statistik. Keluaran ini menggambarkan kondisi data mentah sebelum diolah, termasuk variabel yang masih terbaca sebagai teks.
## Jumlah baris: 1000
## Jumlah kolom: 12
## [1] "freelancer_ID" "name" "gender"
## [4] "age" "country" "language"
## [7] "primary_skill" "years_of_experience" "hourly_rate (USD)"
## [10] "rating" "is_active" "client_satisfaction"
## 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 ...
## # 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>
## # A tibble: 6 × 12
## freelancer_ID name gender age country language primary_skill
## <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 FL250995 Jennifer Hinton Female 34.0 South Africa Afrikaa… DevOps
## 2 FL250996 Albert Wilcox Male 56.0 Turkey Turkish DevOps
## 3 FL250997 Cheryl Norris f 26.0 Germany German Blockchain D…
## 4 FL250998 Kathy Watkins female 37.0 Japan Japanese Data Analysis
## 5 FL250999 John Obrien m 46.0 Russia Russian Machine Lear…
## 6 FL251000 Dawn Green Female 36.0 Mexico Spanish UI/UX Design
## # ℹ 5 more variables: years_of_experience <chr>, `hourly_rate (USD)` <chr>,
## # rating <chr>, is_active <chr>, client_satisfaction <dbl>
## freelancer_ID name gender age
## Length :1000 Length :1000 Length :1000 Length :1000
## N.unique :1000 N.unique : 992 N.unique : 10 N.unique : 41
## N.blank : 0 N.blank : 0 N.blank : 0 N.blank : 0
## Min.nchar: 8 Min.nchar: 7 Min.nchar: 1 Min.nchar: 4
## Max.nchar: 8 Max.nchar: 25 Max.nchar: 6 Max.nchar: 4
## NAs : 30
##
## country language primary_skill years_of_experience
## Length :1000 Length :1000 Length :1000 Length :1000
## N.unique : 21 N.unique : 16 N.unique : 10 N.unique : 41
## N.blank : 0 N.blank : 0 N.blank : 0 N.blank : 0
## Min.nchar: 5 Min.nchar: 5 Min.nchar: 2 Min.nchar: 3
## Max.nchar: 14 Max.nchar: 10 Max.nchar: 22 Max.nchar: 4
## NAs : 51
##
## hourly_rate (USD) rating is_active client_satisfaction
## Length :1000 Length :1000 Length :1000 Min. : 0.60
## N.unique : 18 N.unique : 42 N.unique : 8 1st Qu.: 0.71
## N.blank : 0 N.blank : 0 N.blank : 0 Median : 0.82
## Min.nchar: 2 Min.nchar: 3 Min.nchar: 1 Mean : 11.73
## Max.nchar: 7 Max.nchar: 3 Max.nchar: 5 3rd Qu.: 0.94
## NAs : 94 NAs : 101 NAs : 89 Max. :100.00
## NAs :176
Nilai hilang dihitung pada setiap variabel, baik dalam jumlah maupun persentase. Variabel dengan persentase nilai hilang yang besar perlu mendapat perhatian lebih pada tahap penanganan.
## freelancer_ID name gender age
## 0 0 0 30
## country language primary_skill years_of_experience
## 0 0 0 51
## hourly_rate (USD) rating is_active client_satisfaction
## 94 101 89 176
## freelancer_ID name gender age
## 0.0 0.0 0.0 3.0
## country language primary_skill years_of_experience
## 0.0 0.0 0.0 5.1
## hourly_rate (USD) rating is_active client_satisfaction
## 9.4 10.1 8.9 17.6
## Total missing value: 541
Variabel gender ditulis dengan beragam bentuk untuk
kategori yang sama, misalnya f, F, dan
female. Penulisan tersebut diseragamkan menjadi
Female dan Male agar jumlah pada setiap
kelompok dapat dihitung dengan benar.
##
## f F female Female FEMALE m M male Male MALE
## 103 90 86 96 115 99 106 100 103 102
ADE$gender <- tolower(trimws(as.character(ADE$gender)))
ADE$gender[ADE$gender %in% c("f", "female")] <- "Female"
ADE$gender[ADE$gender %in% c("m", "male")] <- "Male"
table(ADE$gender, useNA = "ifany")##
## Female Male
## 490 510
Tarif per jam masih bercampur dengan simbol $ dan
tulisan USD, sehingga terbaca sebagai teks dan tidak dapat
dihitung. Simbol tersebut dihapus, kemudian variabel diubah menjadi
angka.
## [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"
ADE$`hourly_rate (USD)` <- gsub("\\$", "", as.character(ADE$`hourly_rate (USD)`))
ADE$`hourly_rate (USD)` <- gsub("USD", "", ADE$`hourly_rate (USD)`, ignore.case = TRUE)
ADE$`hourly_rate (USD)` <- trimws(ADE$`hourly_rate (USD)`)
ADE$`hourly_rate (USD)` <- as.numeric(ADE$`hourly_rate (USD)`)
str(ADE$`hourly_rate (USD)`)## num [1:1000] 100 100 50 40 30 30 75 40 NA 50 ...
Tanda persen dibuang lalu kolom dijadikan numerik. Pada data ini skalanya tidak seragam: sebagian nilai ditulis dalam skala 0 sampai 1 (misalnya 0,84) dan sebagian dalam skala 0 sampai 100 (misalnya 84). Nilai di atas 1 karena itu dibagi 100 agar semuanya berada pada skala 0 sampai 1. Nilai kosong yang tersisa diisi dengan median, karena median tidak mudah terpengaruh oleh nilai ekstrem.
## [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("%", "", as.character(ADE$client_satisfaction))
ADE$client_satisfaction <- trimws(ADE$client_satisfaction)
ADE$client_satisfaction <- as.numeric(ADE$client_satisfaction)
str(ADE$client_satisfaction)## num [1:1000] NA 0.84 0.71 0.9 0.83 NA 0.94 0.94 0.76 NA ...
# Menyamakan skala: nilai 0-100 diubah ke skala 0-1
cat("Nilai di atas 1 (skala 0-100):",
sum(ADE$client_satisfaction > 1, na.rm = TRUE), "\n")## Nilai di atas 1 (skala 0-100): 114
skala_besar <- !is.na(ADE$client_satisfaction) &
ADE$client_satisfaction > 1
ADE$client_satisfaction[skala_besar] <-
ADE$client_satisfaction[skala_besar] / 100
summary(ADE$client_satisfaction)## Min. 1st Qu. Median Mean 3rd Qu. Max. NAs
## 0.6000 0.6975 0.7900 0.7927 0.8900 1.0000 176
## [1] 176
median_satisfaction <- median(ADE$client_satisfaction, na.rm = TRUE)
ADE$client_satisfaction[is.na(ADE$client_satisfaction)] <- median_satisfaction
summary(ADE$client_satisfaction)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.6000 0.7100 0.7900 0.7922 0.8700 1.0000
## [1] 0
Variabel usia, pengalaman kerja, dan rating masih terbaca sebagai teks sehingga perlu diubah menjadi angka. Langkah wrangling yang sama diterapkan pada ketiganya, yaitu membuang tanda yang tidak diperlukan dan mengonversi tipe datanya.
## [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("%", "", as.character(ADE$age))
ADE$age <- trimws(ADE$age)
ADE$age <- as.numeric(ADE$age)
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("%", "", as.character(ADE$years_of_experience))
ADE$years_of_experience <- trimws(ADE$years_of_experience)
ADE$years_of_experience <- as.numeric(ADE$years_of_experience)
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("%", "", as.character(ADE$rating))
ADE$rating <- trimws(ADE$rating)
ADE$rating <- as.numeric(ADE$rating)
str(ADE[, c("age", "years_of_experience", "rating")])## tibble [1,000 × 3] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:1000] 52 52 53 38 53 59 52 43 26 52 ...
## $ years_of_experience: num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
## $ rating : num [1:1000] NA 3.3 0 1.5 4.8 2.4 3.1 4.6 4 NA ...
Status keaktifan ditulis dalam banyak bentuk (1,
Y, yes, True, dan sejenisnya).
Seluruhnya disatukan menjadi Active atau
Inactive, sedangkan nilai yang tidak dapat dikenali diberi
label Unknown.
##
## 0 1 FALSE N no TRUE Y yes <NA>
## 182 190 97 98 88 77 94 85 89
active_raw <- tolower(trimws(as.character(ADE$is_active)))
ADE$is_active <- ifelse(
active_raw %in% c("1", "y", "yes", "true"),
"Active",
ifelse(
active_raw %in% c("0", "n", "no", "false"),
"Inactive",
NA_character_
)
)
ADE$is_active[is.na(ADE$is_active)] <- "Unknown"
table(ADE$is_active, useNA = "ifany")##
## Active Inactive Unknown
## 446 465 89
## [1] 0
Baris yang sama persis lebih dari satu kali dapat membuat hasil analisis menjadi berlebih. Karena itu, jumlah baris ganda dihitung terlebih dahulu, kemudian dihapus apabila ada.
## [1] 0
## # A tibble: 0 × 12
## # ℹ 12 variables: freelancer_ID <chr>, name <chr>, gender <chr>, age <dbl>,
## # country <chr>, language <chr>, primary_skill <chr>,
## # years_of_experience <dbl>, hourly_rate (USD) <dbl>, rating <dbl>,
## # is_active <chr>, client_satisfaction <dbl>
## [1] 0
## [1] 1000 12
Pemeriksaan ini memastikan setiap nilai berada pada rentang yang masuk akal, misalnya usia tidak negatif dan rating tidak melebihi 5. Rating bernilai 0 juga dicatat karena maknanya ambigu: dapat berarti penilaian terendah atau belum adanya penilaian. Nilai tersebut tetap dipertahankan karena masih berada dalam rentang 0 sampai 5.
## Min. 1st Qu. Median Mean 3rd Qu. Max. NAs
## 20.00 31.00 41.00 40.51 51.00 60.00 30
## [1] 0
## [1] 0
## Min. 1st Qu. Median Mean 3rd Qu. Max. NAs
## 0.00 3.00 9.00 11.34 17.00 41.00 51
## [1] 0
## Min. 1st Qu. Median Mean 3rd Qu. Max. NAs
## 0.000 1.400 2.600 2.513 3.800 5.000 101
## [1] 0
## [1] 0
## [1] 145
## Min. 1st Qu. Median Mean 3rd Qu. Max. NAs
## 20.00 30.00 40.00 52.46 75.00 100.00 94
## [1] 0
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.6000 0.7100 0.7900 0.7922 0.8700 1.0000
## [1] 0
## [1] 0
Data yang telah diseragamkan disalin ke objek baru bernama
data_clean, sehingga data hasil wrangling tersimpan
terpisah dari tahap imputasi. Struktur dan ringkasannya ditampilkan
untuk memastikan tipe data sudah sesuai.
## 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] "Inactive" "Active" "Inactive" "Inactive" ...
## $ client_satisfaction: num [1:1000] 0.79 0.84 0.71 0.9 0.83 0.79 0.94 0.94 0.76 0.79 ...
## [1] 1000 12
## freelancer_ID name gender age
## Length :1000 Length :1000 Length :1000 Min. :20.00
## N.unique :1000 N.unique : 992 N.unique : 2 1st Qu.:31.00
## N.blank : 0 N.blank : 0 N.blank : 0 Median :41.00
## Min.nchar: 8 Min.nchar: 7 Min.nchar: 4 Mean :40.51
## Max.nchar: 8 Max.nchar: 25 Max.nchar: 6 3rd Qu.:51.00
## Max. :60.00
## NAs :30
## country language primary_skill years_of_experience
## Length :1000 Length :1000 Length :1000 Min. : 0.00
## N.unique : 21 N.unique : 16 N.unique : 10 1st Qu.: 3.00
## N.blank : 0 N.blank : 0 N.blank : 0 Median : 9.00
## Min.nchar: 5 Min.nchar: 5 Min.nchar: 2 Mean :11.34
## Max.nchar: 14 Max.nchar: 10 Max.nchar: 22 3rd Qu.:17.00
## Max. :41.00
## NAs :51
## hourly_rate (USD) rating is_active client_satisfaction
## Min. : 20.00 Min. :0.000 Length :1000 Min. :0.6000
## 1st Qu.: 30.00 1st Qu.:1.400 N.unique : 3 1st Qu.:0.7100
## Median : 40.00 Median :2.600 N.blank : 0 Median :0.7900
## Mean : 52.46 Mean :2.513 Min.nchar: 6 Mean :0.7922
## 3rd Qu.: 75.00 3rd Qu.:3.800 Max.nchar: 8 3rd Qu.:0.8700
## Max. :100.00 Max. :5.000 Max. :1.0000
## NAs :94 NAs :101
Nilai hilang pada pengalaman kerja, tarif per jam, dan rating diganti dengan median. Median dipilih karena tidak mudah terpengaruh oleh nilai ekstrem. Hasilnya diperiksa dengan menghitung sisa nilai hilang pada ketiga variabel tersebut, yang seharusnya bernilai nol.
# Years of experience
if (any(!is.na(data_clean$years_of_experience))) {
median_exp <- median(data_clean$years_of_experience, na.rm = TRUE)
data_clean$years_of_experience_clean <- ifelse(
is.na(data_clean$years_of_experience),
median_exp,
data_clean$years_of_experience
)
} else {
data_clean$years_of_experience_clean <- data_clean$years_of_experience
}
# Hourly rate
if (any(!is.na(data_clean$`hourly_rate (USD)`))) {
median_rate <- median(data_clean$`hourly_rate (USD)`, na.rm = TRUE)
data_clean$hourly_rate_clean <- ifelse(
is.na(data_clean$`hourly_rate (USD)`),
median_rate,
data_clean$`hourly_rate (USD)`
)
} else {
data_clean$hourly_rate_clean <- data_clean$`hourly_rate (USD)`
}
# Rating
if (any(!is.na(data_clean$rating))) {
median_rating <- median(data_clean$rating, na.rm = TRUE)
data_clean$rating[is.na(data_clean$rating)] <- median_rating
}
# Cek hasil imputasi
sum(is.na(data_clean$years_of_experience_clean))## [1] 0
## [1] 0
## [1] 0
Bagian ini mengulang pemeriksaan permasalahan data pada
data_clean untuk memastikan perbaikan telah berhasil.
Hitungan baris ganda dan nilai di luar rentang seharusnya bernilai
nol.
## 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] 2.6 3.3 0 1.5 4.8 2.4 3.1 4.6 4 2.6 ...
## $ is_active : chr [1:1000] "Inactive" "Active" "Inactive" "Inactive" ...
## $ client_satisfaction : num [1:1000] 0.79 0.84 0.71 0.9 0.83 0.79 0.94 0.94 0.76 0.79 ...
## $ 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 ...
## [1] 1000 14
## freelancer_ID name gender age
## Length :1000 Length :1000 Length :1000 Min. :20.00
## N.unique :1000 N.unique : 992 N.unique : 2 1st Qu.:31.00
## N.blank : 0 N.blank : 0 N.blank : 0 Median :41.00
## Min.nchar: 8 Min.nchar: 7 Min.nchar: 4 Mean :40.51
## Max.nchar: 8 Max.nchar: 25 Max.nchar: 6 3rd Qu.:51.00
## Max. :60.00
## NAs :30
## country language primary_skill years_of_experience
## Length :1000 Length :1000 Length :1000 Min. : 0.00
## N.unique : 21 N.unique : 16 N.unique : 10 1st Qu.: 3.00
## N.blank : 0 N.blank : 0 N.blank : 0 Median : 9.00
## Min.nchar: 5 Min.nchar: 5 Min.nchar: 2 Mean :11.34
## Max.nchar: 14 Max.nchar: 10 Max.nchar: 22 3rd Qu.:17.00
## Max. :41.00
## NAs :51
## hourly_rate (USD) rating is_active client_satisfaction
## Min. : 20.00 Min. :0.000 Length :1000 Min. :0.6000
## 1st Qu.: 30.00 1st Qu.:1.500 N.unique : 3 1st Qu.:0.7100
## Median : 40.00 Median :2.600 N.blank : 0 Median :0.7900
## Mean : 52.46 Mean :2.521 Min.nchar: 6 Mean :0.7922
## 3rd Qu.: 75.00 3rd Qu.:3.700 Max.nchar: 8 3rd Qu.:0.8700
## Max. :100.00 Max. :5.000 Max. :1.0000
## NAs :94
## years_of_experience_clean hourly_rate_clean
## Min. : 0.00 Min. : 20.00
## 1st Qu.: 3.00 1st Qu.: 30.00
## Median : 9.00 Median : 40.00
## Mean :11.22 Mean : 51.29
## 3rd Qu.:17.00 3rd Qu.: 75.00
## Max. :41.00 Max. :100.00
##
## 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
## 0 0 0
## years_of_experience_clean hourly_rate_clean
## 0 0
## freelancer_ID name gender
## 0.0 0.0 0.0
## age country language
## 3.0 0.0 0.0
## primary_skill years_of_experience hourly_rate (USD)
## 0.0 5.1 9.4
## rating is_active client_satisfaction
## 0.0 0.0 0.0
## years_of_experience_clean hourly_rate_clean
## 0.0 0.0
## Baris duplikat: 0
## Usia di luar 0-100: 0
## Pengalaman kerja negatif: 0
## Rating di luar 0-5: 0
## Hourly rate negatif: 0
cat("Client satisfaction di luar 0-1:",
sum(data_clean$client_satisfaction < 0 |
data_clean$client_satisfaction > 1, na.rm = TRUE), "\n")## Client satisfaction di luar 0-1: 0
Uji ini memeriksa apakah suatu variabel berdistribusi normal. H0 menyatakan data berdistribusi normal, dan H0 ditolak apabila p-value kurang dari 0,05. Hasilnya sebaiknya dibaca bersama histogram dan Q-Q plot pada bab 7.
hourly_rate_test <- na.omit(data_clean$hourly_rate_clean)
experience_test <- na.omit(data_clean$years_of_experience_clean)
if (length(hourly_rate_test) >= 3 && length(hourly_rate_test) <= 5000) {
print(shapiro.test(hourly_rate_test))
} else {
message("Shapiro-Wilk membutuhkan 3 sampai 5000 observasi.")
}##
## Shapiro-Wilk normality test
##
## data: hourly_rate_test
## W = 0.85064, p-value < 2.2e-16
if (length(experience_test) >= 3 && length(experience_test) <= 5000) {
print(shapiro.test(experience_test))
} else {
message("Shapiro-Wilk membutuhkan 3 sampai 5000 observasi.")
}##
## Shapiro-Wilk normality test
##
## data: experience_test
## W = 0.9101, p-value < 2.2e-16
Uji ini membandingkan varians tarif per jam antarkelompok gender. H0 menyatakan varians antarkelompok sama, dan H0 ditolak apabila p-value kurang dari 0,05, yang berarti varians dianggap berbeda.
data_bartlett <- data_clean[
!is.na(data_clean$hourly_rate_clean) & !is.na(data_clean$gender),
]
data_bartlett$gender <- droplevels(factor(data_bartlett$gender))
if (
length(unique(data_bartlett$gender)) >= 2 &&
all(table(data_bartlett$gender) >= 2)
) {
print(bartlett.test(hourly_rate_clean ~ gender, data = data_bartlett))
} else {
message("Data kelompok belum cukup untuk uji Bartlett.")
}##
## Bartlett test of homogeneity of variances
##
## data: hourly_rate_clean by gender
## Bartlett's K-squared = 1.4921, df = 1, p-value = 0.2219
Hasil uji normalitas menentukan apakah korelasi Pearson layak digunakan. Apabila data tidak berdistribusi normal, digunakan korelasi Spearman yang tidak mensyaratkan normalitas. H0 menyatakan tidak ada hubungan monotonik antara pengalaman kerja dan tarif per jam, dan H0 ditolak apabila p-value kurang dari 0,05. Nilai rho menunjukkan arah dan kekuatan hubungan.
data_korelasi <- data.frame(
pengalaman = data_clean$years_of_experience_clean,
tarif = data_clean$hourly_rate_clean
)
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) {
hasil_spearman <- cor.test(
data_korelasi$pengalaman,
data_korelasi$tarif,
method = "spearman",
exact = FALSE
)
print(hasil_spearman)
rho <- unname(hasil_spearman$estimate)
kekuatan <- as.character(cut(
abs(rho),
breaks = c(-Inf, 0.2, 0.4, 0.6, 0.8, Inf),
labels = c("sangat lemah", "lemah", "sedang", "kuat", "sangat kuat")
))
cat("\nKoefisien Spearman (rho):", round(rho, 4), "\n")
cat("P-value:", signif(hasil_spearman$p.value, 4), "\n")
cat("Arah hubungan:", ifelse(rho > 0, "positif", "negatif"), "\n")
cat("Kekuatan hubungan:", kekuatan, "\n")
} else {
message("Data tidak cukup bervariasi untuk menghitung korelasi.")
}##
## Spearman's rank correlation rho
##
## data: data_korelasi$pengalaman and data_korelasi$tarif
## S = 153640365, p-value = 0.01343
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## 0.07815689
##
##
## Koefisien Spearman (rho): 0.0782
## P-value: 0.01343
## Arah hubungan: positif
## Kekuatan hubungan: sangat lemah
Pengalaman kerja dikelompokkan menjadi empat kategori berurutan,
yaitu pemula (0 sampai 10 tahun), menengah (11 sampai 20 tahun), jago
(21 sampai 30 tahun), dan master (di atas 30 tahun). Setiap kategori
diberi kode angka 1 sampai 4, sedangkan nilai yang tidak tersedia diberi
kategori unknown dan tidak diberi kode angka.
## [1] 41
data_clean$kategori_pengalaman <- ifelse(
is.na(data_clean$years_of_experience_clean),
"unknown",
ifelse(
data_clean$years_of_experience_clean <= 10,
"pemula",
ifelse(
data_clean$years_of_experience_clean <= 20,
"menengah",
ifelse(
data_clean$years_of_experience_clean <= 30,
"jago",
"master"
)
)
)
)
data_clean$kategori_encode <- as.numeric(
factor(
data_clean$kategori_pengalaman,
levels = c("pemula", "menengah", "jago", "master")
)
)
table(
data_clean$kategori_pengalaman,
data_clean$kategori_encode,
useNA = "ifany"
)##
## 1 2 3 4
## jago 0 0 122 0
## master 0 0 0 55
## menengah 0 252 0 0
## pemula 571 0 0 0
## num [1:1000] 2 4 4 1 3 2 1 2 1 3 ...
Statistik deskriptif dihitung pada pengalaman kerja dan tarif per jam setelah imputasi, sehingga jumlah datanya lengkap. Tabel ini memperlihatkan pusat dan sebaran data. Apabila nilai mean berbeda cukup jauh dari median, distribusi data cenderung miring.
hourly_rate_test <- na.omit(data_clean$hourly_rate_clean)
experience_test <- na.omit(data_clean$years_of_experience_clean)
ringkas <- function(x) {
c(length(x), round(mean(x), 2), median(x),
round(sd(x), 2), min(x), max(x))
}
tabel_deskriptif <- data.frame(
Statistik = c("Jumlah Data", "Mean", "Median",
"Standar Deviasi", "Minimum", "Maksimum"),
Years_of_Experience = ringkas(experience_test),
Hourly_Rate_USD = ringkas(hourly_rate_test)
)
knitr::kable(tabel_deskriptif, align = "lrr")| Statistik | Years_of_Experience | Hourly_Rate_USD |
|---|---|---|
| Jumlah Data | 1000.00 | 1000.00 |
| Mean | 11.22 | 51.29 |
| Median | 9.00 | 40.00 |
| Standar Deviasi | 9.44 | 26.26 |
| Minimum | 0.00 | 20.00 |
| Maksimum | 41.00 | 100.00 |
Histogram memperlihatkan sebaran pengalaman kerja dan sebaran kategorinya. Bentuknya dibaca untuk mengetahui apakah data simetris atau miring, yang dapat dibandingkan dengan hasil uji normalitas pada bab 6.
hist(
na.omit(data_clean$years_of_experience_clean),
main = "Histogram Pengalaman Kerja",
xlab = "Years of Experience",
col = "#A2CA6C"
)hist(
na.omit(data_clean$kategori_encode),
main = "Histogram Kategori Pengalaman",
xlab = "Kode Kategori",
breaks = seq(0.5, 4.5, by = 1),
col = "#678E34"
)Q-Q plot membandingkan kuantil data dengan kuantil distribusi normal. Apabila titik-titik mengikuti garis, data mendekati distribusi normal. Semakin menyimpang titik dari garis, semakin jauh data dari distribusi normal.
if (length(hourly_rate_test) >= 2) {
qqnorm(hourly_rate_test, main = "QQ Plot Hourly Rate",
col = "#678E34", pch = 16)
qqline(hourly_rate_test, col = "#23330E", lwd = 2)
}if (length(experience_test) >= 2) {
qqnorm(experience_test, main = "QQ Plot Years of Experience",
col = "#678E34", pch = 16)
qqline(experience_test, col = "#23330E", lwd = 2)
}Diagram pencar memperlihatkan pola hubungan antara pengalaman kerja dan tarif per jam. Titik yang membentuk pola naik atau turun menandakan adanya hubungan, sedangkan titik yang tersebar tanpa pola menandakan hubungan yang lemah.
plot(
data_clean$years_of_experience_clean,
data_clean$hourly_rate_clean,
main = "Pengalaman Kerja dan Hourly Rate",
xlab = "Years of Experience",
ylab = "Hourly Rate (USD)",
pch = 19,
col = "#3C5718"
)Bagian bab ini menyelaraskan skala dan distribusi pengalaman kerja serta tarif per jam, sehingga kedua variabel siap dipakai pada analisis eksploratif dan pemodelan statistik lanjutan. Tiga transformasi digunakan, yaitu normalisasi min-max, standardisasi z-score, dan transformasi invers kuadrat.
Normalisasi min-max mengubah nilai variabel ke rentang 0 sampai 1
tanpa mengubah bentuk sebarannya, dengan rumus
(x - min) / (maks - min). Rentang awal data diperiksa
terlebih dahulu, dan hasil akhirnya seharusnya berada tepat pada 0
sampai 1.
# Paket pendukung
for (pkg in c("dplyr", "ggplot2")) {
if (!requireNamespace(pkg, quietly = TRUE)) install.packages(pkg)
}
library(dplyr)
library(ggplot2)
# 1. Pemeriksaan rentang data awal
data_clean %>%
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. 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_clean <- data_clean %>%
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
## Rentang Exp Min-Max : 0 - 1
## Rentang Rate Min-Max : 0 - 1
Interpretasi. Pengalaman kerja yang semula berkisar 0 sampai 41 tahun dan tarif per jam yang semula 20 sampai 100 USD kini sama-sama berada pada rentang 0 sampai 1. Nilai 0 mewakili data terkecil dan nilai 1 mewakili data terbesar, sehingga kedua variabel dapat dibandingkan pada skala yang sebanding.
Standardisasi z-score mengubah setiap nilai menjadi jaraknya dari rata-rata dalam satuan simpangan baku, sehingga variabel dengan satuan berbeda dapat dibandingkan. Hasil yang benar memiliki rata-rata mendekati 0 dan simpangan baku sama dengan 1.
data_clean <- data_clean %>%
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
## Rata-rata Z-Score Exp : 0
## Standar Deviasi Z Exp : 1
## Rata-rata Z-Score Rate : 0
## Standar Deviasi Z Rate : 1
Interpretasi. Rata-rata z-score kedua variabel adalah 0 dan simpangan bakunya 1. Nilai z yang positif menunjukkan data berada di atas rata-rata, sedangkan nilai yang negatif menunjukkan data berada di bawah rata-rata. Bentuk sebaran tidak berubah, hanya skalanya yang diseragamkan.
Transformasi invers kuadrat, yaitu 1 / (x + 1)^2,
mengubah skala secara nonlinier: nilai kecil menghasilkan angka besar
dan nilai besar menghasilkan angka kecil, sehingga urutannya terbalik.
Angka 1 ditambahkan agar tidak terjadi pembagian dengan nol, karena
pengalaman kerja dapat bernilai 0. Subbab ini juga menyatukan seluruh
hasil transformasi ke dalam satu tabel ringkasan.
# 1. Pengecekan keamanan nilai nol
data_clean %>%
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 untuk melindungi dari pembagian 1/0)
data_clean <- data_clean %>%
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_clean, aes(x = years_of_experience_clean)) +
geom_histogram(bins = 20, fill = "#678E34", color = "white") +
labs(
title = "Distribusi Pengalaman Kerja Sebelum Transformasi",
x = "Pengalaman Kerja (Tahun)",
y = "Frekuensi"
) +
theme_minimal() +
theme(plot.title = element_text(face = "bold", color = "#23330E"))# 4. Konsolidasi dan evaluasi ringkasan statistik
data_transformasi <- data_clean %>%
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
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>
Interpretasi. Terdapat 72 freelancer dengan pengalaman kerja 0 tahun, sehingga penambahan angka 1 pada rumus memang diperlukan. Histogram menunjukkan sebaran pengalaman kerja yang miring ke kanan: sebagian besar freelancer berpengalaman rendah dan hanya sedikit yang berpengalaman tinggi, sesuai dengan rata-rata (11,22) yang lebih besar daripada median (9). Setelah transformasi invers kuadrat, nilai berkisar antara 0,0006 sampai 1 untuk pengalaman kerja dan antara 0,0001 sampai 0,0023 untuk tarif, dengan urutan yang terbalik. Pada data ini transformasi tersebut tidak menormalkan sebaran, bahkan kemiringan pengalaman kerja justru meningkat, sehingga hasilnya lebih tepat dipakai sebagai pembanding daripada pengganti variabel asli. Ringkasan evaluasi menunjukkan rata-rata pengalaman kerja 11,22 tahun (SD 9,44) dan rata-rata tarif 51,29 USD (SD 26,26).
Hasil imputasi dimasukkan kembali ke kolom aslinya, kemudian kolom sementara dihapus. Dengan demikian, dataset final memuat nama variabel yang sama dengan data awal.
data_final <- data_clean
data_final$years_of_experience <- data_final$years_of_experience_clean
data_final$`hourly_rate (USD)` <- data_final$hourly_rate_clean
data_final$years_of_experience_clean <- NULL
data_final$hourly_rate_clean <- NULL
str(data_final)## tibble [1,000 × 20] (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 40 50 ...
## $ rating : num [1:1000] 2.6 3.3 0 1.5 4.8 2.4 3.1 4.6 4 2.6 ...
## $ is_active : chr [1:1000] "Inactive" "Active" "Inactive" "Inactive" ...
## $ client_satisfaction: num [1:1000] 0.79 0.84 0.71 0.9 0.83 0.79 0.94 0.94 0.76 0.79 ...
## $ kategori_pengalaman: chr [1:1000] "menengah" "master" "master" "pemula" ...
## $ kategori_encode : num [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 ...
## freelancer_ID name gender age
## Length :1000 Length :1000 Length :1000 Min. :20.00
## N.unique :1000 N.unique : 992 N.unique : 2 1st Qu.:31.00
## N.blank : 0 N.blank : 0 N.blank : 0 Median :41.00
## Min.nchar: 8 Min.nchar: 7 Min.nchar: 4 Mean :40.51
## Max.nchar: 8 Max.nchar: 25 Max.nchar: 6 3rd Qu.:51.00
## Max. :60.00
## NAs :30
## country language primary_skill years_of_experience
## Length :1000 Length :1000 Length :1000 Min. : 0.00
## N.unique : 21 N.unique : 16 N.unique : 10 1st Qu.: 3.00
## N.blank : 0 N.blank : 0 N.blank : 0 Median : 9.00
## Min.nchar: 5 Min.nchar: 5 Min.nchar: 2 Mean :11.22
## Max.nchar: 14 Max.nchar: 10 Max.nchar: 22 3rd Qu.:17.00
## Max. :41.00
##
## hourly_rate (USD) rating is_active client_satisfaction
## Min. : 20.00 Min. :0.000 Length :1000 Min. :0.6000
## 1st Qu.: 30.00 1st Qu.:1.500 N.unique : 3 1st Qu.:0.7100
## Median : 40.00 Median :2.600 N.blank : 0 Median :0.7900
## Mean : 51.29 Mean :2.521 Min.nchar: 6 Mean :0.7922
## 3rd Qu.: 75.00 3rd Qu.:3.700 Max.nchar: 8 3rd Qu.:0.8700
## Max. :100.00 Max. :5.000 Max. :1.0000
##
## kategori_pengalaman kategori_encode exp_minmax rate_minmax
## Length :1000 Min. :1.000 Min. :0.00000 Min. :0.0000
## N.unique : 4 1st Qu.:1.000 1st Qu.:0.07317 1st Qu.:0.1250
## N.blank : 0 Median :1.000 Median :0.21951 Median :0.2500
## Min.nchar: 4 Mean :1.661 Mean :0.27368 Mean :0.3911
## Max.nchar: 8 3rd Qu.:2.000 3rd Qu.:0.41463 3rd Qu.:0.6875
## Max. :4.000 Max. :1.00000 Max. :1.0000
##
## exp_z rate_z exp_inv_sq rate_inv_sq
## Min. :-1.1881 Min. :-1.1916 Min. :0.0005669 Min. :9.803e-05
## 1st Qu.:-0.8705 1st Qu.:-0.8107 1st Qu.:0.0030864 1st Qu.:1.731e-04
## Median :-0.2352 Median :-0.4299 Median :0.0100000 Median :5.949e-04
## Mean : 0.0000 Mean : 0.0000 Mean :0.1059001 Mean :7.328e-04
## 3rd Qu.: 0.6119 3rd Qu.: 0.9029 3rd Qu.:0.0625000 3rd Qu.:1.041e-03
## Max. : 3.1531 Max. : 1.8549 Max. :1.0000000 Max. :2.268e-03
##
## [1] 1000 20
## freelancer_ID name gender age
## 0 0 0 30
## country language primary_skill years_of_experience
## 0 0 0 0
## hourly_rate (USD) rating is_active client_satisfaction
## 0 0 0 0
## kategori_pengalaman kategori_encode exp_minmax rate_minmax
## 0 0 0 0
## exp_z rate_z exp_inv_sq rate_inv_sq
## 0 0 0 0
## [1] 0
Integrasi data adalah penyusunan variabel yang relevan ke dalam satu
dataset yang konsisten agar lebih mudah dipakai dalam analisis statistik
dan visualisasi. Dari data final dipilih kolom-kolom yang dibutuhkan,
termasuk kolom hasil transformasi numerik, dan fungsi
intersect() digunakan agar hanya kolom yang benar-benar
tersedia yang diambil.
## tibble [1,000 × 20] (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 40 50 ...
## $ rating : num [1:1000] 2.6 3.3 0 1.5 4.8 2.4 3.1 4.6 4 2.6 ...
## $ is_active : chr [1:1000] "Inactive" "Active" "Inactive" "Inactive" ...
## $ client_satisfaction: num [1:1000] 0.79 0.84 0.71 0.9 0.83 0.79 0.94 0.94 0.76 0.79 ...
## $ kategori_pengalaman: chr [1:1000] "menengah" "master" "master" "pemula" ...
## $ kategori_encode : num [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 ...
## [1] 1000 20
## [1] "freelancer_ID" "name" "gender"
## [4] "age" "country" "language"
## [7] "primary_skill" "years_of_experience" "hourly_rate (USD)"
## [10] "rating" "is_active" "client_satisfaction"
## [13] "kategori_pengalaman" "kategori_encode" "exp_minmax"
## [16] "rate_minmax" "exp_z" "rate_z"
## [19] "exp_inv_sq" "rate_inv_sq"
kolom_analisis <- c(
"age",
"gender",
"country",
"years_of_experience",
"kategori_pengalaman",
"kategori_encode",
"hourly_rate (USD)",
"client_satisfaction",
"rating",
"is_active",
"exp_minmax",
"exp_z",
"exp_inv_sq",
"rate_minmax",
"rate_z",
"rate_inv_sq"
)
kolom_tersedia <- intersect(kolom_analisis, names(data_integrasi))
data_analisis <- data_integrasi[, kolom_tersedia, drop = FALSE]
head(data_analisis)## # A tibble: 6 × 16
## age gender country years_of_experience kategori_pengalaman kategori_encode
## <dbl> <chr> <chr> <dbl> <chr> <dbl>
## 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
## # ℹ 10 more variables: `hourly_rate (USD)` <dbl>, client_satisfaction <dbl>,
## # rating <dbl>, is_active <chr>, exp_minmax <dbl>, exp_z <dbl>,
## # exp_inv_sq <dbl>, rate_minmax <dbl>, rate_z <dbl>, rate_inv_sq <dbl>
## tibble [1,000 × 16] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:1000] 52 52 53 38 53 59 52 43 26 52 ...
## $ gender : chr [1:1000] "Female" "Female" "Male" "Female" ...
## $ country : chr [1:1000] "Italy" "Australia" "Germany" "Australia" ...
## $ years_of_experience: num [1:1000] 11 34 31 4 27 14 10 14 4 22 ...
## $ kategori_pengalaman: chr [1:1000] "menengah" "master" "master" "pemula" ...
## $ kategori_encode : num [1:1000] 2 4 4 1 3 2 1 2 1 3 ...
## $ hourly_rate (USD) : num [1:1000] 100 100 50 40 30 30 75 40 40 50 ...
## $ client_satisfaction: num [1:1000] 0.79 0.84 0.71 0.9 0.83 0.79 0.94 0.94 0.76 0.79 ...
## $ rating : num [1:1000] 2.6 3.3 0 1.5 4.8 2.4 3.1 4.6 4 2.6 ...
## $ is_active : chr [1:1000] "Inactive" "Active" "Inactive" "Inactive" ...
## $ exp_minmax : num [1:1000] 0.2683 0.8293 0.7561 0.0976 0.6585 ...
## $ exp_z : num [1:1000] -0.0234 2.4119 2.0943 -0.7646 1.6707 ...
## $ exp_inv_sq : num [1:1000] 0.006944 0.000816 0.000977 0.04 0.001276 ...
## $ rate_minmax : num [1:1000] 1 1 0.375 0.25 0.125 ...
## $ rate_z : num [1:1000] 1.8549 1.8549 -0.0491 -0.4299 -0.8107 ...
## $ rate_inv_sq : num [1:1000] 0.000098 0.000098 0.000384 0.000595 0.001041 ...
## age gender country years_of_experience
## Min. :20.00 Length :1000 Length :1000 Min. : 0.00
## 1st Qu.:31.00 N.unique : 2 N.unique : 21 1st Qu.: 3.00
## Median :41.00 N.blank : 0 N.blank : 0 Median : 9.00
## Mean :40.51 Min.nchar: 4 Min.nchar: 5 Mean :11.22
## 3rd Qu.:51.00 Max.nchar: 6 Max.nchar: 14 3rd Qu.:17.00
## Max. :60.00 Max. :41.00
## NAs :30
## kategori_pengalaman kategori_encode hourly_rate (USD) client_satisfaction
## Length :1000 Min. :1.000 Min. : 20.00 Min. :0.6000
## N.unique : 4 1st Qu.:1.000 1st Qu.: 30.00 1st Qu.:0.7100
## N.blank : 0 Median :1.000 Median : 40.00 Median :0.7900
## Min.nchar: 4 Mean :1.661 Mean : 51.29 Mean :0.7922
## Max.nchar: 8 3rd Qu.:2.000 3rd Qu.: 75.00 3rd Qu.:0.8700
## Max. :4.000 Max. :100.00 Max. :1.0000
##
## rating is_active exp_minmax exp_z
## Min. :0.000 Length :1000 Min. :0.00000 Min. :-1.1881
## 1st Qu.:1.500 N.unique : 3 1st Qu.:0.07317 1st Qu.:-0.8705
## Median :2.600 N.blank : 0 Median :0.21951 Median :-0.2352
## Mean :2.521 Min.nchar: 6 Mean :0.27368 Mean : 0.0000
## 3rd Qu.:3.700 Max.nchar: 8 3rd Qu.:0.41463 3rd Qu.: 0.6119
## Max. :5.000 Max. :1.00000 Max. : 3.1531
##
## exp_inv_sq rate_minmax rate_z rate_inv_sq
## Min. :0.0005669 Min. :0.0000 Min. :-1.1916 Min. :9.803e-05
## 1st Qu.:0.0030864 1st Qu.:0.1250 1st Qu.:-0.8107 1st Qu.:1.731e-04
## Median :0.0100000 Median :0.2500 Median :-0.4299 Median :5.949e-04
## Mean :0.1059001 Mean :0.3911 Mean : 0.0000 Mean :7.328e-04
## 3rd Qu.:0.0625000 3rd Qu.:0.6875 3rd Qu.: 0.9029 3rd Qu.:1.041e-03
## Max. :1.0000000 Max. :1.0000 Max. : 1.8549 Max. :2.268e-03
##
Dataset hasil integrasi diperiksa kembali, meliputi dimensi, nilai hilang, baris ganda, serta sebaran rating, status keaktifan, dan kategori pengalaman.
## [1] 1000 16
## age gender country years_of_experience
## 30 0 0 0
## kategori_pengalaman kategori_encode hourly_rate (USD) client_satisfaction
## 0 0 0 0
## rating is_active exp_minmax exp_z
## 0 0 0 0
## exp_inv_sq rate_minmax rate_z rate_inv_sq
## 0 0 0 0
## [1] 0
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 1.500 2.600 2.521 3.700 5.000
## [1] 0
##
## Active Inactive Unknown
## 446 465 89
##
## jago master menengah pemula
## 122 55 252 571
Tahap terakhir adalah menyimpan dataset hasil pengolahan ke file CSV agar dapat digunakan kembali pada analisis berikutnya.
Proses data wrangling berhasil meningkatkan kualitas data
Global Freelancers Dataset melalui penyeragaman kategori,
perbaikan tipe data dan skala, penghapusan baris ganda, imputasi median,
serta pemberian label Unknown pada status yang tidak jelas.
Dataset akhir sudah bersih dan konsisten, lalu disimpan sebagai
data_analisis_final.csv untuk analisis lanjutan.
Transformasi numerik berupa normalisasi min-max, standardisasi z-score,
dan transformasi invers kuadrat juga dilakukan untuk menyelaraskan skala
dan distribusi variabel.
Hasil uji Shapiro-Wilk menunjukkan bahwa pengalaman kerja dan tarif per jam tidak berdistribusi normal, sehingga hubungan keduanya dianalisis dengan korelasi Spearman. Hasilnya menunjukkan hubungan positif yang signifikan secara statistik, tetapi kekuatannya tergolong sangat lemah. Uji Bartlett menunjukkan varians tarif per jam antara kelompok gender tidak berbeda nyata.
Dengan demikian, pengalaman kerja berkaitan dengan tarif per jam, tetapi pengaruhnya kecil. Faktor lain di luar variabel yang dianalisis kemungkinan berperan lebih besar dalam menentukan besarnya tarif freelancer.