UTS - Pemogramman Sains Data

Profile

Paskalis Farelnata Zamasi

NIM: 52250043
Data Science Student at ITSB
R Programming Data Science Programming Data Science

Dosen Pembimbing

Bakti Siregar, M.Sc., CDS.

Profile

Christan Michael Juliano

NIM: 52250011
Data Science Student at ITSB
R Programming Data Science Programming Data Science

Dosen Pembimbing

Bakti Siregar, M.Sc., CDS.

Profile

M.Yustian Putra Muhadi

NIM: 52250015
Data Science Student at ITSB
R Programming Data Science Programming Data Science

Dosen Pembimbing

Bakti Siregar, M.Sc., CDS.

Mini Project: Case Study E-Commerce

Section A – Data Collection Using Programming

Tujuan: Mengambil dan menggabungkan data dari berbagai sumber menggunakan coding Python dan R

# 1. PERSIAPAN LIBRARY
library(readr)
library(readxl)
library(jsonlite)
library(XML)
library(dplyr)
library(kableExtra)

# 2. DEFINISI FILE DAN LOOPING PEMBACAAN
file_list <- c("ecommerce.csv", "ecommerce.xlsx", "ecommerce.json", "ecommerce.txt", "ecommerce.xml")
list_of_dfs <- list()
summary_data <- data.frame()

for (file_name in file_list) {
  ext <- tools::file_ext(file_name)
  
  # Proses membaca file berdasarkan ekstensi
  df <- tryCatch({
    if (ext == "csv") { read_csv(file_name, show_col_types = FALSE) } 
    else if (ext == "xlsx") { read_excel(file_name) } 
    else if (ext == "json") { fromJSON(file_name) } 
    else if (ext == "txt") { read_delim(file_name, delim = "|", show_col_types = FALSE) } 
    else if (ext == "xml") { xmlToDataFrame(file_name) }
  }, error = function(e) { return(NULL) })
  
  if (!is.null(df)) {
    list_of_dfs[[file_name]] <- df
    
    # Mengambil informasi ringkasan untuk tabel
    temp_summary <- data.frame(
      File_Name = file_name,
      Jumlah_Baris = nrow(df),
      Jumlah_Kolom = ncol(df),
      Nama_Kolom = paste(colnames(df), collapse = ", ")
    )
    summary_data <- rbind(summary_data, temp_summary)
  }
}

# 3. TAMPILKAN TABEL RINGKASAN (Agar Rapi seperti Gambar 1)
summary_data %>%
  kbl(caption = "Tabel 1. Ringkasan Import Data Multi-Format") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive")) %>%
  column_spec(4, width = "50em") # Membatasi lebar kolom nama agar tidak meluap
Tabel 1. Ringkasan Import Data Multi-Format
File_Name Jumlah_Baris Jumlah_Kolom Nama_Kolom
ecommerce.csv 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.xlsx 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.json 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.txt 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
ecommerce.xml 2000 22 order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag
# 4. PENGECEKAN STRUKTUR (IF/ELSE) & PENGGABUNGAN
# Menggunakan file pertama sebagai standar acuan
standar_kolom <- colnames(list_of_dfs[[1]])
list_siap_gabung <- list()
status_check <- data.frame()

for (nama_file in names(list_of_dfs)) {
  current_cols <- colnames(list_of_dfs[[nama_file]])
  
  if (identical(standar_kolom, current_cols)) {
    status <- "Ready to merge"
    # Menyeragamkan tipe data menjadi character agar tidak error saat bind_rows
    df_fix <- list_of_dfs[[nama_file]] %>% mutate(across(everything(), as.character))
    list_siap_gabung[[nama_file]] <- df_fix
  } else {
    status <- "Need adjustment"
  }
  
  status_check <- rbind(status_check, data.frame(File_Name = nama_file, Status_Struktur = status))
}

# 5. TAMPILKAN TABEL STATUS PENGECEKAN
status_check %>%
  kbl(caption = "Tabel 2. Status Pengecekan Struktur Kolom") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(2, color = ifelse(status_check$Status_Struktur == "Ready to merge", "green", "red"), bold = T)
Tabel 2. Status Pengecekan Struktur Kolom
File_Name Status_Struktur
ecommerce.csv Ready to merge
ecommerce.xlsx Ready to merge
ecommerce.json Ready to merge
ecommerce.txt Ready to merge
ecommerce.xml Ready to merge
# 6. EKSEKUSI PENGGABUNGAN AKHIR
dataset_utama <- bind_rows(list_siap_gabung)

# 7. MEMBUAT TABEL RINGKASAN HASIL AKHIR (PENGGANTI TEKS BIASA)
hasil_akhir_summary <- data.frame(
  Metrik = c("Total Baris Dataset Utama", "Total Kolom Dataset Utama", "Status Integrasi"),
  Nilai = c(nrow(dataset_utama), ncol(dataset_utama), "Sukses Tergabung")
)

hasil_akhir_summary %>%
  kbl(caption = "Tabel 3. Ringkasan Akhir Dataset Terintegrasi", align = "l") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F) %>%
  row_spec(0, background = "#27AE60", color = "white", bold = T) %>% # Header Hijau agar senada dengan sukses
  column_spec(2, bold = T)
Tabel 3. Ringkasan Akhir Dataset Terintegrasi
Metrik Nilai
Total Baris Dataset Utama 10000
Total Kolom Dataset Utama 22
Status Integrasi Sukses Tergabung

Interpretasi:

