1. Pendahuluan

1.1 Latar Belakang

Perkembangan teknologi digital memberikan kesempatan bagi masyarakat untuk bekerja secara lepas (freelance) tanpa harus terikat pada satu lokasi kerja. Dalam pasar kerja tersebut, freelancer memiliki karakteristik yang beragam, mulai dari usia, keahlian, pengalaman, hingga tarif jasa yang ditawarkan. Lama pengalaman kerja (years of experience) menjadi salah satu faktor yang menarik untuk diteliti karena diduga berkaitan dengan tarif per jam (hourly rate).

Analisis ini menggunakan Global Freelancers Dataset yang bersumber dari Kaggle. Dataset tersebut terdiri atas 1.000 observasi freelancer dan 12 variabel yang memuat informasi mengenai karakteristik individu, pengalaman kerja, tarif jasa, rating, kepuasan klien, serta status keaktifan.

Sebelum dianalisis, data perlu diperiksa untuk mengetahui kemungkinan adanya nilai yang hilang (missing value), ketidakkonsistenan kategori, kesalahan format, duplikasi, dan nilai yang berpotensi tidak wajar. Proses pembersihan dan pengolahan data dilakukan agar informasi yang digunakan lebih konsisten. Selanjutnya, analisis diarahkan untuk menggambarkan karakteristik pengalaman kerja dan mengkaji hubungannya dengan tarif per jam freelancer.

1.2 Rumusan Masalah

  1. Apa saja permasalahan kualitas data yang terdapat pada Global Freelancers Dataset?
  2. Bagaimana proses preprocessing dilakukan untuk menangani nilai yang hilang, inkonsistensi format, dan ketidaksesuaian tipe data?
  3. Bagaimana karakteristik pengalaman kerja freelancer setelah pembersihan data berdasarkan statistik deskriptif dan pengujian normalitas?
  4. Bagaimana hubungan antara pengalaman kerja dan tarif per jam freelancer?

1.3 Tujuan Analisis

  1. Mengidentifikasi permasalahan kualitas data yang terdapat pada Global Freelancers Dataset.
  2. Melakukan preprocessing untuk menangani nilai yang hilang, menyeragamkan format, dan memperbaiki tipe data.
  3. Mendeskripsikan karakteristik pengalaman kerja melalui statistik deskriptif dan pemeriksaan normalitas setelah pembersihan data.
  4. Menganalisis hubungan antara pengalaman kerja dan tarif per jam freelancer.

2. Gambaran Dataset

2.1 Informasi Dataset

Dataset berisi informasi mengenai profil freelancer dari berbagai negara, termasuk karakteristik demografi, pengalaman kerja, tarif jasa per jam, rating, kepuasan klien, dan status keaktifan.

2.2 Sumber Data

Data diperoleh dari Kaggle dengan nama file data ade global_freelancers_raw.xlsx.

2.3 Jenis Data

Data yang digunakan mencakup variabel kuantitatif dan kualitatif. Data berbentuk potret observasi pada sejumlah freelancer, sehingga analisis dilakukan berdasarkan informasi yang tersedia dalam dataset.

2.4 Import Data

if (!requireNamespace("readxl", quietly = TRUE)) {
  install.packages("readxl")
}

library(readxl)
library(dplyr)

lokasi_file <- "C:/Users/advan/Downloads/data ade global_freelancers_raw.xlsx"

if (!file.exists(lokasi_file)) {
  stop("File Excel tidak ditemukan. Periksa kembali lokasi file.")
}

ADE <- read_excel(lokasi_file)

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

3. Permasalahan Data

3.1 Missing Value

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

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

