Data Transformation

Assignment ~ Week 9

Arya Fharezi

Arya Fharezi

NIM Mahasiswa : 52250008
Mahasiswa Sains Data Institut Teknologi Sains Bandung
Informasi Akademik
Mata Kuliah
:
Pemrograman Sains Data I
Dosen
:
Bakti Siregar, M.Sc., CDS.
Mahasiswa Aktif - Semester 2


1 Transformasi Temporal

Lag, Diff, dan Rolling Mean

Perhatikan kode R berikut yang melakukan transformasi temporal pada dataset data_bisnis menggunakan fungsi lag(), diff, dan rolling mean (library zoo).

Pertanyaan:

Mengapa kolom Lag_Quantity, Diff_Quantity, dan RollingMean_3 pada output menampilkan nilai NA? Jelaskan!

1.1 Kode & Output

# Load data
data_bisnis <- read.csv("6_Data-Transformation___Data_Science_Programming.csv")

library(knitr)
# (Contoh untuk Quantity, berdasarkan tanggal transaksi)
Tempral <- data_bisnis %>%
  arrange(Customer_ID, Transaction_Date) %>%
  group_by(Customer_ID) %>%
  mutate(
    Lag_Quantity  = lag(Quantity),
    Diff_Quantity = Quantity - lag(Quantity),
    RollingMean_3 = zoo::rollapply(Quantity, width = 3,
                    FUN = mean, fill = NA, align = 'right')
  ) %>%
  ungroup()

# Tampilkan 5 baris pertama
kable(head(Tempral, 5))
X Transaction_ID Transaction_Date Customer_ID Product_Category Product_ID Quantity Unit_Price Discount Region Sales_Channel Delivery_Time Total_Price Price_per_Unit Efficiency Feature_Interaction Cross_Term ID_Prefix ID_Length ID_HasPattern Discount_Level Sales_Rank Avg_Quantity_Region Sum_Sales_Region Count_Product_Region Lag_Quantity Diff_Quantity RollingMean_3
122 1PaWvGiAokHB 2023-02-09 02kNipUny9 Groceries P0253 3 13.11 0.07 East Offline 10 36.58 12.193333 0.300 0.21 Groceries_East P0 5 true 2 208 2.936508 4261.13 126 NA NA NA
400 IYlg0MAGwsUw 2020-11-30 04npfK5VJa Books P0113 3 15.90 0.24 North Offline 3 36.25 12.083333 1.000 0.72 Books_North P0 5 true 4 212 2.992908 4864.94 141 NA NA NA
201 0kgKWZOpEp6Z 2020-03-18 0NwgTyo7P2 Clothing P0445 5 2.65 0.20 North Offline 8 10.60 2.120000 0.625 1.00 Clothing_North P0 5 true 3 425 2.992908 4864.94 141 NA NA NA
412 ddFsMFlQOa2J 2023-05-19 0PlvCaxPuS Electronics P0298 3 9.12 0.20 East Online 8 21.89 7.296667 0.375 0.60 Electronics_East P0 5 true 3 335 2.936508 4261.13 126 NA NA NA
300 VOCzzxDOxQps 2020-07-07 0S9qOEuCr9 Clothing P0353 3 1.31 0.12 West Online 2 3.46 1.153333 1.500 0.36 Clothing_West P0 5 true 2 469 3.116667 4169.72 120 NA NA NA

1.2 Jawaban:

Analisis Kemunculan Nilai NA (Not Available)

Nilai NA (Not Available) dalam R muncul ketika suatu nilai tidak tersedia atau tidak bisa dihitung. Pada kasus ini, munculnya NA di ketiga kolom bukan berarti kodenya salah, tapi memang begitulah cara kerja fungsi-fungsi transformasi temporal yang digunakan.

Sebelum masuk ke penjelasan tiap kolom, berikut konteks kode yang relevan dengan munculnya NA:

  • arrange(Customer_ID, Transaction_Date) — Mengurutkan data berdasarkan Customer_ID lalu Transaction_Date, hal ini penting karena fungsi lag() dan rollapply() sangat bergantung pada urutan baris. Jika urutan salah, nilai NA bisa muncul di posisi yang tidak tepat.
  • group_by(Customer_ID) — Mengelompokkan per customer. Inilah penyebab utama NA muncul di baris pertama setiap customer, karena setiap grup selalu mulai dari awal tanpa riwayat data sebelumnya.