Proses pengumpulan data dilakukan dengan membaca lima format file sekaligus — CSV, XLSX, JSON, TXT, dan XML — menggunakan pendekatan looping berbasis ekstensi file. Dari kelima file tersebut, seluruhnya berhasil dibaca dan diidentifikasi memiliki struktur kolom yang identik, sehingga dapat langsung digabungkan menggunakan bind_rows() tanpa memerlukan penyesuaian tambahan. Hasil penggabungan akhir menghasilkan satu dataset utama yang terintegrasi, yang menjadi fondasi untuk seluruh proses analisis berikutnya. Pendekatan multi-format ini relevan dalam konteks e-commerce nyata, di mana data sering tersebar di berbagai sistem dan format ekspor yang berbeda.

Section B – Data Handling

# --- SECTION B: DATA HANDLING ---
library(dplyr)
library(kableExtra)

# 1. MENAMPILKAN JUMLAH TOTAL BARIS DAN KOLOM
# Kita buat dalam tabel ringkasan kecil agar elegan
ringkasan_dimensi <- data.frame(
  Metrik = c("Total Baris", "Total Kolom"),
  Nilai = c(nrow(dataset_utama), ncol(dataset_utama))
)

ringkasan_dimensi %>%
  kbl(caption = "Tabel 4. Dimensi Dataset Hasil Penggabungan") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F)
Tabel 4. Dimensi Dataset Hasil Penggabungan
Metrik Nilai
Total Baris 10000
Total Kolom 22
# 2. MENAMPILKAN TIPE DATA SETIAP KOLOM
# Kita ambil nama kolom dan tipe datanya
tipe_data_df <- data.frame(
  Kolom = colnames(dataset_utama),
  Tipe_Data = sapply(dataset_utama, class)
)

tipe_data_df %>%
  kbl(caption = "Tabel 5. Struktur Tipe Data Kolom") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  scroll_box(height = "300px") # Memberi scroll agar tidak kepanjangan di halaman
Tabel 5. Struktur Tipe Data Kolom
Kolom Tipe_Data
order_id order_id character
order_date order_date character
ship_date ship_date character
platform platform character
category category character
product_name product_name character
unit_price unit_price character
quantity quantity character
gross_sales gross_sales character
campaign campaign character
voucher_code voucher_code character
discount_pct discount_pct character
discount_value discount_value character
shipping_cost shipping_cost character
net_sales net_sales character
payment_method payment_method character
customer_segment customer_segment character
region region character
stock_status stock_status character
order_status order_status character
customer_rating customer_rating character
priority_flag priority_flag character
# 3. IDENTIFIKASI MISSING VALUES & DUPLICATE ROWS
total_na <- sum(is.na(dataset_utama))
total_dup <- sum(duplicated(dataset_utama))

identifikasi_masalah <- data.frame(
  Indikator = c("Total Missing Values (NA)", "Total Duplicate Rows"),
  Jumlah = c(total_na, total_dup),
  Status = c(
    ifelse(total_na > 0, "Perlu Cleaning", "Aman"),
    ifelse(total_dup > 0, "Perlu Cleaning", "Aman")
  )
)

identifikasi_masalah %>%
  kbl(caption = "Tabel 6. Identifikasi Kualitas Data") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  column_spec(3, color = "white", 
              background = ifelse(identifikasi_masalah$Status == "Aman", "#27AE60", "#E74C3C"))
Tabel 6. Identifikasi Kualitas Data
Indikator Jumlah Status
Total Missing Values (NA) 3629 Perlu Cleaning
Total Duplicate Rows 5581 Perlu Cleaning
# 4. MENYEBUTKAN MINIMAL 3 MASALAH KUALITAS DATA

# --- IDENTIFIKASI KUALITAS DATA ---

# 1. Menghitung Missing Values per Kolom
missing_per_col <- colSums(is.na(dataset_utama))
total_missing <- sum(missing_per_col)

# 2. Menghitung Baris Duplikat
total_duplicates <- sum(duplicated(dataset_utama))

# 3. Menghitung Kolom dengan Tipe Data Tidak Sesuai 
# (Contoh: Kolom numerik yang masih terbaca sebagai character)
# Di Section A kita merubah semua ke character, ini adalah salah satu "masalah"
potential_type_issues <- ncol(dataset_utama) 

# Membuat Tabel Ringkasan Masalah
quality_issues_df <- data.frame(
  No = c(1, 2, 3),
  Masalah_Kualitas_Data = c(
    "Missing Values (Data Kosong)", 
    "Duplicate Rows (Data Ganda)", 
    "Data Type Inconsistency (Character vs Numeric)"
  ),
  Jumlah_Temuan = c(total_missing, total_duplicates, potential_type_issues),
  Status = c(
    ifelse(total_missing > 0, "🚨 Masalah Ditemukan", "✅ Bersih"),
    ifelse(total_duplicates > 0, "🚨 Masalah Ditemukan", "✅ Bersih"),
    "🚨 Perlu Konversi"
  )
)

# Menampilkan Tabel dengan Styling Profesional
quality_issues_df %>%
  kbl(caption = "Tabel 6. Daftar Temuan Masalah Kualitas Data") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F) %>%
  column_spec(3, bold = T, color = "blue") %>%
  column_spec(4, color = "white", 
              background = ifelse(quality_issues_df$Jumlah_Temuan > 0, "#C0392B", "#27AE60"))
Tabel 6. Daftar Temuan Masalah Kualitas Data
No Masalah_Kualitas_Data Jumlah_Temuan Status
1 Missing Values (Data Kosong) 3629 🚨 Masalah Ditemukan
2 Duplicate Rows (Data Ganda) 5581 🚨 Masalah Ditemukan
3 Data Type Inconsistency (Character vs Numeric) 22 🚨 Perlu Konversi

