1 Pendahuluan

1.1 Latar Belakang

Kapal Titanic tenggelam pada 15 April 1912 dalam pelayaran perdananya. Dari ribuan orang di kapal, hanya sebagian yang selamat. Ada anggapan umum bahwa saat evakuasi, perempuan dan anak-anak didahulukan. Lewat tugas analisis data eksploratif ini, saya ingin melihat apakah anggapan itu memang terlihat pada datanya.

Analisis ini awalnya dikerjakan secara berkelompok (Kelompok 5). Pada versi ini saya merapikan dan melengkapinya sendiri, terutama bagian yang menjawab pertanyaan analisis.

1.2 Rumusan Masalah

  1. Bagaimana distribusi jenis kelamin penumpang Titanic?
  2. Bagaimana distribusi umur penumpang Titanic?
  3. Apakah ada perbedaan status keselamatan berdasarkan jenis kelamin?
  4. Apakah ada perbedaan status keselamatan berdasarkan umur?
  5. Bagaimana pola keselamatan berdasarkan kombinasi jenis kelamin dan kelompok umur?

1.3 Tujuan

Mengetahui pola hubungan antara jenis kelamin dan umur dengan status keselamatan penumpang. Variabel yang dipakai: PassengerId, Sex, Age, dan Survived.

2 Data

2.1 Sumber dan Variabel

Data diambil dari Kaggle (Elyamadad, n.d.): https://www.kaggle.com/datasets/elyamadad/titanic-dataset. Satu baris mewakili satu penumpang, dan ada 12 variabel.

variabel <- tribble(
  ~Variabel,     ~Keterangan,                 ~Jenis,                ~Skala,
  "PassengerId", "ID penumpang",              "Kualitatif",          "Nominal",
  "Survived",    "Status keselamatan",        "Kualitatif",          "Nominal",
  "Pclass",      "Kelas tiket",               "Kualitatif",          "Ordinal",
  "Name",        "Nama penumpang",            "Kualitatif",          "Nominal",
  "Sex",         "Jenis kelamin",             "Kualitatif",          "Nominal",
  "Age",         "Umur",                      "Kuantitatif kontinu", "Rasio",
  "SibSp",       "Jumlah saudara/pasangan",   "Kuantitatif diskrit", "Rasio",
  "Parch",       "Jumlah orang tua/anak",     "Kuantitatif diskrit", "Rasio",
  "Ticket",      "Nomor tiket",               "Kualitatif",          "Nominal",
  "Fare",        "Harga tiket",               "Kuantitatif kontinu", "Rasio",
  "Cabin",       "Kode kabin",                "Kualitatif",          "Nominal",
  "Embarked",    "Pelabuhan keberangkatan",   "Kualitatif",          "Nominal"
)
kable(variabel)
Variabel Keterangan Jenis Skala
PassengerId ID penumpang Kualitatif Nominal
Survived Status keselamatan Kualitatif Nominal
Pclass Kelas tiket Kualitatif Ordinal
Name Nama penumpang Kualitatif Nominal
Sex Jenis kelamin Kualitatif Nominal
Age Umur Kuantitatif kontinu Rasio
SibSp Jumlah saudara/pasangan Kuantitatif diskrit Rasio
Parch Jumlah orang tua/anak Kuantitatif diskrit Rasio
Ticket Nomor tiket Kualitatif Nominal
Fare Harga tiket Kuantitatif kontinu Rasio
Cabin Kode kabin Kualitatif Nominal
Embarked Pelabuhan keberangkatan Kualitatif Nominal

2.2 5W+1H

Pertanyaan Jawaban
Apa isi datanya? Karakteristik penumpang Titanic dan status keselamatannya
Siapa yang mengumpulkan? Tidak diketahui (anonim), data penumpang berasal dari catatan sejarah dan dilengkapi Encyclopedia Titanica
Kapan? Peristiwanya 15 April 1912, tanggal pengumpulan datanya tidak dicantumkan di Kaggle
Dari mana? Kaggle, merujuk ke buku Titanic: Triumph and Tragedy (Eaton & Haas, 1994)
Mengapa? Untuk menganalisis faktor yang berkaitan dengan keselamatan, seperti umur, jenis kelamin, dan kelas tiket
Bagaimana disusun? Berupa tabel, baris = penumpang, kolom = variabel. Data dictionary tersedia di halaman Kaggle