1. Kolom Lag_Quantity = lag(Quantity)

a. Definisi Fungsi lag()

Fungsi lag() dari paket dplyr bekerja dengan cara mengambil nilai dari baris sebelumnya dalam suatu urutan data. Sederhananya, nilai-nilai tersebut digeser ke bawah sebanyak n langkah, dengan default n = 1.

Rumus Konseptual:
Lag_Quantity[baris ke-n] = Quantity[baris ke-(n-1)]

Contoh sederhana (tanpa pengelompokan):
Quantity : 5   8   3   7
Lag_Quantity : NA  5   8   3

b. Pengaruh group_by(Customer_ID)

Karena kode menggunakan group_by(Customer_ID) sebelum mutate(), setiap Customer_ID dihitung secara terpisah. Artinya setiap kali berpindah ke Customer_ID baru, fungsi lag() mulai dari awal lagi tanpa mengambil nilai dari customer sebelumnya. Akibatnya, baris pertama dari setiap Customer_ID akan selalu NA karena tidak ada baris sebelumnya dalam kelompok tersebut.

2. Kolom Diff_Quantity = Quantity - lag(Quantity)

a. Definisi Operasi

Kolom Diff_Quantity berisi hasil pengurangan antara nilai Quantity saat ini dengan Lag_Quantity atau Quantity baris sebelumnya. Kolom ini digunakan untuk melihat selisih perubahan antar transaksi yang berurutan pada customer yang sama.

Hukum Propagasi NA dalam R:
angka + NA = NA
angka - NA = NA
angka * NA = NA

Contoh: 5 - NA = NA | 10 - NA = NA

b. Alur Terjadinya NA

Karena Lag_Quantity di baris pertama setiap Customer_ID bernilai NA, maka Quantity - NA otomatis menghasilkan NA juga. Diff_Quantity tidak bisa dihitung karena salah satu nilainya yaitu Lag_Quantity tidak tersedia.

3. Kolom RollingMean_3 = zoo::rollapply(…, width=3)

a. Definisi Fungsi rollapply()

Fungsi zoo::rollapply() menerapkan suatu fungsi pada window atau jendela data yang bergerak dengan lebar tertentu. Dalam kasus ini fungsi yang dipakai adalah mean, sehingga menghasilkan Rolling Mean yaitu rata-rata dari sejumlah n data terakhir yang terus bergerak seiring berjalannya waktu.

Parameter Penting dalam Kode:
width = 3  # Jendela data yang digunakan berjumlah 3 baris berturut-turut
FUN = mean  # Fungsi yang diterapkan adalah rata-rata aritmatika
fill = NA  # Posisi yang tidak dapat dihitung diisi dengan nilai NA
align = ‘right’  # Window dihitung dari sisi kanan (data saat ini + 2 sebelumnya)

b. Mekanisme Rolling Window

Dengan align=‘right’ dan width=3, fungsi ini butuh data dari baris sekarang dan dua baris sebelumnya untuk bisa melakukan perhitungan. Kalau datanya belum cukup, nilainya akan diisi NA sesuai parameter fill=NA yang sudah diset di kode.

Baris Qty[n-2] Qty[n-1] Qty[n] Penjelasan Hasil
1 (pertama) - - 5 Hanya 1 data tersedia, butuh 3 NA
2 - 5 8 Hanya 2 data tersedia, butuh 3 NA
3 5 8 3 Sudah 3 data: (5+8+3)/3 5.33 ✓
4 8 3 7 Sudah 3 data: (8+3+7)/3 6.00 ✓

Keterangan: Warna kuning = NA (belum tersedia cukup data) | Warna hijau = berhasil dihitung

c. Pengaruh group_by(Customer_ID)