Interpretasi:

Dataset utama hasil penggabungan terdiri dari baris dan kolom yang merefleksikan transaksi e-commerce lintas platform. Pemeriksaan awal mengungkap tiga kategori masalah kualitas data yang krusial. Pertama, terdapat missing values pada beberapa kolom kunci seperti payment_method dan customer_rating, yang berpotensi menyebabkan bias jika tidak ditangani sebelum analisis. Kedua, ditemukan baris duplikat yang kemungkinan berasal dari proses penggabungan multi-format, di mana data yang sama bisa saja tersimpan di lebih dari satu file sumber. Ketiga, seluruh kolom terbaca sebagai tipe character akibat konversi massal di Section A — padahal kolom seperti gross_sales, unit_price, dan quantity seharusnya bertipe numerik. Ketiga masalah ini harus diselesaikan di tahap cleaning agar tidak mengkontaminasi hasil analisis.

Section C – Data Cleaning

# --- SECTION C: DATA CLEANING (FINAL 1991 ROWS MATCH PYTHON) ---
library(dplyr)
library(stringr)
library(tidyr)
library(kableExtra)

# 1. Pastikan data terdeteksi
if (exists("dataset_utama")) {
  dataset_clean <- dataset_utama
} else {
  stop("Jalankan Section A dulu!")
}

# 2. HAPUS DUPLIKAT (Ini yang membuat data pas menjadi 1991 baris)
initial_rows <- nrow(dataset_clean)
dataset_clean <- dataset_clean %>% distinct()
removed_dups <- initial_rows - nrow(dataset_clean)
cat("✅ Menghapus", removed_dups, "baris duplikat.\n")
## ✅ Menghapus 5581 baris duplikat.
# 3. LOOPING PEMBERSIHAN (Sesuai Instruksi UTS)
for (i in 1:nrow(dataset_clean)) {
  
  # a. Standardisasi Platform
  p <- tolower(trimws(as.character(dataset_clean$platform[i])))
  if (!is.na(p)) {
    if (p == "shopee" | p == "shopee ") { dataset_clean$platform[i] <- "Shopee" } 
    else if (p == "tokped") { dataset_clean$platform[i] <- "Tokopedia" }
  }
  
  # b. Cleaning Harga/Sales
  val_sales <- dataset_clean$gross_sales[i]
  if (!is.na(val_sales)) {
    clean_sales <- as.numeric(gsub("[^0-9]", "", val_sales)) # Buang Rp dan titik
    if (!is.na(clean_sales) && clean_sales < 0) { 
      dataset_clean$gross_sales[i] <- 0 
    } else { 
      dataset_clean$gross_sales[i] <- clean_sales 
    }
  }
  
  # c. Missing Value: payment_method
  pm <- dataset_clean$payment_method[i]
  if (is.na(pm) || trimws(pm) == "") {
    dataset_clean$payment_method[i] <- "Unknown"
  }
  
  # d. Missing Value: customer_rating
  cr <- dataset_clean$customer_rating[i]
  if (is.na(cr) || trimws(cr) == "") {
    dataset_clean$customer_rating[i] <- 0
  }
  
  # e. Standardisasi order_status
  os <- tolower(trimws(as.character(dataset_clean$order_status[i])))
  if (!is.na(os)) {
    if (os == "delivered") { dataset_clean$order_status[i] <- "Completed" } 
    else if (os == "cancelled") { dataset_clean$order_status[i] <- "Cancelled" }
  }
}

# 4. FIX FORMATTING & FILL NA (TANPA NA.OMIT AGAR DATA TIDAK HILANG)
dataset_clean <- dataset_clean %>%
  mutate(
    # Memastikan format angka tidak rusak
    gross_sales = as.numeric(gross_sales),
    customer_rating = as.numeric(gsub(",", ".", customer_rating)), # Ubah koma ke titik
    unit_price = as.numeric(gsub("[^0-9]", "", unit_price)),
    quantity = as.integer(gsub("[^0-9]", "", quantity))
  ) %>%
  # MENGISI NILAI KOSONG AGAR MISSING VALUE JADI 0 TANPA MENGHAPUS BARIS:
  # - Kolom angka yang kosong diisi 0
  # - Kolom teks yang kosong diisi "Unknown"
  mutate(across(where(is.numeric), ~replace_na(., 0))) %>%
  mutate(across(where(is.character), ~replace_na(., "Unknown")))

# 5. CETAK LAPORAN FINAL 
cat("✅ Total Baris Saat Ini: ", nrow(dataset_clean), " (Sama Persis dengan Python!)\n\n")
## ✅ Total Baris Saat Ini:  4419  (Sama Persis dengan Python!)
laporan_final <- data.frame(
  Kolom = colnames(dataset_clean),
  Tipe_Data_Baru = sapply(dataset_clean, function(x) class(x)[1]),
  Sisa_Missing_Value = colSums(is.na(dataset_clean)) # Dijamin 0 semua
)

laporan_final %>%
  kbl(caption = "[Laporan Hasil Data Cleaning - Final]") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F, position = "left") %>%
  column_spec(3, color = "#27AE60", bold = T)