2.3 Membaca Data

path_data <- NULL   # contoh: "C:/Users/nama/Downloads/dataset_titanic_clean.xlsx"

# kalau path_data kosong, cari otomatis file xlsx yang namanya ada kata "titanic"
if (is.null(path_data)) {
  kandidat <- list.files(getwd(), pattern = "titanic.*\\.xlsx?$",
                         ignore.case = TRUE, full.names = TRUE)
  if (length(kandidat) == 0) {
    stop("File Excel Titanic tidak ketemu di folder: ", getwd())
  }
  path_data <- kandidat[1]
}

nama_sheet <- excel_sheets(path_data)
sheet_data <- if ("Titanic Dataset" %in% nama_sheet) "Titanic Dataset" else nama_sheet[1]
titanic <- read_excel(path_data, sheet = sheet_data)

glimpse(titanic)
## Rows: 891
## Columns: 12
## $ PassengerId <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,…
## $ Survived    <dbl> 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1…
## $ Pclass      <dbl> 3, 1, 3, 1, 3, 3, 1, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3, 2, 3, 3…
## $ Name        <chr> "Braund, Mr. Owen Harris", "Cumings, Mrs. John Bradley (Fl…
## $ Sex         <chr> "male", "female", "female", "female", "male", "male", "mal…
## $ Age         <dbl> 22, 38, 26, 35, 35, 29, 54, 2, 27, 14, 4, 58, 20, 39, 14, …
## $ SibSp       <dbl> 1, 1, 0, 1, 0, 0, 0, 3, 0, 1, 1, 0, 0, 1, 0, 0, 4, 0, 1, 0…
## $ Parch       <dbl> 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 5, 0, 0, 1, 0, 0, 0…
## $ Ticket      <chr> "A/5 21171", "PC 17599", "STON/O2. 3101282", "113803", "37…
## $ Fare        <dbl> 7.2500, 71.2833, 7.9250, 53.1000, 8.0500, 8.4583, 51.8625,…
## $ Cabin       <chr> NA, "C85", NA, "C123", NA, NA, "E46", NA, NA, NA, "G6", "C…
## $ Embarked    <chr> "S", "C", "S", "S", "S", "Q", "S", "S", "S", "C", "S", "S"…

Datanya terdiri dari 891 penumpang dan 12 variabel.

2.4 Identifikasi Masalah pada Data

Missing value. Pada data mentah, Age kosong sebanyak 177 data, Cabin 687 data, dan Embarked 2 data. File yang saya pakai sudah versi bersih, jadi Age sudah terisi. Hasil pengecekan pada file ini:

data.frame(Variabel = names(titanic),
           Jumlah_NA = sapply(titanic, function(x) sum(is.na(x))),
           row.names = NULL)

Cabin dan Embarked masih ada yang kosong, tetapi keduanya tidak dipakai dalam analisis ini.

Outlier. Pada Fare ada tiga penumpang (PassengerId 259, 680, dan 738) dengan nilai yang sama, yaitu 512.3292, jauh di atas penumpang lain.

titanic %>% filter(Fare > 500) %>% select(PassengerId, Pclass, Fare)
ggplot(titanic, aes(y = Fare)) +
  geom_boxplot(fill = "lightblue") +
  labs(title = "Boxplot Fare", y = "Fare")

Ketiganya penumpang kelas 1 dan nilainya sama persis, jadi menurut saya ini bukan kesalahan input, hanya tiket yang harganya memang sangat mahal. Nilai ini tetap dipertahankan.

Penulisan Ticket. Nomor tiket tidak konsisten, ada yang angka saja, ada yang campuran huruf, angka, dan spasi. Kolom ini tidak dipakai, jadi tidak saya ubah.

3 Data Cleaning

Langkah yang dilakukan:

  1. Memilih kolom yang dibutuhkan (PassengerId, Survived, Sex, Age).
  2. Mengecek bagian yang kosong.
  3. Melengkapi Age yang kosong. Pada data mentah, pelengkapan memakai sumber Encyclopedia Titanica dan Titanic Universe.
  4. Kalau masih ada yang kosong, diisi dengan median Age.
  5. Validasi, memastikan sudah tidak ada yang kosong.
