Perkembangan teknologi digital dan platform daring telah membuka peluang bagi banyak orang untuk bekerja secara lepas (freelance) tanpa terikat pada satu perusahaan maupun lokasi tertentu. Pekerja lepas memiliki karakteristik yang beragam, antara lain usia, negara asal, lama pengalaman, tarif per jam, dan penilaian dari klien. Keragaman tersebut menjadikan data pekerja lepas layak untuk dikaji lebih lanjut.
Data yang digunakan dalam laporan ini adalah data mentah Global
Freelancers dalam format Excel. Sebagaimana data mentah pada
umumnya, kondisinya belum sepenuhnya siap dianalisis. Sejumlah variabel
masih memuat simbol seperti $, USD, dan
% sehingga terbaca sebagai teks. Penulisan kategori juga
belum seragam, misalnya f, F, dan
female yang sebenarnya merujuk pada kategori yang sama.
Selain itu, data berpotensi mengandung nilai hilang (missing
value), baris ganda, dan nilai yang tidak wajar.
Apabila data dengan kondisi demikian langsung dianalisis, kesimpulan yang dihasilkan berisiko tidak akurat. Oleh karena itu, laporan ini difokuskan pada tahapan data preprocessing, yaitu pemeriksaan permasalahan data, pembersihan, transformasi, visualisasi, pengujian asumsi, hingga penyimpanan dataset final yang siap digunakan untuk analisis lanjutan.
Bagian ini memperlihatkan isi dataset sebelum diolah, supaya kondisi awalnya bisa dibandingkan dengan hasil akhir.
File Excel diletakkan satu folder dengan file .Rmd ini,
sehingga lokasinya cukup ditulis dengan nama file.
## 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
## 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
Pertama dicek dulu variasi penulisan pada kolom gender,
lalu diseragamkan menjadi Female dan Male.
##
## 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
Kolom tarif per jam masih bisa mengandung simbol $ dan
tulisan USD, sehingga terbaca sebagai teks. Simbol dihapus
dulu, baru kolomnya 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. Nilai kosong yang tersisa diisi dengan median, karena median tidak terlalu 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 ...
## [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.7300 0.8200 9.8065 0.9125 100.0000
## [1] 0
Ketiga kolom ini diperlakukan dengan cara yang sama, yaitu membuang tanda yang tidak perlu dan mengubahnya ke angka.
## [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 ...
Kolom status aktif punya banyak penulisan (1,
y, yes, true, dan seterusnya).
Semuanya disatukan menjadi Active atau
Inactive, dan nilai yang tidak bisa 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
## [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
Di sini dicek apakah ada nilai yang tidak masuk akal, misalnya usia negatif atau rating di atas 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
## 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.7300 0.8200 9.8065 0.9125 100.0000
## [1] 0
## [1] 0
Data hasil pembersihan disalin ke objek baru bernama
data_clean, supaya data yang sudah diseragamkan tetap
tersimpan terpisah dari tahap imputasi.
## 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.82 0.84 0.71 0.9 0.83 0.82 0.94 0.94 0.76 0.82 ...
## [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.7300
## Median : 40.00 Median :2.600 N.blank : 0 Median : 0.8200
## Mean : 52.46 Mean :2.513 Min.nchar: 6 Mean : 9.8065
## 3rd Qu.: 75.00 3rd Qu.:3.800 Max.nchar: 8 3rd Qu.: 0.9125
## Max. :100.00 Max. :5.000 Max. :100.0000
## NAs :94 NAs :101
Imputasi median dilakukan pada pengalaman kerja, tarif per jam, dan rating.
# 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
Semua pemeriksaan di bagian 3 diulang pada data_clean
untuk memastikan masalahnya sudah teratasi.
## 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.82 0.84 0.71 0.9 0.83 0.82 0.94 0.94 0.76 0.82 ...
## $ 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.7300
## Median : 40.00 Median :2.600 N.blank : 0 Median : 0.8200
## Mean : 52.46 Mean :2.521 Min.nchar: 6 Mean : 9.8065
## 3rd Qu.: 75.00 3rd Qu.:3.700 Max.nchar: 8 3rd Qu.: 0.9125
## Max. :100.00 Max. :5.000 Max. :100.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-100:",
sum(data_clean$client_satisfaction < 0 |
data_clean$client_satisfaction > 100, na.rm = TRUE), "\n")## Client satisfaction di luar 0-100: 0
Pengalaman kerja dikelompokkan ke dalam empat kategori berurutan, lalu setiap kategori diberi kode angka 1 sampai 4.
## [1] 41
data_clean$kategori_pengalaman <- ifelse(
is.na(data_clean$years_of_experience_clean),
NA_character_,
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 ...
hist(
na.omit(data_clean$years_of_experience_clean),
main = "Histogram Pengalaman Kerja",
xlab = "Years of Experience",
col = "#A3B18A"
)hist(
na.omit(data_clean$kategori_encode),
main = "Histogram Kategori Pengalaman",
xlab = "Kode Kategori",
breaks = seq(0.5, 4.5, by = 1),
col = "#588157"
)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) >= 2) {
qqnorm(hourly_rate_test, main = "QQ Plot Hourly Rate")
qqline(hourly_rate_test, col = "#344E41")
}if (length(experience_test) >= 2) {
qqnorm(experience_test, main = "QQ Plot Years of Experience")
qqline(experience_test, col = "#344E41")
}Hipotesis yang diuji: H0 menyatakan data berdistribusi normal. Jika p-value kurang dari 0,05, H0 ditolak, artinya data tidak berdistribusi normal. Hasil uji sebaiknya dibaca bersama histogram dan Q-Q plot di atas.
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 antar kelompok gender. H0 menyatakan varians antar kelompok sama. Jika p-value kurang dari 0,05, 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 imputasi dimasukkan kembali ke kolom aslinya, lalu kolom sementara dihapus.
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 × 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 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.82 0.84 0.71 0.9 0.83 0.82 0.94 0.94 0.76 0.82 ...
## $ kategori_pengalaman: chr [1:1000] "menengah" "master" "master" "pemula" ...
## $ kategori_encode : num [1:1000] 2 4 4 1 3 2 1 2 1 3 ...
## 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.7300
## Median : 40.00 Median :2.600 N.blank : 0 Median : 0.8200
## Mean : 51.29 Mean :2.521 Min.nchar: 6 Mean : 9.8065
## 3rd Qu.: 75.00 3rd Qu.:3.700 Max.nchar: 8 3rd Qu.: 0.9125
## Max. :100.00 Max. :5.000 Max. :100.0000
##
## kategori_pengalaman kategori_encode
## Length :1000 Min. :1.000
## N.unique : 4 1st Qu.:1.000
## N.blank : 0 Median :1.000
## Min.nchar: 4 Mean :1.661
## Max.nchar: 8 3rd Qu.:2.000
## Max. :4.000
##
## [1] 1000 14
## 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
## 0 0
## [1] 0
Dari data final dipilih kolom-kolom yang dibutuhkan untuk analisis.
intersect() dipakai supaya hanya kolom yang benar-benar ada
yang diambil.
## 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 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.82 0.84 0.71 0.9 0.83 0.82 0.94 0.94 0.76 0.82 ...
## $ kategori_pengalaman: chr [1:1000] "menengah" "master" "master" "pemula" ...
## $ kategori_encode : num [1:1000] 2 4 4 1 3 2 1 2 1 3 ...
## [1] 1000 14
## [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"
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_integrasi))
data_analisis <- data_integrasi[, kolom_tersedia, drop = FALSE]
head(data_analisis)## # A tibble: 6 × 10
## 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
## # ℹ 4 more variables: `hourly_rate (USD)` <dbl>, client_satisfaction <dbl>,
## # rating <dbl>, is_active <chr>
## tibble [1,000 × 10] (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.82 0.84 0.71 0.9 0.83 0.82 0.94 0.94 0.76 0.82 ...
## $ 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" ...
## 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.7300
## N.blank : 0 Median :1.000 Median : 40.00 Median : 0.8200
## Min.nchar: 4 Mean :1.661 Mean : 51.29 Mean : 9.8065
## Max.nchar: 8 3rd Qu.:2.000 3rd Qu.: 75.00 3rd Qu.: 0.9125
## Max. :4.000 Max. :100.00 Max. :100.0000
##
## rating is_active
## Min. :0.000 Length :1000
## 1st Qu.:1.500 N.unique : 3
## Median :2.600 N.blank : 0
## Mean :2.521 Min.nchar: 6
## 3rd Qu.:3.700 Max.nchar: 8
## Max. :5.000
##
## [1] 1000 10
## 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
## 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
Data mentah global freelancers berhasil dibersihkan lewat
beberapa tahap: penyeragaman kategori, perubahan tipe data, penghapusan
baris ganda, imputasi median, dan pemberian label Unknown
pada status yang tidak jelas. Setelah itu pengalaman kerja dikelompokkan
menjadi empat kategori, divisualisasikan, dan diuji asumsinya. Dataset
akhir disimpan sebagai data_analisis_final.csv dan siap
dipakai untuk analisis lanjutan.