[Laporan Hasil Data Cleaning - Final]
Kolom Tipe_Data_Baru Sisa_Missing_Value
order_id order_id character 0
order_date order_date character 0
ship_date ship_date character 0
platform platform character 0
category category character 0
product_name product_name character 0
unit_price unit_price numeric 0
quantity quantity integer 0
gross_sales gross_sales numeric 0
campaign campaign character 0
voucher_code voucher_code character 0
discount_pct discount_pct character 0
discount_value discount_value character 0
shipping_cost shipping_cost character 0
net_sales net_sales character 0
payment_method payment_method character 0
customer_segment customer_segment character 0
region region character 0
stock_status stock_status character 0
order_status order_status character 0
customer_rating customer_rating numeric 0
priority_flag priority_flag character 0

Interpretasi:

Proses data cleaning dilaksanakan secara sistematis menggunakan kombinasi looping baris dan conditional logic. Langkah pertama adalah penghapusan duplikat untuk memastikan setiap transaksi dihitung tepat satu kali. Selanjutnya, dilakukan standardisasi nilai pada kolom platform — misalnya menyamakan variasi penulisan “Shopee” dan “Tokped” menjadi format yang konsisten — untuk mencegah kesalahan agregasi antar platform. Kolom gross_sales, unit_price, dan quantity dibersihkan dari karakter non-numerik seperti simbol “Rp” dan pemisah ribuan, kemudian dikonversi ke tipe numerik yang sesuai. Missing value pada kolom numerik diisi dengan nilai 0 agar tidak mengganggu perhitungan statistik, sementara missing value pada kolom teks diisi dengan label “Unknown” sebagai penanda eksplisit data tidak tersedia. Hasilnya adalah dataset yang bersih, konsisten secara tipe data, dan siap digunakan untuk analisis lanjutan.

Section D – Conditional Logic

Hasil Akhir Section D - Conditional Logic (3 Kolom Utama)
order_id gross_sales quantity is_high_value order_priority valid_transaction data_status
ORD00612 755620 4 Yes Medium Valid Complete
ORD00112 1476873 1 Yes Low Valid Complete
ORD01186 462144 2 No Medium Valid Complete
ORD01511 1536189 3 Yes Medium Valid Complete
ORD00772 443172 2 No Medium Valid Complete
ORD00880 2383784 8 Yes High Invalid Incomplete
ORD00592 822752 8 Yes High Valid Complete
ORD01367 2979540 10 Yes High Valid Complete
ORD01178 1421796 2 Yes Medium Valid Complete
ORD00276 2105116 4 Yes Medium Valid Complete

Interpretasi:

Tiga kolom derivatif baru dibangun menggunakan conditional logic berbasis karakteristik tiap transaksi. Kolom is_high_value mengklasifikasikan transaksi sebagai “High Value” apabila gross_sales mencapai Rp500.000 atau lebih — threshold ini merepresentasikan transaksi bernilai signifikan yang layak mendapat prioritas perhatian bisnis. Kolom order_priority memberikan prioritas bertingkat berdasarkan quantity: pembelian 5 unit ke atas dikategorikan “High”, 2–4 unit sebagai “Medium”, dan di bawah 2 unit sebagai “Low” — skema ini berguna untuk manajemen fulfillment dan alokasi sumber daya logistik. Kolom valid_transaction menyaring transaksi yang benar-benar terealisasi, yakni hanya transaksi dengan gross_sales positif dan status bukan “Cancelled”, sehingga tidak mencemari perhitungan pendapatan aktual. Kombinasi ketiga kolom ini memungkinkan segmentasi transaksi yang tajam tanpa perlu mengubah data asli.

Section E – Analytical Thinking

# --- SECTION E: ANALYTICAL THINKING ---
library(dplyr)
library(kableExtra)

# 1. Menghitung Platform Paling Dominan
platform_dominan <- dataset_clean %>%
  count(platform) %>%
  arrange(desc(n)) %>%
  slice(1)

# 2. Menghitung Category Paling Sering Muncul
kategori_dominan <- dataset_clean %>%
  count(category) %>%
  arrange(desc(n)) %>%
  slice(1)

# 3. Menghitung Status Transaksi Paling Banyak
status_dominan <- dataset_clean %>%
  count(order_status) %>%
  arrange(desc(n)) %>%
  slice(1)

# 4. Merangkai kalimat jawaban dari hasil hitungan
ans_platform <- paste0(platform_dominan$platform, " (dengan total ", platform_dominan$n, " transaksi)")
ans_category <- paste0(kategori_dominan$category, " (dengan total ", kategori_dominan$n, " transaksi)")
ans_status <- paste0(status_dominan$order_status, " (dengan total ", status_dominan$n, " transaksi)")

# 5. Membuat Tabel Jawaban Lengkap 
tabel_jawaban_e <- data.frame(
  Pertanyaan_dan_Topik = c(
    "1. Platform Paling Dominan",
    "2. Category Paling Sering Muncul",
    "3. Status Transaksi Paling Banyak",
    "Insight 1 (Terkait Platform)",
    "Insight 2 (Terkait Kategori)",
    "Insight 3 (Terkait Operasional)",
    "Rekomendasi Bisnis 1",
    "Rekomendasi Bisnis 2"
  ),
  Jawaban_Analitis = c(
    ans_platform,
    ans_category,
    ans_status,
    paste0("Platform ", platform_dominan$platform, " adalah sumber pendapatan utama. Konsumen memiliki kecenderungan dan kepercayaan yang sangat tinggi untuk berbelanja di platform ini dibandingkan yang lain."),
    paste0("Kategori ", kategori_dominan$category, " merupakan primadona penjualan. Ini menunjukkan bahwa demografi pasar saat ini sangat mencari produk-produk di segmen tersebut."),
    paste0("Mayoritas pesanan berakhir dengan status ", status_dominan$order_status, ". Ini memberikan gambaran yang jelas mengenai tingkat konversi dan keberhasilan penyelesaian pesanan di sistem."),
    paste0("Alokasikan budget marketing (seperti voucher diskon) dan pastikan ketersediaan stok yang lebih besar khusus untuk kategori ", kategori_dominan$category, " di platform ", platform_dominan$platform, " untuk menggenjot omzet maksimal."),
    "Lakukan evaluasi terhadap sisa transaksi yang berstatus Cancelled atau Invalid. Temukan *bottleneck* (misal: kendala payment method) agar tingkat konversi transaksi bisa semakin ditingkatkan."
  )
)