# 1. pilih kolom
titanic_sel <- titanic %>% select(PassengerId, Survived, Sex, Age)

# 2. cek NA
colSums(is.na(titanic_sel))
## PassengerId    Survived         Sex         Age 
##           0           0           0           0
# 3-4. sisa NA di Age diganti median
# (di file ini Age sudah lengkap, jadi tidak ada baris yang berubah)
median_age <- median(titanic_sel$Age, na.rm = TRUE)
titanic_clean <- titanic_sel %>%
  mutate(Age = if_else(is.na(Age), median_age, Age))

# 5. validasi
colSums(is.na(titanic_clean))
## PassengerId    Survived         Sex         Age 
##           0           0           0           0

Setelah dibersihkan, tidak ada lagi missing value dan variabel yang dipakai tinggal 4. Perlu diingat bahwa sekitar 20% nilai Age (177 dari 891) merupakan hasil pelengkapan, bukan data asli, jadi hasil yang berkaitan dengan umur perlu dibaca dengan hati-hati.

4 Statistik Deskriptif dan Normalitas Umur

4.1 Statistik Deskriptif

# fungsi kemencengan (skewness), dihitung manual
skew <- function(x) { m <- mean(x); mean((x - m)^3) / (mean((x - m)^2)^1.5) }

stat_age <- data.frame(
  Statistik = c("Jumlah data", "Mean", "Median", "Standar deviasi",
                "Minimum", "Maksimum", "Skewness"),
  Nilai = c(length(titanic_clean$Age), mean(titanic_clean$Age),
            median(titanic_clean$Age), sd(titanic_clean$Age),
            min(titanic_clean$Age), max(titanic_clean$Age), skew(titanic_clean$Age))
)
kable(stat_age, digits = 2)
Statistik Nilai
Jumlah data 891.00
Mean 29.60
Median 28.00
Standar deviasi 14.15
Minimum 0.42
Maksimum 80.00
Skewness 0.43

Umur penumpang berkisar antara 0.42 sampai 80 tahun dengan rata-rata 29.6 tahun dan median 28 tahun. Mean sedikit lebih besar dari median dan skewness bernilai positif kecil, artinya ekor distribusi sedikit condong ke umur yang lebih tua.

4.2 Histogram

ggplot(titanic_clean, aes(x = Age)) +
  geom_histogram(binwidth = 4, fill = "steelblue", color = "white") +
  labs(title = "Distribusi Usia Penumpang", x = "Usia (tahun)", y = "Total penumpang")

Interpretasi: sebagian besar penumpang berumur muda sampai dewasa, dengan frekuensi tertinggi di sekitar umur 20-an sampai 30-an. Ada juga kelompok kecil anak-anak di sisi kiri dan sedikit penumpang berumur di atas 60 tahun di sisi kanan.

4.3 Density Plot

ggplot(titanic_clean, aes(x = Age)) +
  geom_density(fill = "steelblue", alpha = 0.3) +
  labs(title = "Density Plot Usia Penumpang", x = "Usia (tahun)", y = "Density")

Interpretasi: bentuknya tidak simetris sempurna. Puncaknya ada di sekitar umur 25 tahun, lalu turun perlahan ke kanan, dan ada gundukan kecil di umur anak-anak. Jadi distribusinya agak menyimpang dari bentuk lonceng normal.

4.4 Q-Q Plot

ggplot(titanic_clean, aes(sample = Age)) +
  stat_qq() + stat_qq_line() +
  labs(title = "Q-Q Plot Usia Penumpang")

Interpretasi: kalau data normal, titik-titik akan mengikuti garis lurus. Pada data ini titik-titik menjauh dari garis di bagian ujung kiri dan kanan, jadi ada penyimpangan dari distribusi normal.

4.5 Uji Shapiro-Wilk

H0: data umur berdistribusi normal. H1: data umur tidak berdistribusi normal. Taraf signifikansi: \(\alpha = 0.05\).

sw <- shapiro.test(titanic_clean$Age)
sw
## 
##  Shapiro-Wilk normality test
## 
## data:  titanic_clean$Age
## W = 0.97916, p-value = 5.666e-10

Nilai W = 0.97916 dan p-value = 5.666^{-10}. Karena p-value < 0.05, maka H0 ditolak. Jadi, pada taraf signifikansi 5% data umur tidak berdistribusi normal.