Sama seperti lag(), fungsi rollapply() juga dipengaruhi oleh group_by(Customer_ID). Setiap customer punya urutannya sendiri, sehingga rolling window tidak bisa mengambil data dari customer lain. Akibatnya, 2 baris pertama setiap Customer_ID selalu menghasilkan NA.

Kesimpulan

Semua NA yang muncul pada ketiga kolom tersebut terjadi karena fungsi-fungsi temporal yang digunakan membutuhkan data historis sebelumnya, sementara pengelompokan per Customer_ID membuat setiap grup selalu mulai dari awal tanpa riwayat data apapun.

Lag_Quantity
NA di baris ke-1 tiap customer

Diff_Quantity
NA di baris ke-1 tiap customer

RollingMean_3
NA di baris ke-1 & ke-2 tiap customer


2 Log Transform (log1p)

Log Transform

Pertanyaan: Jelaskan tentang log1p pada kode berikut.

2.1 Kode & Output

min_positive <- min(data_bisnis$Total_Price[data_bisnis$Total_Price > 0])

Log <- data_bisnis %>%
  mutate(
    Safe_Total_Price = ifelse(Total_Price <= 0, min_positive, Total_Price),
    Log_Total_Price  = log1p(Safe_Total_Price)
  )

# Tampilkan 5 baris pertama
kable(head(Log, 5))
X Transaction_ID Transaction_Date Customer_ID Product_Category Product_ID Quantity Unit_Price Discount Region Sales_Channel Delivery_Time Total_Price Price_per_Unit Efficiency Feature_Interaction Cross_Term ID_Prefix ID_Length ID_HasPattern Discount_Level Sales_Rank Avg_Quantity_Region Sum_Sales_Region Count_Product_Region Safe_Total_Price Log_Total_Price
1 7zmPHxF7XfN9 2021-07-14 BAl3Y7yxev Clothing P0370 2 15.18 0.00 North Online 5 30.36 15.18000 0.4000000 0.00 Clothing_North P0 5 true 1 253 2.992908 4864.94 141 30.36 3.445533
2 y4bCY9pKTBWU 2020-11-16 TYY0h5C190 Electronics P0185 5 10.22 0.15 West Offline 2 43.44 8.68800 2.5000000 0.75 Electronics_West P0 5 true 2 157 3.116667 4169.72 120 43.44 3.794140
3 8k0B7XX19Ykf 2023-03-22 nUX640AaXg Home P0443 3 17.74 0.05 West Online 8 50.56 16.85333 0.3750000 0.15 Home_West P0 5 true 1 121 3.116667 4169.72 120 50.56 3.942746
4 l8ahQz5YNOKz 2023-01-02 sBZyUSJLEP Home P0035 6 28.30 0.22 North Offline 8 132.44 22.07333 0.7500000 1.32 Home_North P0 5 true 3 4 2.992908 4864.94 141 132.44 4.893652
5 kmufgw8wx5qk 2023-06-05 GMfVH2ZWNX Groceries P0375 3 11.91 0.13 North Offline 7 31.09 10.36333 0.4285714 0.39 Groceries_North P0 5 true 2 246 2.992908 4864.94 141 31.09 3.468545

2.2 Jawaban:

Apa itu Log Transform dan log1p?

Log Transform adalah teknik transformasi data yang menggunakan fungsi logaritma untuk mengubah distribusi data yang miring (skewed) menjadi lebih mendekati distribusi normal. Teknik ini umum dipakai dalam data science untuk menangani data yang memiliki rentang nilai sangat lebar.

Rumus log1p(x)

log1p(x) = ln(1 + x)

Fungsi ini menambahkan 1 ke nilai x terlebih dahulu sebelum menghitung logaritmanya.

Bedanya dengan log() biasa:

Fungsi Rumus Masalah
log(x) ln(x) log(0) = -Inf
log1p(x) ln(1+x) log1p(0) = 0 ✓

Kenapa Pakai log1p dan Bukan log Biasa?