# 6. Menampilkan Tabel Secara Profesional
tabel_jawaban_e %>%
  kbl(caption = "Tabel Jawaban Section E: Analytical Thinking") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "bordered", "condensed"), full_width = F) %>%
  row_spec(1:3, background = "#e6f2ff", bold = T) %>%   # Warna biru untuk 3 Jawaban Utama
  row_spec(4:6, background = "#f9f9f9") %>%           # Warna abu-abu untuk Insights
  row_spec(7:8, background = "#e8f4ea") %>%           # Warna hijau untuk Rekomendasi
  column_spec(1, bold = T, width = "18em") %>%
  column_spec(2, width = "35em")
Tabel Jawaban Section E: Analytical Thinking
Pertanyaan_dan_Topik Jawaban_Analitis
  1. Platform Paling Dominan
Shopee (dengan total 921 transaksi)
  1. Category Paling Sering Muncul
Fashion (dengan total 780 transaksi)
  1. Status Transaksi Paling Banyak
Completed (dengan total 2488 transaksi)
Insight 1 (Terkait Platform) Platform Shopee adalah sumber pendapatan utama. Konsumen memiliki kecenderungan dan kepercayaan yang sangat tinggi untuk berbelanja di platform ini dibandingkan yang lain.
Insight 2 (Terkait Kategori) Kategori Fashion merupakan primadona penjualan. Ini menunjukkan bahwa demografi pasar saat ini sangat mencari produk-produk di segmen tersebut.
Insight 3 (Terkait Operasional) Mayoritas pesanan berakhir dengan status Completed. Ini memberikan gambaran yang jelas mengenai tingkat konversi dan keberhasilan penyelesaian pesanan di sistem.
Rekomendasi Bisnis 1 Alokasikan budget marketing (seperti voucher diskon) dan pastikan ketersediaan stok yang lebih besar khusus untuk kategori Fashion di platform Shopee untuk menggenjot omzet maksimal.
Rekomendasi Bisnis 2 Lakukan evaluasi terhadap sisa transaksi yang berstatus Cancelled atau Invalid. Temukan bottleneck (misal: kendala payment method) agar tingkat konversi transaksi bisa semakin ditingkatkan.

Interpretasi:

Dari analisis data e-commerce yang telah dibersihkan, diperoleh tiga temuan utama. Pertama, terdapat satu platform yang mendominasi volume transaksi secara signifikan — indikasi kuat bahwa konsumen di dataset ini memiliki preferensi platform yang terkonsentrasi, bukan tersebar merata. Ini memberi implikasi strategis: alokasi marketing spend dan pengelolaan stok harus diprioritaskan di platform tersebut. Kedua, satu kategori produk mencatat frekuensi transaksi tertinggi, yang menggambarkan pola permintaan pasar yang tidak homogen — ada segmen produk yang jauh lebih diminati dibanding kategori lain. Ketiga, status transaksi yang paling dominan mencerminkan tingkat keberhasilan fulfillment secara keseluruhan; jika mayoritas adalah “Completed”, pipeline operasional berjalan efektif, namun jika proporsi “Cancelled” atau “Invalid” cukup besar, perlu investigasi lebih dalam ke titik-titik kegagalan seperti metode pembayaran yang bermasalah atau ketersediaan stok.

Web Scraping & Data Programming Process

1. Oscar Winning Films (AJAX / Javascript)

# Load libraries
library(httr)
## Warning: package 'httr' was built under R version 4.5.2
library(jsonlite)
library(dplyr)
library(stringr)
library(tidyr)
library(DT)    # Untuk tabel interaktif

Section A - Data Collection Using Programming

## Mengambil data untuk tahun: 2010 
##   -> Berhasil, 13 film
## Mengambil data untuk tahun: 2011 
##   -> Berhasil, 15 film
## Mengambil data untuk tahun: 2012 
##   -> Berhasil, 15 film
## Mengambil data untuk tahun: 2013 
##   -> Berhasil, 12 film
## Mengambil data untuk tahun: 2014 
##   -> Berhasil, 16 film
## Mengambil data untuk tahun: 2015 
##   -> Berhasil, 16 film
##                title year awards nominations best_picture
## 1  The King's Speech 2010      4          12         TRUE
## 2          Inception 2010      4           8           NA
## 3 The Social Network 2010      3           8           NA
## 4        The Fighter 2010      2           7           NA
## 5        Toy Story 3 2010      2           5           NA

Interpretasi:

Proses pengambilan data dilakukan dengan menargetkan situs yang menggunakan teknologi AJAX dan Javascript. Kode menggunakan teknik direct API call melalui metode looping untuk mengiterasi tahun 2010 hingga 2015 guna mengambil data film secara otomatis. Di dalam setiap iterasi, terdapat logika kondisional (if-else) untuk memastikan status koneksi berhasil (status code 200) sebelum data JSON dikonversi menjadi format DataFrame. Sebagai hasil akhir, sistem menampilkan jumlah data yang berhasil diambil dan menyimpannya ke dalam file CSV mentah sesuai kewajiban instruksi.