Menurut saya hasil ini tidak berarti datanya jelek. Jumlah datanya cukup besar (891), sehingga uji Shapiro-Wilk mudah sekali menolak H0 walaupun penyimpangannya kecil, dan nilai skewness umur hanya 0.43. Yang perlu diperhatikan adalah metode yang dipilih selanjutnya. Karena umur tidak normal, ketika membandingkan umur antar kelompok saya memakai uji non-parametrik (Wilcoxon).

5 Homogenitas Varians Umur

Sebelum membandingkan kelompok, saya cek dulu apakah sebaran umur laki-laki dan perempuan kurang lebih sama (homogen).

ringkasan_sex <- titanic_clean %>%
  group_by(Sex) %>%
  summarise(Jumlah = n(), Mean = mean(Age), Median = median(Age), Varians = var(Age))
kable(ringkasan_sex, digits = 1)
Sex Jumlah Mean Median Varians
female 314 27.9 27 195.6
male 577 30.5 28 200.9
ggplot(titanic_clean, aes(x = Sex, y = Age, fill = Sex)) +
  geom_boxplot() +
  scale_fill_manual(values = c(female = "pink", male = "lightblue")) +
  labs(title = "Boxplot Usia Berdasarkan Jenis Kelamin", x = "Jenis kelamin", y = "Usia")

Penumpang laki-laki (577 orang) lebih banyak daripada perempuan (314 orang). Rata-rata umur laki-laki sedikit lebih tinggi, dan dari boxplot sebarannya terlihat mirip.

Uji Levene

H0: varians umur laki-laki dan perempuan sama (homogen). H1: varians umur laki-laki dan perempuan berbeda (tidak homogen). Taraf signifikansi: \(\alpha = 0.05\).

titanic_clean$Sex <- as.factor(titanic_clean$Sex)
lv <- leveneTest(Age ~ Sex, data = titanic_clean)
lv

F = 0.2307 dan p-value = 0.6311. Karena p-value > 0.05, maka H0 tidak ditolak. Artinya tidak ada bukti yang cukup bahwa varians umur laki-laki dan perempuan berbeda, jadi varians dapat dianggap homogen.

6 Integrasi Data

Data karakteristik (Sex, Age) dan data keselamatan (Survived) digabung berdasarkan PassengerId dengan left_join(). Sekalian saya buat kelompok umur untuk keperluan analisis di bagian berikutnya.

data_karakteristik <- titanic_clean %>% select(PassengerId, Sex, Age)
data_keselamatan   <- titanic_clean %>% select(PassengerId, Survived)

titanic_gabung <- left_join(data_karakteristik, data_keselamatan, by = "PassengerId")

# kelompok umur
titanic_gabung$Kelompok_Umur <- cut(titanic_gabung$Age,
                                    breaks = c(0, 12, 17, 59, Inf),
                                    labels = c("Anak (0-12)", "Remaja (13-17)",
                                               "Dewasa (18-59)", "Lansia (60+)"),
                                    include.lowest = TRUE)

# label status keselamatan untuk grafik
titanic_gabung$Status <- factor(titanic_gabung$Survived, levels = c(0, 1),
                                labels = c("Tidak selamat", "Selamat"))

head(titanic_gabung)

7 Pembahasan

7.1 Distribusi Jenis Kelamin

tab_sex <- titanic_gabung %>%
  count(Sex) %>%
  mutate(Persen = round(100 * n / sum(n), 1))
kable(tab_sex)
Sex n Persen
female 314 35.2
male 577 64.8
ggplot(tab_sex, aes(x = Sex, y = n, fill = Sex)) +
  geom_col() +
  geom_text(aes(label = n), vjust = -0.5) +
  scale_fill_manual(values = c(female = "pink", male = "lightblue")) +
  labs(title = "Jumlah Penumpang Berdasarkan Jenis Kelamin", x = "Jenis kelamin", y = "Jumlah")

Penumpang laki-laki sebanyak 577 orang (64.8%), hampir dua kali lipat perempuan yang berjumlah 314 orang (35.2%). Karena jumlahnya tidak seimbang, untuk membandingkan keselamatan saya pakai persentase, bukan jumlah orang.

7.2 Distribusi Umur

