Tenggelamnya kapal Titanic pada tahun 1912 menyisakan data penumpang yang banyak dipakai untuk latihan analisis data. Makalah ini mengeksplorasi data tersebut untuk mengetahui bagaimana jenis kelamin dan umur berkaitan dengan status keselamatan penumpang. Tahapan yang dilakukan meliputi pembersihan data, pemeriksaan distribusi dan normalitas umur, pengujian homogenitas varians, transformasi data, serta analisis status keselamatan menurut jenis kelamin, umur, dan kombinasi keduanya. Seluruh analisis dilakukan dengan bahasa R.
Kata kunci: Titanic, analisis data eksploratif, jenis kelamin, umur, keselamatan, R
Kapal RMS Titanic tenggelam pada 15 April 1912 setelah menabrak gunung es dalam pelayaran perdananya. Dari seluruh penumpang yang tercatat, hanya sebagian yang selamat. Peristiwa ini kemudian menjadi salah satu kasus yang paling sering dipakai dalam pembelajaran analisis data, karena datanya memuat variabel demografis dan status keselamatan yang jelas.
Pembagian sekoci yang terbatas memunculkan dugaan bahwa peluang selamat tidak sama untuk setiap penumpang. Kebiasaan mendahulukan perempuan dan anak-anak, misalnya, sering disebut dalam catatan sejarah. Dugaan ini perlu diperiksa langsung dari data agar tidak berhenti sebagai cerita, dan analisis data eksploratif (exploratory data analysis, EDA) adalah pendekatan yang tepat untuk tujuan itu.
Tujuan makalah ini adalah mengeksplorasi pola hubungan antara jenis kelamin dan umur dengan status keselamatan penumpang Titanic, serta menjawab kelima rumusan masalah di atas.
Analisis hanya menggunakan empat variabel, yaitu
PassengerId, Survived, Sex, dan
Age. Variabel lain seperti kelas tiket
(Pclass) dan harga tiket (Fare) tidak
dianalisis terhadap keselamatan. Fare hanya dipakai pada
bagian transformasi data numerik.
Data yang digunakan adalah Titanic Dataset dari Kaggle (Elyamadad, n.d.). Data ini berasal dari berbagai sumber sejarah dan penelitian, lalu diperbaiki dan dilengkapi menggunakan Encyclopedia Titanica. Dataset tersimpan dalam bentuk tabel, dengan setiap baris mewakili satu penumpang. Jumlah observasinya 891 penumpang dengan 12 variabel.
Tabel berikut menjelaskan seluruh variabel pada dataset.
tabel_variabel <- data.frame(
Variabel = c("PassengerId", "Survived", "Pclass", "Name", "Sex", "Age",
"SibSp", "Parch", "Ticket", "Fare", "Cabin", "Embarked"),
Keterangan = c("ID penumpang", "Status keselamatan (0 = tidak selamat, 1 = selamat)",
"Kelas tiket", "Nama penumpang", "Jenis kelamin", "Umur (tahun)",
"Jumlah saudara/pasangan yang ikut", "Jumlah orang tua/anak yang ikut",
"Nomor tiket", "Harga tiket", "Kode kabin", "Pelabuhan keberangkatan"),
Jenis = c("Kualitatif", "Kualitatif", "Kualitatif", "Kualitatif", "Kualitatif",
"Kuantitatif kontinu", "Kuantitatif diskrit", "Kuantitatif diskrit",
"Kualitatif", "Kuantitatif kontinu", "Kualitatif", "Kualitatif"),
Skala = c("Nominal", "Nominal", "Ordinal", "Nominal", "Nominal", "Rasio",
"Rasio", "Rasio", "Nominal", "Rasio", "Nominal", "Nominal")
)
kable(tabel_variabel, caption = "Tabel 1. Deskripsi variabel dataset Titanic")
| Variabel | Keterangan | Jenis | Skala |
|---|---|---|---|
| PassengerId | ID penumpang | Kualitatif | Nominal |
| Survived | Status keselamatan (0 = tidak selamat, 1 = selamat) | Kualitatif | Nominal |
| Pclass | Kelas tiket | Kualitatif | Ordinal |
| Name | Nama penumpang | Kualitatif | Nominal |
| Sex | Jenis kelamin | Kualitatif | Nominal |
| Age | Umur (tahun) | Kuantitatif kontinu | Rasio |
| SibSp | Jumlah saudara/pasangan yang ikut | Kuantitatif diskrit | Rasio |
| Parch | Jumlah orang tua/anak yang ikut | Kuantitatif diskrit | Rasio |
| Ticket | Nomor tiket | Kualitatif | Nominal |
| Fare | Harga tiket | Kuantitatif kontinu | Rasio |
| Cabin | Kode kabin | Kualitatif | Nominal |
| Embarked | Pelabuhan keberangkatan | Kualitatif | Nominal |
Analisis dilakukan dengan bahasa R, menggunakan paket
dplyr, tidyr, dan ggplot2 (bagian
dari ekosistem tidyverse) untuk pengolahan dan visualisasi data serta
fungsi dasar R untuk uji homogenitas. Langkah-langkahnya adalah sebagai
berikut.
Seluruh pengujian menggunakan taraf signifikansi 5% (\(\alpha = 0{,}05\)).
File Excel dibaca dengan paket readxl. Pastikan file
berada di folder yang sama dengan file .Rmd ini.
titanic_raw <- read_excel("data set titanic ensiklopedia sudah cleaning.xlsx")
glimpse(titanic_raw)
## 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"…
Pada data mentah Kaggle ditemukan tiga masalah kualitas data.
Pertama, data hilang pada Age (177 data),
Cabin (687 data), dan Embarked (2 data).
Kedua, nilai Fare sebesar 512,3292 muncul tiga kali pada
baris 259, 680, dan 738, sehingga tampak sebagai pencilan. Ketiga,
penulisan Ticket tidak konsisten karena bercampur huruf,
angka, dan spasi.
File Excel yang digunakan sudah melalui proses cleaning,
yaitu data Age yang hilang dilengkapi dengan Encyclopedia
Titanica. Dari 12 variabel yang ada, analisis ini hanya memakai variabel
PassengerId, Survived, Sex, dan
Age, sehingga masalah pada Cabin,
Embarked, Fare, dan Ticket tidak
memengaruhi hasil.
titanic <- titanic_raw %>%
select(PassengerId, Survived, Sex, Age)
head(titanic)
Jumlah data hilang pada data setelah cleaning adalah sebagai berikut.
missing_cleaning <- colSums(is.na(titanic))
kable(data.frame(Variabel = names(missing_cleaning),
Jumlah_Missing = as.integer(missing_cleaning)),
caption = "Tabel 2. Jumlah data hilang pada data setelah cleaning")
| Variabel | Jumlah_Missing |
|---|---|
| PassengerId | 0 |
| Survived | 0 |
| Sex | 0 |
| Age | 3 |
Jika masih ada data Age yang hilang setelah
cleaning, nilainya diisi dengan median, karena
median tidak terpengaruh nilai ekstrem.
median_age <- median(titanic$Age, na.rm = TRUE)
titanic <- titanic %>%
mutate(Age = ifelse(is.na(Age), median_age, Age))
kable(data.frame(Variabel = names(titanic),
Jumlah_Missing = as.integer(colSums(is.na(titanic)))),
caption = "Tabel 3. Jumlah data hilang setelah imputasi median")
| Variabel | Jumlah_Missing |
|---|---|
| PassengerId | 0 |
| Survived | 0 |
| Sex | 0 |
| Age | 0 |
Setelah imputasi dengan median sebesar 28 tahun, tidak ada lagi data hilang. Dataset akhir terdiri atas 891 observasi dan 4 variabel.
Data karakteristik penumpang (Sex, Age) dan
data keselamatan (Survived) digabungkan menggunakan
PassengerId sebagai kunci dengan fungsi
left_join().
data_karakteristik <- titanic %>% select(PassengerId, Sex, Age)
data_keselamatan <- titanic %>% select(PassengerId, Survived)
data_gabungan <- data_karakteristik %>%
left_join(data_keselamatan, by = "PassengerId")
head(data_gabungan)
Variabel Sex berbentuk teks (male dan
female) sehingga perlu diubah menjadi angka agar mudah dipakai
pada pemodelan. Dua cara dicoba. Cara pertama adalah label
encoding (1 = male, 0 = female). Cara kedua adalah one-hot
encoding, yaitu setiap kategori dijadikan kolom indikator 0/1.
data_encoded <- data_gabungan %>%
mutate(
sex_kode = ifelse(Sex == "male", 1, 0),
Sex_male = ifelse(Sex == "male", 1, 0),
Sex_female = ifelse(Sex == "female", 1, 0)
)
head(data_encoded, 8)
tabel_sex <- data_gabungan %>%
count(Sex) %>%
mutate(Persen = round(n / sum(n) * 100, 1))
kable(tabel_sex, caption = "Tabel 4. Jumlah penumpang menurut jenis kelamin")
| Sex | n | Persen |
|---|---|---|
| female | 314 | 35.2 |
| male | 577 | 64.8 |
ggplot(tabel_sex, aes(x = Sex, y = n, fill = Sex)) +
geom_col(width = 0.6) +
geom_text(aes(label = paste0(n, " (", Persen, "%)")), vjust = -0.5) +
scale_fill_manual(values = c(female = warna_female, male = warna_male)) +
labs(title = "Gambar 1. Distribusi Jenis Kelamin Penumpang",
x = "Jenis Kelamin", y = "Jumlah Penumpang") +
theme(legend.position = "none") +
ylim(0, max(tabel_sex$n) * 1.15)
Dari 891 penumpang, terdapat 577 laki-laki (64.8%) dan 314 perempuan (35.2%). Penumpang laki-laki jauh lebih banyak, sehingga perbandingan keselamatan antar jenis kelamin nanti perlu dibaca dalam bentuk proporsi, bukan jumlah mentah.
statistik_age <- tibble(
Statistik = c("Jumlah data", "Rata-rata", "Median", "Standar deviasi",
"Minimum", "Maksimum"),
Nilai = c(nrow(data_gabungan),
round(mean(data_gabungan$Age), 2),
median(data_gabungan$Age),
round(sd(data_gabungan$Age), 2),
min(data_gabungan$Age),
max(data_gabungan$Age))
)
kable(statistik_age, caption = "Tabel 5. Statistik deskriptif umur penumpang")
| Statistik | Nilai |
|---|---|
| Jumlah data | 891.00 |
| Rata-rata | 29.61 |
| Median | 28.00 |
| Standar deviasi | 14.15 |
| Minimum | 0.42 |
| Maksimum | 80.00 |
Umur penumpang berkisar dari 0.42 hingga 80 tahun dengan rata-rata 29.61 tahun dan median 28 tahun. Rata-rata yang sedikit lebih besar dari median mengisyaratkan distribusi yang miring ke kanan. Hal ini terlihat pada histogram dan density plot berikut.
ggplot(data_gabungan, aes(x = Age)) +
geom_histogram(binwidth = 4, fill = "steelblue", color = "white", alpha = 0.9) +
labs(title = "Gambar 2. Histogram Umur Penumpang",
x = "Umur (tahun)", y = "Jumlah Penumpang")
ggplot(data_gabungan, aes(x = Age)) +
geom_density(fill = warna_utama, alpha = 0.3, color = warna_utama, linewidth = 1) +
labs(title = "Gambar 3. Density Plot Umur Penumpang",
x = "Umur (tahun)", y = "Density")
Mayoritas penumpang berada pada usia muda hingga dewasa, dengan puncak di sekitar 20 sampai 30 tahun, lalu jumlahnya menurun ke arah umur yang lebih tinggi. Terdapat pula kelompok kecil anak-anak pada umur sangat rendah. Bentuk distribusi tidak simetris sehingga menyimpang dari distribusi normal.
Untuk memastikan dugaan visual tersebut, digunakan Q-Q plot dan uji Shapiro-Wilk. Pada Q-Q plot, data yang berdistribusi normal akan mengikuti garis acuan.
ggplot(data_gabungan, aes(sample = Age)) +
stat_qq(alpha = 0.7) +
stat_qq_line(color = "red") +
labs(title = "Gambar 4. Q-Q Plot Umur Penumpang",
x = "Kuantil Teoretis", y = "Kuantil Sampel")
Titik-titik menyimpang dari garis acuan, terutama pada bagian ujung distribusi. Selanjutnya dilakukan uji Shapiro-Wilk dengan hipotesis:
uji_shapiro <- shapiro.test(data_gabungan$Age)
uji_shapiro
##
## Shapiro-Wilk normality test
##
## data: data_gabungan$Age
## W = 0.97921, p-value = 5.866e-10
Statistik uji menghasilkan W = 0.9792 dengan p-value = 5.866e-10. Karena p-value < 0,05, H0 ditolak, sehingga umur penumpang tidak berdistribusi normal.
Hasil ini tidak berarti data buruk. Dalam EDA, ketidaknormalan justru informasi tentang karakter data. Data umur memang wajar tidak normal, dan konsekuensinya adalah pemilihan uji statistik yang tidak mensyaratkan normalitas, seperti uji Wilcoxon pada bagian 4.6.
Pengaruh umur dan jenis kelamin mungkin saling terkait, sehingga keduanya dilihat bersamaan.
tabel_kombinasi <- data_analisis %>%
group_by(Sex, Kelompok_Umur) %>%
summarise(
Total = n(),
Selamat = sum(Survived),
Persen_Selamat = round(mean(Survived) * 100, 1),
.groups = "drop"
)
kable(tabel_kombinasi, caption = "Tabel 9. Tingkat keselamatan menurut jenis kelamin dan kelompok umur")
| Sex | Kelompok_Umur | Total | Selamat | Persen_Selamat |
|---|---|---|---|---|
| female | Anak (0-12) | 38 | 20 | 52.6 |
| female | Remaja (13-17) | 25 | 20 | 80.0 |
| female | Dewasa Muda (18-35) | 164 | 125 | 76.2 |
| female | Dewasa (36-60) | 83 | 65 | 78.3 |
| female | Lansia (>60) | 4 | 3 | 75.0 |
| male | Anak (0-12) | 41 | 24 | 58.5 |
| male | Remaja (13-17) | 26 | 2 | 7.7 |
| male | Dewasa Muda (18-35) | 331 | 52 | 15.7 |
| male | Dewasa (36-60) | 157 | 29 | 18.5 |
| male | Lansia (>60) | 22 | 2 | 9.1 |
ggplot(tabel_kombinasi, aes(x = Kelompok_Umur, y = Persen_Selamat, fill = Sex)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
geom_text(aes(label = paste0(Persen_Selamat, "%")),
position = position_dodge(width = 0.8), vjust = -0.4, size = 3.3) +
scale_fill_manual(values = c(female = warna_female, male = warna_male),
name = "Jenis Kelamin") +
labs(title = "Gambar 9. Persentase Selamat Menurut Jenis Kelamin dan Kelompok Umur",
x = "Kelompok Umur", y = "Persentase Selamat (%)") +
ylim(0, 105) +
theme(axis.text.x = element_text(angle = 15, hjust = 1))
Grafik ini memperlihatkan apakah keunggulan keselamatan perempuan
konsisten di setiap kelompok umur, dan apakah anak laki-laki memiliki
peluang yang berbeda dari laki-laki dewasa. Kelompok dengan jumlah
penumpang sedikit (lihat kolom Total pada Tabel 9) perlu
ditafsirkan dengan hati-hati karena persentasenya mudah berubah.
Bagian ini adalah eksplorasi lanjutan untuk melihat bagaimana skala
dan bentuk distribusi Age berubah setelah ditransformasi.
Transformasi tidak mengubah kesimpulan analisis keselamatan di atas.
Normalisasi Min-Max mengubah umur ke rentang 0 sampai 1 dengan rumus \(x' = \dfrac{x - x_{min}}{x_{max} - x_{min}}\). Standarisasi Z-Score menyatakan posisi relatif umur terhadap rata-rata dengan rumus \(z = \dfrac{x - \bar{x}}{s}\).
data_trans <- data_gabungan %>%
mutate(
Age_MinMax = (Age - min(Age)) / (max(Age) - min(Age)),
Age_Z = as.numeric(scale(Age))
)
head(data_trans %>% select(PassengerId, Age, Age_MinMax, Age_Z))
data_trans %>%
summarise(Min_MinMax = min(Age_MinMax), Max_MinMax = max(Age_MinMax),
Mean_Z = mean(Age_Z), SD_Z = sd(Age_Z)) %>%
kable(digits = 4, caption = "Tabel 10. Ringkasan hasil Min-Max dan Z-Score")
| Min_MinMax | Max_MinMax | Mean_Z | SD_Z |
|---|---|---|---|
| 0 | 1 | 0 | 1 |
Setelah Min-Max, nilai minimum menjadi 0 dan maksimum menjadi 1, dengan urutan data tetap terjaga. Hasil Z-Score memiliki rata-rata mendekati 0 dan standar deviasi 1. Nilai Z positif berarti umur di atas rata-rata dan negatif berarti di bawah rata-rata.
Transformasi invers tidak aman jika ada nilai 0, sehingga dicek terlebih dahulu.
tibble(
min_val = min(data_trans$Age),
jumlah_nol = sum(data_trans$Age == 0)
) %>% kable(caption = "Tabel 11. Pemeriksaan nilai nol pada Age")
| min_val | jumlah_nol |
|---|---|
| 0.42 | 0 |
Tidak ada Age bernilai 0, sehingga transformasi invers
dapat dilakukan. Namun, umur yang sangat kecil (misalnya 0,42 tahun)
tetap menghasilkan nilai invers yang sangat besar.
data_trans <- data_trans %>%
mutate(
Age_Inv_Sq = 1 / (Age^2),
Age_Inv_Cubic = 1 / (Age^3)
)
data_trans %>%
summarise(Min = min(Age_Inv_Sq), Max = max(Age_Inv_Sq),
Mean = mean(Age_Inv_Sq), SD = sd(Age_Inv_Sq)) %>%
kable(digits = 6, caption = "Tabel 12. Ringkasan Invers Square (1/x^2)")
| Min | Max | Mean | SD |
|---|---|---|---|
| 0.000156 | 5.668934 | 0.032139 | 0.250727 |
head(data_trans %>% select(PassengerId, Age, Age_Inv_Sq, Age_Inv_Cubic))
Semakin besar umur, semakin kecil nilai hasil transformasinya. Inverse Cubic berubah lebih tajam daripada Inverse Square, terutama pada umur rendah.
Ketiga transformasi ini diterapkan pada Age dan
Fare. Karena Fare memiliki nilai 0, logaritma
dihitung dengan log1p(), yaitu \(\log(1 + x)\), agar tidak menghasilkan
-Inf.
data_all <- data_trans %>%
left_join(titanic_raw %>% select(PassengerId, Fare), by = "PassengerId") %>%
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 <- tibble(
Transformasi = c("Sebelum transformasi", "Logaritma", "Akar kuadrat", "Akar pangkat tiga"),
Rata2_Age = c(mean(data_all$Age), mean(data_all$Age_Log),
mean(data_all$Age_Sqrt), mean(data_all$Age_Cbrt)),
SD_Age = c(sd(data_all$Age), sd(data_all$Age_Log),
sd(data_all$Age_Sqrt), sd(data_all$Age_Cbrt)),
Rata2_Fare = c(mean(data_all$Fare), mean(data_all$Fare_Log),
mean(data_all$Fare_Sqrt), mean(data_all$Fare_Cbrt)),
SD_Fare = c(sd(data_all$Fare), sd(data_all$Fare_Log),
sd(data_all$Fare_Sqrt), sd(data_all$Fare_Cbrt))
)
kable(perbandingan, digits = 3, caption = "Tabel 13. Perbandingan hasil transformasi")
| Transformasi | Rata2_Age | SD_Age | Rata2_Fare | SD_Fare |
|---|---|---|---|---|
| Sebelum transformasi | 29.605 | 14.153 | 32.204 | 49.693 |
| Logaritma | 3.269 | 0.651 | 2.962 | 0.969 |
| Akar kuadrat | 5.250 | 1.432 | 4.851 | 2.946 |
| Akar pangkat tiga | 2.990 | 0.587 | 2.766 | 1.072 |
data_all %>%
select(Age, Age_Log, Age_Sqrt, Age_Cbrt) %>%
pivot_longer(everything(), names_to = "Transformasi", values_to = "Nilai") %>%
mutate(Transformasi = factor(Transformasi,
levels = c("Age", "Age_Log", "Age_Sqrt", "Age_Cbrt"),
labels = c("Asli", "Logaritma", "Akar Kuadrat",
"Akar Pangkat Tiga"))) %>%
ggplot(aes(x = Nilai)) +
geom_histogram(bins = 25, fill = warna_utama, color = "white", alpha = 0.85) +
facet_wrap(~ Transformasi, scales = "free") +
labs(title = "Gambar 10. Distribusi Umur Setelah Berbagai Transformasi",
x = "Nilai", y = "Frekuensi")
Pada Age, akar pangkat tiga menghasilkan standar deviasi
terkecil, sedangkan pada Fare transformasi logaritma yang
terkecil. Namun standar deviasi bukan satu-satunya ukuran. Bentuk
distribusi pada histogram dan tujuan analisis juga harus
dipertimbangkan, dan transformasi tidak selalu membuat data
berdistribusi normal.
Sex dan Age. Kelas
tiket (Pclass) dan variabel lain kemungkinan juga
berpengaruh dan dapat menjadi pengacau (confounder).Age yang hilang diisi dengan median, yang dapat
mengurangi variasi data asli.Penelitian selanjutnya dapat menambahkan variabel
Pclass, Fare, dan ukuran keluarga
(SibSp + Parch), lalu membangun model prediksi
seperti regresi logistik untuk mengukur pengaruh tiap variabel terhadap
peluang selamat.
sessionInfo()
## R version 4.5.3 (2026-03-11 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=English_Indonesia.utf8 LC_CTYPE=English_Indonesia.utf8
## [3] LC_MONETARY=English_Indonesia.utf8 LC_NUMERIC=C
## [5] LC_TIME=English_Indonesia.utf8
##
## time zone: Asia/Jakarta
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] knitr_1.52 readxl_1.5.0.1 tidyr_1.3.2 ggplot2_4.0.3 dplyr_1.2.1
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.6 jsonlite_2.0.0 compiler_4.5.3 tidyselect_1.2.1
## [5] jquerylib_0.1.4 scales_1.4.0 yaml_2.3.12 fastmap_1.2.0
## [9] R6_2.6.1 labeling_0.4.3 generics_0.1.4 tibble_3.3.1
## [13] bslib_0.12.0 pillar_1.11.1 RColorBrewer_1.1-3 rlang_1.1.7
## [17] cachem_1.1.0 xfun_0.61 sass_0.4.10 S7_0.2.2
## [21] cli_3.6.5 withr_3.0.2 magrittr_2.0.4 digest_0.6.39
## [25] grid_4.5.3 rstudioapi_0.19.0 lifecycle_1.0.5 vctrs_0.7.2
## [29] evaluate_1.0.5 glue_1.8.0 farver_2.1.2 cellranger_1.1.0
## [33] rmarkdown_2.32 purrr_1.2.2 tools_4.5.3 pkgconfig_2.0.3
## [37] htmltools_0.5.9