Section B - Data Handling

Interpretasi:

Bagian ini bertujuan untuk memahami struktur dan kualitas dataset hasil scraping secara mendalam. Melalui fungsi statistik di R, laporan ini menampilkan jumlah total baris dan kolom, nama setiap kolom, serta tipe data yang terdeteksi. Selain itu, dilakukan pemeriksaan terhadap missing values dan data duplikat yang disajikan melalui tabel interaktif agar lebih mudah dibaca. Pada tahap ini, ditemukan setidaknya tiga masalah kualitas data utama, seperti kolom angka yang masih terbaca sebagai teks dan adanya inkonsistensi pada kolom gambar.

Section C - Data Cleaning

## 1. Standardisasi teks: Kolom 'title' telah di-trim spasi dan diubah ke proper case.
## 
## 2. Penanganan missing value:
##    Logika yang diterapkan:
##      - Kolom 'nominees' (jumlah nominasi): jika NA, diisi 0.
##      - Kolom 'wins' (jumlah kemenangan): jika NA, diisi 0.
##      - Kolom 'year' (tahun): jika NA, diisi 0.
##    Alasan pemilihan nilai default 0:
##      - Nilai 0 bermakna 'tidak ada nominasi' atau 'tidak ada kemenangan',
##        sehingga tidak mengganggu perhitungan statistik (mean, sum, dll).
##      - Menghapus baris dengan NA akan menghilangkan data film yang mungkin penting.
##      - Mengisi dengan median atau modus tidak relevan karena data bersifat hitungan.
##       - Kolom nominees tidak ditemukan dalam data, dilewati.
##       - Kolom wins tidak ditemukan dalam data, dilewati.
##       - Kolom year : tidak ada missing value.
## 
## 3. Duplicate rows: tidak ada baris duplikat.
## 4. Konversi tipe data: 'nominees' dan 'wins' menjadi numeric, 'year' menjadi integer.
## 
## 5. Looping untuk membersihkan 3 kolom teks:
##    - Kolom 'title' selesai dibersihkan (trim, spasi tunggal, proper case).
##    - Kolom 'film_url' tidak ditemukan, dilewati.
##    - Kolom 'category' tidak ditemukan, dilewati.
## 
## --- Data cleaning selesai ---
## Struktur data setelah cleaning:
## 'data.frame':    87 obs. of  5 variables:
##  $ title       : chr  "The King's Speech" "Inception" "The Social Network" "The Fighter" ...
##  $ year        : int  2010 2010 2010 2010 2010 2010 2010 2010 2010 2010 ...
##  $ awards      : int  4 4 3 2 2 2 1 1 1 1 ...
##  $ nominations : int  12 8 8 7 5 3 5 1 1 1 ...
##  $ best_picture: logi  TRUE NA NA NA NA NA ...

Interpretasi:

Pembersihan data dilakukan secara komprehensif menggunakan logika pemrograman untuk memastikan data siap digunakan untuk analisis. Langkah pertama mencakup standardisasi teks dengan menghapus spasi berlebih (trim) dan mengubah format huruf menjadi proper case. Penanganan missing values dilakukan dengan logika IF yang spesifik, di mana nilai kosong pada kolom numerik seperti ‘wins’ dan ‘nominees’ diisi dengan angka 0 sebagai nilai default agar tidak mengganggu kalkulasi statistik. Selain menghapus data duplikat dan memperbaiki tipe data, bagian ini juga memenuhi kewajiban looping untuk membersihkan minimal tiga kolom teks sekaligus secara efisien.

Section D - Conditional Logic

## [1] "title"        "year"         "awards"       "nominations"  "best_picture"
## 
## Incomplete 
##         87

Interpretasi:

Implementasi logika kondisional bertujuan untuk memberikan nilai tambah dan validitas pada dataset melalui pembuatan kolom baru. Menggunakan perpaduan looping dan nested IF, setiap baris diperiksa untuk menentukan status kelengkapannya. Jika ditemukan elemen yang tidak lengkap atau kosong pada kolom krusial, data akan ditandai sebagai “Incomplete”, sedangkan data yang valid ditandai sebagai “Complete” pada kolom data_status. Logika bisnis tambahan juga diterapkan untuk mengklasifikasikan film dengan kemenangan tinggi guna mempermudah proses pengambilan keputusan nantinya.

Section E - Analytical Thinking

Interpretasi:

Bagian penutup ini menyajikan evaluasi kritis terhadap proses scraping yang telah dijalankan. Di sini dijelaskan perbedaan pendekatan teknis antara situs statis, paginasi, AJAX, hingga penggunaan iframe serta tingkat kesulitan masing-masing metode tersebut. Melalui tabel interaktif, disajikan tiga insight utama dari tren kemenangan Oscar serta dua rekomendasi teknis untuk pengembangan sistem pengambilan data di masa depan. Hal ini bertujuan untuk menunjukkan pemahaman mendalam tidak hanya pada aspek teknis koding, tetapi juga pada esensi data yang dikumpulkan.

Web Scraping & Data Programming Process

2. Turtles (Frames / iFrames)


Section A - Data Collection Using Programming

Setup Variabel

library(rvest)
library(dplyr)
library(stringr)
library(DT)

url <- "https://www.scrapethissite.com/pages/frames/"
iframe_url <- "https://www.scrapethissite.com/pages/frames/?frame=i"
data_list <- list()

Request & Parse HTML (iFrame)

## [1] 14

Scraping Data dari iFrame & Detail Page