log1p lebih aman dari log biasa karena bisa menangani nilai 0 tanpa menghasilkan error -Inf. Selain itu, log1p juga lebih akurat secara numerik untuk nilai x yang sangat kecil (mendekati 0), karena log(1+x) biasa rentan kehilangan presisi akibat pembulatan floating point. Itulah mengapa log1p sering digunakan dalam transformasi data, terutama pada data bisnis seperti jumlah transaksi atau kuantitas barang yang bisa bernilai 0.

Mengapa ada Safe_Total_Price?

Safe_Total_Price = ifelse(Total_Price <= 0, min_positive, Total_Price)

Karena log tidak bisa menghitung nilai negatif atau nol (hasilnya NaN/error), maka:

  • Jika Total_Price <= 0 → diganti dengan min_positive (nilai positif terkecil di dataset)
  • Jika Total_Price > 0 → tetap pakai nilai aslinya

Baru setelah aman, dilakukan log transform: Log_Total_Price = log1p(Safe_Total_Price)

Mengapa perlu Log Transform?

  • Data harga (Total_Price) biasanya memiliki distribusi right-skewed (ada nilai yang sangat besar/outlier)
  • Setelah log transform, distribusi menjadi lebih normal
  • Model statistik dan machine learning bekerja lebih baik pada data yang terdistribusi normal
Kesimpulan

Log Transform digunakan untuk menormalkan distribusi data yang skewed. log1p() dipilih karena aman untuk nilai 0, dan Safe_Total_Price dibuat terlebih dahulu untuk menghindari error pada nilai negatif atau nol sebelum transformasi dilakukan. Log1p juga lebih akurat secara numerik untuk nilai x yang sangat kecil mendekati 0, tidak hanya sekadar “aman dari error”.


3 Robust Scaling

Scaling & Normalization

Pertanyaan: Jelaskan tentang teknik Robust Scaling.

3.1 Kode & Output

# Robust Scaling
data_robust <- data_bisnis %>%
  mutate(
    Quantity_Robust   = (Quantity   - median(Quantity))   / IQR(Quantity),
    Unit_Price_Robust = (Unit_Price - median(Unit_Price)) / IQR(Unit_Price)
  )

# Tampilkan 5 baris pertama
kable(head(data_robust, 5))
X Transaction_ID Transaction_Date Customer_ID Product_Category Product_ID Quantity Unit_Price Discount Region Sales_Channel Delivery_Time Total_Price Price_per_Unit Efficiency Feature_Interaction Cross_Term ID_Prefix ID_Length ID_HasPattern Discount_Level Sales_Rank Avg_Quantity_Region Sum_Sales_Region Count_Product_Region Quantity_Robust Unit_Price_Robust
1 7zmPHxF7XfN9 2021-07-14 BAl3Y7yxev Clothing P0370 2 15.18 0.00 North Online 5 30.36 15.18000 0.4000000 0.00 Clothing_North P0 5 true 1 253 2.992908 4864.94 141 -0.5 0.2375237
2 y4bCY9pKTBWU 2020-11-16 TYY0h5C190 Electronics P0185 5 10.22 0.15 West Offline 2 43.44 8.68800 2.5000000 0.75 Electronics_West P0 5 true 2 157 3.116667 4169.72 120 1.0 -0.3891346
3 8k0B7XX19Ykf 2023-03-22 nUX640AaXg Home P0443 3 17.74 0.05 West Online 8 50.56 16.85333 0.3750000 0.15 Home_West P0 5 true 1 121 3.116667 4169.72 120 0.0 0.5609602
4 l8ahQz5YNOKz 2023-01-02 sBZyUSJLEP Home P0035 6 28.30 0.22 North Offline 8 132.44 22.07333 0.7500000 1.32 Home_North P0 5 true 3 4 2.992908 4864.94 141 1.5 1.8951358
5 kmufgw8wx5qk 2023-06-05 GMfVH2ZWNX Groceries P0375 3 11.91 0.13 North Offline 7 31.09 10.36333 0.4285714 0.39 Groceries_North P0 5 true 2 246 2.992908 4864.94 141 0.0 -0.1756159
# Tabel Ringkasan Robust Scaling
kesimpulan <- data.frame(
  Metrik = c("Median Before", "Median After", "IQR Before", "IQR After",
             "Min Value", "Max Value", "Method Used"),
  Quantity = c(
    round(median(data_bisnis$Quantity), 2),
    round(median(data_robust$Quantity_Robust), 2),
    round(IQR(data_bisnis$Quantity), 2),
    round(IQR(data_robust$Quantity_Robust), 2),
    round(min(data_robust$Quantity_Robust), 2),
    round(max(data_robust$Quantity_Robust), 2),
    "(X - Median) / IQR"
  ),
  Unit_Price = c(
    round(median(data_bisnis$Unit_Price), 2),
    round(median(data_robust$Unit_Price_Robust), 2),
    round(IQR(data_bisnis$Unit_Price), 2),
    round(IQR(data_robust$Unit_Price_Robust), 2),
    round(min(data_robust$Unit_Price_Robust), 2),
    round(max(data_robust$Unit_Price_Robust), 2),
    "(X - Median) / IQR"
  )
)