tabel_missing <- data.frame(
  Variabel = names(jumlah_missing),
  Jumlah_Missing = as.integer(jumlah_missing),
  Persentase_Missing = as.numeric(persen_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

3.2 Inkonsistensi Data

Pemeriksaan dilakukan terhadap variabel kategori untuk mengetahui variasi penulisan yang perlu distandardisasi.

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

3.3 Duplikasi Data

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

3.4 Data Noisy

Pemeriksaan dilakukan terhadap ringkasan nilai untuk menemukan nilai yang berpotensi tidak wajar. Nilai ekstrem tidak otomatis dihapus sebelum diperiksa lebih lanjut.

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

4. Data Wrangling

4.1 Menghapus Duplikat

ADE <- ADE[!duplicated(ADE), ]

cat("Jumlah baris setelah menghapus duplikat:",
    nrow(ADE), "\n")
## Jumlah baris setelah menghapus duplikat: 1000
cat("Sisa duplikasi:", sum(duplicated(ADE)), "\n")
## Sisa duplikasi: 0

4.2 Standardisasi Data

Proses ini menyeragamkan kategori dan mengubah variabel numerik ke tipe data yang sesuai. Fungsi konversi dibuat agar simbol mata uang, tanda persen, dan pemisah ribuan dapat ditangani.

# Fungsi untuk mengubah teks numerik menjadi angka
ubah_numerik <- function(x) {
  x <- trimws(as.character(x))
  x[x == ""] <- NA_character_

  x <- gsub(",", "", x)
  x <- gsub("USD", "", x, ignore.case = TRUE)
  x <- gsub("\\$", "", x)
  x <- gsub("%", "", x)

  suppressWarnings(as.numeric(trimws(x)))
}

# 1. Standardisasi gender
if ("gender" %in% names(ADE)) {
  gender_raw <- tolower(trimws(as.character(ADE$gender)))

  ADE$gender <- ifelse(
    is.na(gender_raw) | gender_raw == "",
    NA_character_,
    ifelse(
      gender_raw %in% c("f", "female", "woman"),
      "Female",
      ifelse(
        gender_raw %in% c("m", "male", "man"),
        "Male",
        "Unknown"
      )
    )
  )
}

# 2. Standardisasi hourly rate
if ("hourly_rate (USD)" %in% names(ADE)) {
  ADE$`hourly_rate (USD)` <-
    ubah_numerik(ADE$`hourly_rate (USD)`)
}

# 3. Standardisasi client satisfaction
if ("client_satisfaction" %in% names(ADE)) {
  satisfaction_raw <- trimws(
    as.character(ADE$client_satisfaction)
  )

  ada_persen <- grepl("%", satisfaction_raw, fixed = TRUE)
  satisfaction_num <- ubah_numerik(satisfaction_raw)

  # Konversi persentase ke skala 0-1
  satisfaction_num[ada_persen] <-
    satisfaction_num[ada_persen] / 100

  # Nilai 0-100 tanpa tanda persen juga dikonversi
  tanpa_persen <- !ada_persen &
    !is.na(satisfaction_num) &
    satisfaction_num > 1 &
    satisfaction_num <= 100

  satisfaction_num[tanpa_persen] <-
    satisfaction_num[tanpa_persen] / 100

  ADE$client_satisfaction <- satisfaction_num
}

# 4. Standardisasi variabel numerik lainnya
variabel_num <- c(
  "age",
  "years_of_experience",
  "rating"
)

for (v in intersect(variabel_num, names(ADE))) {
  ADE[[v]] <- ubah_numerik(ADE[[v]])
}

# 5. Standardisasi is_active
if ("is_active" %in% names(ADE)) {
  active_raw <- tolower(
    trimws(as.character(ADE$is_active))
  )

  ADE$is_active <- ifelse(
    is.na(active_raw) | active_raw == "",
    "Unknown",
    ifelse(
      active_raw %in% c("1", "y", "yes", "true", "active"),
      "Active",
      ifelse(
        active_raw %in% c("0", "n", "no", "false", "inactive"),
        "Inactive",
        "Unknown"
      )
    )
  )
}

# 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] "Inactive" "Active" "Inactive" "Inactive" ...
##  $ client_satisfaction: num [1:1000] NA 0.84 0.71 0.9 0.83 NA 0.94 0.94 0.76 NA ...
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"))
}
## 
##   Active Inactive  Unknown 
##      446      465       89

4.3 Menghapus Data Noisy

Pada tahap ini, nilai diperiksa terlebih dahulu. Nilai yang ekstrem tidak langsung dihapus karena perlu dibedakan antara nilai yang memang ekstrem dan nilai yang merupakan kesalahan pencatatan.

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 
##  0.6000  0.6975  0.7900  0.7927  0.8900  1.0000     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.4 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.

data_clean <- ADE

# Imputasi median rating
if ("rating" %in% names(data_clean)) {
  median_rating <- median(
    data_clean$rating,
    na.rm = TRUE
  )

  if (is.finite(median_rating)) {
    data_clean$rating[
      is.na(data_clean$rating)
    ] <- median_rating
  }
}

# Imputasi median client satisfaction
if ("client_satisfaction" %in% names(data_clean)) {
  median_sat <- median(
    data_clean$client_satisfaction,
    na.rm = TRUE
  )

  if (is.finite(median_sat)) {
    data_clean$client_satisfaction[
      is.na(data_clean$client_satisfaction)
    ] <- median_sat
  }
}

# Imputasi pengalaman kerja
if ("years_of_experience" %in% names(data_clean)) {
  median_exp <- median(
    data_clean$years_of_experience,
    na.rm = TRUE
  )

  if (is.finite(median_exp)) {
    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
  }
}

# Imputasi hourly rate
if ("hourly_rate (USD)" %in% names(data_clean)) {
  median_rate <- median(
    data_clean$`hourly_rate (USD)`,
    na.rm = TRUE
  )

  if (is.finite(median_rate)) {
    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)`
  }
}

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 
##                         0                         0                         0 
## years_of_experience_clean         hourly_rate_clean 
##                         0                         0

4.5 Hasil Akhir Pembersihan

data_final <- data_clean

# Memindahkan hasil imputasi ke variabel analisis
if ("years_of_experience_clean" %in% names(data_final)) {
  data_final$years_of_experience <-
    data_final$years_of_experience_clean

  data_final$years_of_experience_clean <- NULL
}

if ("hourly_rate_clean" %in% names(data_final)) {
  data_final$`hourly_rate (USD)` <-
    data_final$hourly_rate_clean

  data_final$hourly_rate_clean <- NULL
}

cat("Dimensi data final:\n")
## Dimensi data final:
print(dim(data_final))
## [1] 1000   12
cat("\nStruktur data final:\n")
## 
## Struktur data final:
str(data_final)
## 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 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 ...
cat("\nMissing value setelah pembersihan:\n")
## 
## Missing value setelah pembersihan:
print(colSums(is.na(data_final)))
##       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

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

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. 
##    0.00    3.00    9.00   11.22   17.00   41.00 
## [1] 9.444329
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. 
##   20.00   30.00   40.00   51.29   75.00  100.00 
## [1] 26.25977

6. Validasi Data

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                 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
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: 0

7. Uji Asumsi

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.9101, 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.85064, p-value < 2.2e-16

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.4921, df = 1, p-value = 0.2219

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 = 153640365, p-value = 0.01343
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## 0.07815689

8. Integrasi Data

8.1 Pengertian dan Alasan Integrasi

Integrasi data merupakan proses menggabungkan informasi dari sumber atau tabel yang berbeda agar dapat digunakan secara bersama dalam analisis. Pada penelitian ini, proses pengolahan juga mencakup penyatuan variabel hasil pembersihan dan variabel turunan ke dalam dataset analisis.

8.2 Tujuan Integrasi Data

Integrasi bertujuan menyusun variabel yang relevan dalam satu dataset yang konsisten agar lebih mudah digunakan dalam analisis statistik dan visualisasi.

8.3 Encoding Pengalaman Kerja

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 
##      122       55      252      571
table(
  data_final$kategori_encode,
  useNA = "ifany"
)
## 
##   1   2   3   4 
## 571 252 122  55

8.4 Visualisasi Data

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

# 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 = "red"
)

# 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 = "blue"
)

# 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 = "red",
    lwd = 2
  )
}

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. Integrasi Data II

Penyimpanan dataset hasil pembersihan dan pemilihan variabel ke dalam format CSV agar dapat digunakan kembali dalam pengolahan data.

9.1 Menyimpan Dataset Final

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\ADVAN\Downloads\data_analisis_final.csv

9.2 Pemeriksaan Dataset Final

cat("Dimensi dataset final:\n")
## Dimensi dataset final:
print(dim(data_analisis))
## [1] 1000   10
cat("\nStruktur dataset final:\n")
## 
## Struktur dataset final:
str(data_analisis)
## 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    : int [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" ...
cat("\nMissing value per variabel:\n")
## 
## Missing value per variabel:
print(colSums(is.na(data_analisis)))
##                 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
cat("\nLima baris pertama:\n")
## 
## Lima baris pertama:
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>