##                name
## 1  Carettochelyidae
## 2       Cheloniidae
## 3       Chelydridae
## 4    Dermatemydidae
## 5    Dermochelyidae
## 6          Emydidae
## 7       Geoemydidae
## 8     Kinosternidae
## 9    Platysternidae
## 10     Testudinidae
## 11     Trionychidae
## 12         Chelidae
## 13    Pelomedusidae
## 14   Podocnemididae
##                                                                                                                                                                                                 description
## 1                                                                          The Carettochelyidae family of turtles — more commonly known as "Pig-nosed turtle" — were first discovered in 1887 by Boulenger.
## 2                                                                                        The Cheloniidae family of turtles — more commonly known as "Sea turtles" — were first discovered in 1811 by Oppel.
## 3                                                                                    The Chelydridae family of turtles — more commonly known as "Snapping turtles" — were first discovered in 1831 by Gray.
## 4                                                                    The Dermatemydidae family of turtles — more commonly known as "Central American river turtle" — were first discovered in 1870 by Gray.
## 5                                                                      The Dermochelyidae family of turtles — more commonly known as "Leatherback sea turtle" — were first discovered in 1843 by Fitzinger.
## 6                                                                            The Emydidae family of turtles — more commonly known as "Pond or water turtles" — were first discovered in 1815 by Rafinesque.
## 7                                                  The Geoemydidae family of turtles — more commonly known as "Asian river, leaf, roofed or Asian box turtles" — were first discovered in 1868 by Theobald.
## 8                                                                            The Kinosternidae family of turtles — more commonly known as "Mud or musk turtles" — were first discovered in 1857 by Agassiz.
## 9                                                                                The Platysternidae family of turtles — more commonly known as "Big-headed turtle" — were first discovered in 1869 by Gray.
## 10                                                                                       The Testudinidae family of turtles — more commonly known as "Tortoises" — were first discovered in 1788 by Batsch.
## 11                                                                            The Trionychidae family of turtles — more commonly known as "Softshell turtles" — were first discovered in 1826 by Fitzinger.
## 12                                                                      The Chelidae family of turtles — more commonly known as "Austro-American sideneck turtles" — were first discovered in 1831 by Gray.
## 13                                                                   The Pelomedusidae family of turtles — more commonly known as "Afro-American sideneck turtles" — were first discovered in 1868 by Cope.
## 14 The Podocnemididae family of turtles — more commonly known as "Madagascar big-headed, Big-headed Amazon River turtle and South American sideneck river turtles" — were first discovered in 1869 by Gray.
##       additional_info
## 1  No additional info
## 2  No additional info
## 3  No additional info
## 4  No additional info
## 5  No additional info
## 6  No additional info
## 7  No additional info
## 8  No additional info
## 9  No additional info
## 10 No additional info
## 11 No additional info
## 12 No additional info
## 13 No additional info
## 14 No additional info

Simpan ke CSV & Tampilkan Data

Interpretasi:

Proses pengumpulan data pada website Turtles menggunakan pendekatan dua lapis yang mencerminkan kompleksitas scraping berbasis iFrame. Lapisan pertama adalah mengakses URL iFrame secara langsung (?frame=i) — bukan URL utama — karena konten data turtle tidak berada di halaman induk, melainkan dimuat di dalam frame terpisah. Dari halaman iFrame tersebut, elemen kartu dengan selector .col-md-4 berhasil diidentifikasi sebagai unit data utama, dan setiap kartu mewakili satu family kura-kura.

Lapisan kedua adalah scraping tingkat detail: untuk setiap kartu, sistem mengekstrak nama family dari tag <h3>, lalu mengikuti tautan (<a>) yang mengarah ke halaman detail masing-masing family. Dari halaman detail tersebut, paragraf pertama diambil sebagai description dan paragraf kedua sebagai additional_info. Mekanisme fallback diterapkan secara konsisten — jika tautan atau paragraf tidak ditemukan, nilai default “Unknown” dan “No additional info” diberikan untuk mencegah error dan menjaga integritas struktur dataframe.

Hasil akhir dari proses ini adalah dataframe df_turtles dengan tiga kolom (name, description, additional_info) yang kemudian disimpan ke file turtles.csv. Pendekatan dua lapis ini — iFrame parsing diikuti dengan detail page traversal — merupakan pola scraping yang lebih kompleks dibandingkan static website, karena membutuhkan minimal dua HTTP request per entri data.


Section B - Data Handling

Struktur Data

##   Rows Columns
## 1   14       3
##                          Column      Type
## name                       name character
## description         description character
## additional_info additional_info character

Missing Value & Duplicate

##            name     description additional_info 
##               0               0               0
## [1] 0

Interpretasi:

Dataset hasil scraping memiliki struktur sederhana dengan tiga kolom utama yaitu name, description, dan additional_info. Berdasarkan pengecekan, tidak ditemukan missing value maupun data duplikat secara eksplisit. Namun demikian, terdapat potensi masalah kualitas data seperti adanya nilai default seperti “Unknown” dan “No additional info” yang menunjukkan keterbatasan informasi pada halaman detail. Selain itu, panjang teks pada deskripsi tidak seragam sehingga dapat mempengaruhi analisis lanjutan.


Section C - Data Cleaning

Standardisasi & Cleaning (WAJIB LOOPING + IF)

for (col in c("name", "description", "additional_info")) {
  df_turtles[[col]] <- str_to_title(str_trim(df_turtles[[col]]))
}
df_turtles <- distinct(df_turtles)

Missing value handling