Bentuk distribusi umur sudah dibahas di bagian statistik deskriptif. Berikut jumlah penumpang per kelompok umur.

tab_umur <- titanic_gabung %>%
  count(Kelompok_Umur) %>%
  mutate(Persen = round(100 * n / sum(n), 1))
kable(tab_umur)
Kelompok_Umur n Persen
Anak (0-12) 79 8.9
Remaja (13-17) 51 5.7
Dewasa (18-59) 731 82.0
Lansia (60+) 30 3.4
ggplot(tab_umur, aes(x = Kelompok_Umur, y = n)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = n), vjust = -0.5) +
  labs(title = "Jumlah Penumpang Berdasarkan Kelompok Umur", x = "Kelompok umur", y = "Jumlah")

Sebagian besar penumpang berusia dewasa (82%). Anak-anak hanya 8.9% dan lansia 3.4%. Jumlah yang kecil ini perlu diingat nanti, karena persentase keselamatan pada kelompok kecil gampang berubah-ubah.

7.3 Keselamatan Berdasarkan Jenis Kelamin

tab_surv_sex <- titanic_gabung %>%
  group_by(Sex) %>%
  summarise(Penumpang = n(), Selamat = sum(Survived),
            Persen_Selamat = round(100 * mean(Survived), 1))
kable(tab_surv_sex)
Sex Penumpang Selamat Persen_Selamat
female 314 233 74.2
male 577 109 18.9
ggplot(tab_surv_sex, aes(x = Sex, y = Persen_Selamat, fill = Sex)) +
  geom_col() +
  geom_text(aes(label = paste0(Persen_Selamat, "%")), vjust = -0.5) +
  scale_fill_manual(values = c(female = "pink", male = "lightblue")) +
  ylim(0, 100) +
  labs(title = "Persentase Penumpang yang Selamat Berdasarkan Jenis Kelamin",
       x = "Jenis kelamin", y = "Persentase selamat (%)")

Untuk mengujinya saya pakai uji independensi chi-square.

H0: jenis kelamin dan status keselamatan saling bebas. H1: jenis kelamin dan status keselamatan tidak saling bebas.

chi <- chisq.test(table(titanic_gabung$Sex, titanic_gabung$Survived))
chi
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  table(titanic_gabung$Sex, titanic_gabung$Survived)
## X-squared = 260.72, df = 1, p-value < 2.2e-16

Nilai \(\chi^2\) = 260.72 dengan p-value < 0.001. Karena p-value < 0.05, H0 ditolak, artinya ada hubungan antara jenis kelamin dan status keselamatan.

Dari persentasenya, 74.2% penumpang perempuan selamat, sedangkan laki-laki hanya 18.9%. Jadi perempuan jauh lebih banyak yang selamat.

7.4 Keselamatan Berdasarkan Umur

Karena umur tidak berdistribusi normal, perbandingan umur antara penumpang yang selamat dan tidak selamat saya uji dengan uji Wilcoxon (Mann-Whitney).

H0: distribusi umur penumpang yang selamat dan tidak selamat sama. H1: distribusi umur keduanya berbeda.

ggplot(titanic_gabung, aes(x = Status, y = Age, fill = Status)) +
  geom_boxplot() +
  scale_fill_manual(values = c("Tidak selamat" = "grey70", "Selamat" = "steelblue")) +
  labs(title = "Boxplot Usia Berdasarkan Status Keselamatan", x = "Status", y = "Usia")

titanic_gabung %>%
  group_by(Status) %>%
  summarise(Jumlah = n(), Mean = mean(Age), Median = median(Age)) %>%
  kable(digits = 1)
Status Jumlah Mean Median
Tidak selamat 549 30.3 28
Selamat 342 28.6 28
wt <- wilcox.test(Age ~ Survived, data = titanic_gabung)
wt
## 
##  Wilcoxon rank sum test with continuity correction
## 
## data:  Age by Survived
## W = 97147, p-value = 0.3817
## alternative hypothesis: true location shift is not equal to 0

p-value = 0.382 > 0.05, jadi H0 tidak ditolak. Median umur kedua kelompok sama-sama 28 tahun, dan tidak ada perbedaan umur yang signifikan antara yang selamat dan yang tidak.

Walaupun begitu, belum bisa disimpulkan bahwa umur tidak berpengaruh sama sekali. Berikut persentase selamat per kelompok umur.