kable(kesimpulan, caption = "**Kesimpulan Robust Scaling**", align = 'c')
Kesimpulan Robust Scaling
Metrik Quantity Unit_Price
Median Before 3 13.3
Median After 0 0
IQR Before 2 7.91
IQR After 1 1
Min Value -1.5 -1.84
Max Value 3 2.21
Method Used (X - Median) / IQR (X - Median) / IQR

3.2 Jawaban:

Apa itu Robust Scaling?

Robust Scaling menggunakan median dan IQR (Interquartile Range) sebagai dasar perhitungannya, karena kedua ukuran tersebut tidak sensitif terhadap outlier. Nilai mean misalnya, akan langsung bergeser jika terdapat satu nilai ekstrem dalam data. Sementara median tetap stabil karena hanya mempertimbangkan posisi tengah data, bukan besaran nilainya.

Rumus Robust Scaling

\[\text{Robust_Scaled} = \frac{x - \text{median}}{\text{IQR}}\]

Penjelasan Kode Per Baris

  • data_robust <- data_bisnis %>% — Membuat dataframe baru bernama data_robust yang bersumber dari data_bisnis, kemudian diteruskan ke fungsi berikutnya menggunakan pipe %>%.
  • mutate( — Digunakan untuk menambahkan kolom-kolom baru ke dalam dataframe.
  • Quantity_Robust = (Quantity - median(Quantity)) / IQR(Quantity) — Membuat kolom baru dengan cara mengurangi setiap nilai Quantity dengan nilai mediannya, lalu dibagi IQR-nya sehingga menghasilkan nilai yang terskalakan dan tahan terhadap outlier.
  • Unit_Price_Robust = (Unit_Price - median(Unit_Price)) / IQR(Unit_Price) — Melakukan proses yang sama pada kolom Unit_Price.
  • kable(head(data_robust, 5)) — Menampilkan 5 baris pertama dari dataframe data_robust dalam format tabel yang rapi.

Interpretasi Hasil

Berdasarkan hasil analisis, kedua variabel yaitu Quantity dan Unit_Price berhasil ditransformasi menggunakan Robust Scaling. Setelah transformasi, nilai median menjadi 0 dan IQR menjadi 1 pada kedua variabel.

Keunggulan utama Robust Scaling terletak pada ketahanannya terhadap outlier. Hal ini karena metode ini menggunakan median dan IQR yang tidak mudah terpengaruh oleh nilai ekstrem, berbeda dengan mean dan standar deviasi yang digunakan pada metode lain.

Kesimpulan

Robust Scaling adalah metode normalisasi yang menggunakan median dan IQR sehingga tahan terhadap outlier. Data yang telah di-scaling menjadi lebih stabil dan siap digunakan untuk analisis lanjutan seperti regresi, klasifikasi, maupun model machine learning yang membutuhkan skala data seragam.


Referensi

  1. Wickham, H., Çetinkaya-Rundel, M., & Grolemund, G. (2023). R for Data Science (2nd ed.). O’Reilly Media.
    [Akses Edisi Ke-2 Online]
  2. Siregar, B. (n.d.). Data Science Programming. Bookdown.
    [Akses Online]