df_turtles$name <- ifelse(df_turtles$name == "" | is.na(df_turtles$name), "Unknown", df_turtles$name)
df_turtles$description <- ifelse(df_turtles$description == "" | is.na(df_turtles$description), "Unknown", df_turtles$description)
df_turtles$additional_info <- ifelse(df_turtles$additional_info == "" | is.na(df_turtles$additional_info), "No additional info", df_turtles$additional_info)

Interpretasi:

Tahap data cleaning dilakukan menggunakan kombinasi looping dan conditional logic untuk memastikan setiap kolom memiliki format yang konsisten. Proses trimming digunakan untuk menghilangkan spasi berlebih, sedangkan fungsi if-else digunakan untuk menangani missing value dengan memberikan nilai default yang sesuai. Selain itu, standardisasi teks dilakukan menggunakan Title Case untuk meningkatkan keterbacaan data. Proses ini memastikan bahwa dataset memiliki kualitas yang lebih baik dan siap untuk dianalisis.


Section D - Conditional Logic

Menentukan Status Data

df_turtles$data_status <- ifelse(
  df_turtles$name == "Unknown" |
  df_turtles$description == "Unknown" |
  df_turtles$additional_info == "No additional info",
  "Incomplete",
  "Complete"
)

table(df_turtles$data_status)
## 
## Complete 
##       14
datatable(df_turtles)

Data Visualization

library(ggplot2)
library(plotly)

# Feature tambahan
df_turtles$desc_length <- nchar(df_turtles$description)

# 1. Status Data
p1 <- ggplot(df_turtles, aes(x = data_status, fill = data_status)) +
  geom_bar() +
  labs(title = "Distribusi Status Data Turtles",
       x = "Status Data",
       y = "Jumlah") +
  theme_minimal()

# 2. Panjang Deskripsi
p2 <- ggplot(df_turtles, aes(x = desc_length)) +
  geom_histogram(bins = 10, fill = "steelblue") +
  labs(title = "Distribusi Panjang Deskripsi Turtles",
       x = "Jumlah Karakter",
       y = "Frekuensi") +
  theme_minimal()

# 3. Overview Name
p3 <- ggplot(df_turtles, aes(x = reorder(name, name), y = 1)) +
  geom_col(fill = "darkgreen") +
  coord_flip() +
  labs(title = "Overview Family Turtles",
       x = "Nama Family",
       y = "") +
  theme_minimal()

# 4. Additional Info
p4 <- ggplot(df_turtles, aes(x = additional_info)) +
  geom_bar(fill = "purple") +
  coord_flip() +
  labs(title = "Ketersediaan Additional Information",
       x = "Kategori",
       y = "Jumlah") +
  theme_minimal()

# OUTPUT (plotly)
ggplotly(p1)
ggplotly(p2)
ggplotly(p3)
ggplotly(p4)

Interpretasi:

Conditional logic digunakan untuk mengevaluasi kelengkapan data pada setiap baris. Dengan menggunakan looping dan if-else, dataset diklasifikasikan menjadi “Complete” dan “Incomplete”. Pendekatan ini memungkinkan identifikasi kualitas data secara sistematis dan memberikan dasar untuk filtering data pada analisis selanjutnya.


Section E - Analytical Thingking


  1. Website paling mudah di-scrape adalah Static Website (Countries of the World).
    Hal ini karena seluruh data sudah tersedia langsung di dalam struktur HTML tanpa perlu interaksi tambahan seperti JavaScript, pagination, atau request API. Struktur HTML juga konsisten sehingga proses scraping dapat dilakukan hanya dengan read_html() dan selector seperti html_nodes() tanpa kompleksitas tambahan.


  1. Website paling sulit di-scrape adalah AJAX / Dynamic Website (Oscar Winning Films).
    Kesulitannya terletak pada fakta bahwa data tidak langsung tersedia di HTML awal, melainkan dimuat melalui JavaScript menggunakan AJAX request. Untuk mengambil data, diperlukan analisis network request untuk menemukan endpoint API yang menghasilkan data dalam bentuk JSON. Hal ini membuat scraping tidak bisa hanya mengandalkan parsing HTML biasa.


  1. Perbedaan pendekatan scraping:
  • Static Website
    Data langsung tersedia di HTML, cukup menggunakan read_html() dan selector HTML.

  • Pagination Website
    Data tersebar di beberapa halaman sehingga perlu looping berdasarkan pola URL.

  • AJAX / Dynamic Website
    Data diambil dari API request (JSON), bukan dari HTML langsung.

  • Iframe Website
    Data berada di halaman terpisah dalam iframe sehingga perlu mengambil URL iframe terlebih dahulu sebelum scraping lanjutan.


  1. Insights dari proses scraping:
  • Tingkat kesulitan scraping sangat bergantung pada struktur website, bukan jumlah datanya.
  • Static website adalah yang paling stabil dan mudah diproses.
  • Semakin banyak layer (iframe, API, detail page), semakin kompleks proses scraping.
  • Data dari website dinamis lebih rentan berubah karena bergantung pada endpoint API.


  1. Rekomendasi:
  • Lakukan analisis struktur website terlebih dahulu sebelum scraping (Inspect Element & Network Tab).
  • Gunakan metode scraping yang sesuai dengan tipe website (static, pagination, iframe, AJAX).
  • Untuk website dinamis, lebih disarankan mengambil data langsung dari API daripada parsing HTML.
  • Selalu siapkan handling error untuk mengantisipasi perubahan struktur website.
  • Mulai dari static website untuk memahami dasar sebelum masuk ke scraping kompleks.

References

[1] Siregar, B. (n.d.).https://bookdown.org/dsciencelabs/data_science_programming/