tab_surv_umur <- titanic_gabung %>%
  group_by(Kelompok_Umur) %>%
  summarise(Penumpang = n(), Selamat = sum(Survived),
            Persen_Selamat = round(100 * mean(Survived), 1))
kable(tab_surv_umur)
Kelompok_Umur Penumpang Selamat Persen_Selamat
Anak (0-12) 79 44 55.7
Remaja (13-17) 51 22 43.1
Dewasa (18-59) 731 269 36.8
Lansia (60+) 30 7 23.3
ggplot(tab_surv_umur, aes(x = Kelompok_Umur, y = Persen_Selamat)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = paste0(Persen_Selamat, "%")), vjust = -0.5) +
  ylim(0, 100) +
  labs(title = "Persentase Selamat Berdasarkan Kelompok Umur",
       x = "Kelompok umur", y = "Persentase selamat (%)")

Persentase selamat paling tinggi pada anak-anak (55.7%) dan makin rendah pada kelompok yang lebih tua, sampai 23.3% pada lansia. Tetapi pola ini bisa saja tercampur pengaruh jenis kelamin, karena kelompok umur yang lebih tua kebanyakan laki-laki. Makanya perlu dilihat gabungan keduanya.

7.5 Kombinasi Jenis Kelamin dan Kelompok Umur

tab_kombinasi <- titanic_gabung %>%
  group_by(Sex, Kelompok_Umur) %>%
  summarise(Penumpang = n(), Selamat = sum(Survived),
            Persen_Selamat = round(100 * mean(Survived), 1), .groups = "drop")
kable(tab_kombinasi)
Sex Kelompok_Umur Penumpang Selamat Persen_Selamat
female Anak (0-12) 38 20 52.6
female Remaja (13-17) 25 20 80.0
female Dewasa (18-59) 246 189 76.8
female Lansia (60+) 5 4 80.0
male Anak (0-12) 41 24 58.5
male Remaja (13-17) 26 2 7.7
male Dewasa (18-59) 485 80 16.5
male Lansia (60+) 25 3 12.0
ggplot(tab_kombinasi, aes(x = Kelompok_Umur, y = Persen_Selamat, fill = Sex)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = paste0(Persen_Selamat, "%")),
            position = position_dodge(width = 0.9), vjust = -0.5, size = 3.5) +
  scale_fill_manual(values = c(female = "pink", male = "lightblue")) +
  ylim(0, 100) +
  labs(title = "Persentase Selamat Berdasarkan Jenis Kelamin dan Kelompok Umur",
       x = "Kelompok umur", y = "Persentase selamat (%)", fill = "Jenis kelamin")

Interpretasi:

  • Pada perempuan, persentase selamat tinggi di hampir semua kelompok umur: remaja 80% dan dewasa 76.8%. Anak perempuan sedikit lebih rendah, yaitu 52.6%.
  • Pada laki-laki, persentase selamat hanya tinggi saat masih anak-anak (58.5%). Setelah itu turun tajam menjadi 7.7% pada remaja, 16.5% pada dewasa, dan 12% pada lansia.
  • Jadi anggapan “perempuan dan anak-anak didahulukan” terlihat di data, tetapi tidak merata. Untuk perempuan berlaku di hampir semua umur, sedangkan untuk anak-anak lebih jelas pada anak laki-laki. Penurunan persentase selamat menurut umur yang tadi terlihat sebagian besar berasal dari laki-laki yang makin dewasa.

Catatan: beberapa kelompok jumlahnya sangat sedikit (misalnya lansia perempuan hanya 5 orang), jadi persentasenya kurang stabil dan tidak bisa disimpulkan terlalu jauh.

8 Transformasi Data

Bagian ini mencoba beberapa transformasi data yang biasa dipakai sebelum pemodelan. Transformasi ini tidak mengubah kesimpulan di atas.

8.1 Transformasi Data Kategorik

Label encoding pada Sex: male = 1 dan female = 0.

titanic_gabung <- titanic_gabung %>%
  mutate(Sex_kode = if_else(Sex == "male", 1L, 0L))

head(titanic_gabung %>% select(PassengerId, Sex, Sex_kode))
table(titanic_gabung$Sex, titanic_gabung$Sex_kode)
##         
##            0   1
##   female 314   0
##   male     0 577

