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.
Mengetahui pola hubungan antara jenis kelamin dan umur dengan status
keselamatan penumpang. Variabel yang dipakai: PassengerId,
Sex, Age, dan Survived.
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 |
| 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 |
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.
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.
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.
Langkah yang dilakukan:
PassengerId,
Survived, Sex, Age).Age yang kosong. Pada data mentah,
pelengkapan memakai sumber Encyclopedia Titanica dan Titanic
Universe.Age.# 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.
# 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.
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.
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.
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.
H0: data umur berdistribusi normal. H1: data umur tidak berdistribusi normal. Taraf signifikansi: \(\alpha = 0.05\).
##
## 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).
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)
lvF = 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.
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)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.
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.
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.
##
## 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.
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 |
##
## 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.
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:
Catatan: beberapa kelompok jumlahnya sangat sedikit (misalnya lansia perempuan hanya 5 orang), jadi persentasenya kurang stabil dan tidak bisa disimpulkan terlalu jauh.
Bagian ini mencoba beberapa transformasi data yang biasa dipakai sebelum pemodelan. Transformasi ini tidak mengubah kesimpulan di atas.
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))##
## 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)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.
\[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()## 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.
\[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()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.
Transformasi invers tidak bisa dipakai kalau ada nilai 0, jadi dicek dulu.
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.
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.
Fare, skewness awalnya 4.78 (sangat menceng ke
kanan). Setelah transformasi logaritma menjadi 0.39, jadi sangat
terbantu.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.Fare terbantu oleh transformasi
logaritma, sedangkan Age tidak perlu ditransformasi.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.