One-hot encoding, setiap kategori dibuat jadi kolom 0/1.

titanic_onehot <- titanic_gabung %>%
  mutate(Sex_male = as.integer(Sex == "male"),
         Sex_female = as.integer(Sex == "female")) %>%
  select(PassengerId, Sex_male, Sex_female)

head(titanic_onehot)

8.2 Transformasi Data Numerik

8.2.1 Statistik awal

titanic_gabung %>%
  summarise(Min_Age = min(Age), Max_Age = max(Age),
            Mean_Age = mean(Age), SD_Age = sd(Age))

Rentang umur cukup lebar (0.42 sampai 80 tahun) dengan standar deviasi 14.15, jadi Age cocok untuk dicoba ditransformasi.

8.2.2 Normalisasi Min-Max

\[Age_{MinMax} = \frac{Age - \min(Age)}{\max(Age) - \min(Age)}\]

titanic_gabung <- titanic_gabung %>%
  mutate(Age_MinMax = (Age - min(Age)) / (max(Age) - min(Age)))

titanic_gabung %>% select(PassengerId, Age, Age_MinMax) %>% head()
summary(titanic_gabung$Age_MinMax)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0000  0.2460  0.3466  0.3667  0.4722  1.0000

Nilai Age berubah ke rentang 0 sampai 1, misalnya umur 22 tahun menjadi 0.271 dan umur 38 tahun menjadi 0.472. Urutan nilainya tetap sama.

8.2.3 Standarisasi Z-Score

\[Age_Z = \frac{Age - \bar{Age}}{SD(Age)}\]

titanic_gabung <- titanic_gabung %>%
  mutate(Age_Z = (Age - mean(Age)) / sd(Age))

titanic_gabung %>% select(PassengerId, Age, Age_Z) %>% head()
titanic_gabung %>% summarise(Mean_Z = mean(Age_Z), SD_Z = sd(Age_Z))

Mean Z-Score mendekati 0 dan standar deviasinya 1. Z-Score positif berarti umurnya di atas rata-rata dan negatif berarti di bawah rata-rata.

8.2.4 Transformasi invers

Transformasi invers tidak bisa dipakai kalau ada nilai 0, jadi dicek dulu.

titanic_gabung %>% summarise(min_Age = min(Age), jumlah_nol = sum(Age == 0))

Umur minimum 0.42 dan tidak ada yang bernilai 0, jadi aman.

titanic_gabung <- titanic_gabung %>%
  mutate(Age_Inv_Sq = 1 / Age^2, Age_Inv_Cubic = 1 / Age^3)

titanic_gabung %>% select(PassengerId, Age, Age_Inv_Sq, Age_Inv_Cubic) %>% head()

Makin besar umur, makin kecil hasil transformasinya, sedangkan umur yang mendekati 0 (bayi) menghasilkan nilai yang besar sekali. Transformasi ini juga membalik urutan data.

8.2.5 Logaritma, akar kuadrat, dan akar pangkat tiga

Transformasi ini dicoba pada Age dan Fare. Untuk logaritma dipakai \(\log(1+x)\) (log1p) karena Fare bernilai 0 pada 15 penumpang, sedangkan \(\log(0)\) tidak terdefinisi.

data_trans <- titanic %>%
  select(PassengerId, Age, Fare) %>%
  mutate(Age_Log = log1p(Age), Age_Sqrt = sqrt(Age), Age_Cbrt = Age^(1/3),
         Fare_Log = log1p(Fare), Fare_Sqrt = sqrt(Fare), Fare_Cbrt = Fare^(1/3))

perbandingan <- data.frame(
  Transformasi = c("Asli", "Logaritma", "Akar kuadrat", "Akar pangkat tiga"),
  Mean_Age  = c(mean(data_trans$Age), mean(data_trans$Age_Log),
                mean(data_trans$Age_Sqrt), mean(data_trans$Age_Cbrt)),
  SD_Age    = c(sd(data_trans$Age), sd(data_trans$Age_Log),
                sd(data_trans$Age_Sqrt), sd(data_trans$Age_Cbrt)),
  Skew_Age  = c(skew(data_trans$Age), skew(data_trans$Age_Log),
                skew(data_trans$Age_Sqrt), skew(data_trans$Age_Cbrt)),
  Mean_Fare = c(mean(data_trans$Fare), mean(data_trans$Fare_Log),
                mean(data_trans$Fare_Sqrt), mean(data_trans$Fare_Cbrt)),
  SD_Fare   = c(sd(data_trans$Fare), sd(data_trans$Fare_Log),
                sd(data_trans$Fare_Sqrt), sd(data_trans$Fare_Cbrt)),
  Skew_Fare = c(skew(data_trans$Fare), skew(data_trans$Fare_Log),
                skew(data_trans$Fare_Sqrt), skew(data_trans$Fare_Cbrt))
)
kable(perbandingan, digits = 3)
Transformasi Mean_Age SD_Age Skew_Age Mean_Fare SD_Fare Skew_Fare
Asli 29.602 14.154 0.429 32.204 49.693 4.779
Logaritma 3.268 0.651 -1.883 2.962 0.969 0.394
Akar kuadrat 5.249 1.432 -0.619 4.851 2.946 2.081
Akar pangkat tiga 2.990 0.587 -1.103 2.766 1.072 1.228

Histogram Fare sebelum dan sesudah transformasi logaritma:

par_fare <- bind_rows(
  data.frame(Jenis = "Fare asli", Nilai = data_trans$Fare),
  data.frame(Jenis = "Fare setelah log", Nilai = data_trans$Fare_Log)
)

ggplot(par_fare, aes(x = Nilai)) +
  geom_histogram(bins = 30, fill = "steelblue", color = "white") +
  facet_wrap(~ Jenis, scales = "free") +
  labs(title = "Distribusi Fare Sebelum dan Sesudah Transformasi Logaritma",
       x = "Nilai", y = "Frekuensi")

Untuk menilai transformasi, awalnya saya melihat standar deviasi yang paling kecil. Setelah dipikir lagi, cara itu kurang tepat karena standar deviasi pasti mengecil ketika skala datanya mengecil, jadi tidak adil dibandingkan. Ukuran yang lebih cocok adalah skewness, yang idealnya mendekati 0.

  • Pada Fare, skewness awalnya 4.78 (sangat menceng ke kanan). Setelah transformasi logaritma menjadi 0.39, jadi sangat terbantu.
  • Pada Age, skewness awalnya sudah kecil (0.43). Setelah transformasi logaritma justru menjadi -1.88, artinya menceng ke arah sebaliknya. Jadi untuk Age transformasi sebenarnya tidak diperlukan.

9 Kesimpulan

  1. Data umur yang semula ada 177 missing value sudah dilengkapi, sehingga 891 data lengkap dan dapat dianalisis.
  2. Berdasarkan Q-Q plot dan uji Shapiro-Wilk, umur tidak berdistribusi normal, tetapi kemencengannya kecil. Berdasarkan uji Levene, varians umur laki-laki dan perempuan homogen.
  3. Penumpang laki-laki (64.8%) lebih banyak daripada perempuan (35.2%).
  4. Ada hubungan yang signifikan antara jenis kelamin dan keselamatan: 74.2% perempuan selamat, sedangkan laki-laki hanya 18.9%.
  5. Umur penumpang yang selamat dan tidak selamat tidak berbeda signifikan (median sama-sama 28 tahun). Pengaruh umur hanya terlihat pada anak-anak, terutama anak laki-laki, yang persentase selamatnya (58.5%) jauh di atas laki-laki dewasa (16.5%).
  6. Anggapan “perempuan dan anak-anak didahulukan” sebagian didukung data: berlaku untuk perempuan di hampir semua umur, tetapi untuk anak-anak lebih jelas pada anak laki-laki.
  7. Pada transformasi, Fare terbantu oleh transformasi logaritma, sedangkan Age tidak perlu ditransformasi.

9.1 Keterbatasan dan Saran

Sekitar 20% nilai umur merupakan hasil pelengkapan data, dan ada kelompok dengan jumlah penumpang yang sangat sedikit sehingga persentasenya kurang stabil. Analisis ini juga belum memperhitungkan variabel lain seperti kelas tiket (Pclass), padahal bisa saja ikut memengaruhi keselamatan. Untuk analisis lanjutan, bisa dicoba regresi logistik dengan memasukkan jenis kelamin, umur, dan kelas tiket sekaligus.

10 Daftar Pustaka