Midterm Exam

Group 8 - Hospital Dataset

Logo


Pendahuluan

Dalam sistem pelayanan kesehatan modern, rumah sakit menghasilkan data dalam jumlah besar setiap hari—mulai dari penerimaan pasien, rekam medis, dan penggunaan obat hingga kinerja dokter dan manajemen biaya. Data ini menyimpan wawasan berharga yang dapat membantu meningkatkan luaran pasien, mengoptimalkan efisiensi operasional, dan mendukung pengambilan keputusan berbasis bukti.

Namun, data pelayanan kesehatan seringkali kompleks, melibatkan variabel kategoris (seperti departemen, jenis pasien, atau wilayah) dan variabel numerik (seperti usia pasien, biaya perawatan, dan waktu pemulihan). Untuk memahami kompleksitas ini, penting untuk menerapkan analisis statistik deskriptif dan metode visualisasi data.

Melalui ukuran-ukuran seperti tendensi sentral (mean, median, modus) dan dispersi (rentang, varians, deviasi standar), analis dapat memahami variasi dalam luaran pasien, alokasi sumber daya, dan kinerja perawatan.

1. Data Visualization

1.1 Persiapan Data

# Persiapan Data: Bersihkan, Proses, and Tampilkan tabel interaktif
library(readxl)
library(dplyr)
library(reactable)
library(htmltools)

# Mengimpor dataset
data_raw <- read.csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Bersihkan dan mempersiapkan data
data_clean <- data_raw %>%
  rename_with(~ gsub("\\s+", "_", .x)) %>%
  mutate(across(where(is.character), trimws)) %>%
  mutate(
  
  )

# Buat tabel interaktif dengan dropdown + animated pagination
htmltools::browsable(
  htmltools::tagList(
    
    # Control dropdown untuk jumlah data yang ditampilkan per halaman 
    tags$div(
      style = "display:flex; align-items:center; gap:6px; margin-bottom:10px; font-size:14px;",
      tags$span("Showing"),
      tags$select(
        id = "pageSizeSelect",
        style = "padding:3px 6px; border-radius:4px; border:1px solid #ccc; font-size:14px;",
        tags$option(value = 10, "10"),
        tags$option(value = 25, "25"),
        tags$option(value = 50, "50"),
        tags$option(value = 100, "100")
      ),
      tags$span("entries")
    ),
    
    # Reactable table
    reactable(
      data_clean,
      elementId = "myTable",
      searchable = TRUE,
      bordered = TRUE,
      striped = TRUE,
      highlight = TRUE,
      resizable = TRUE,
      defaultPageSize = 10,
      wrap = FALSE,
      fullWidth = TRUE,
      defaultColDef = colDef(align = "center"),
      
      theme = reactableTheme(
        headerStyle = list(
          background = "#f7f7f7",
          fontWeight = "bold",
          borderBottom = "2px solid #ddd"
        ),
        
        # Pagination area (clear background)
        paginationStyle = list(
          background = "transparent",
          borderTop = "1px solid #ddd",
          padding = "8px 0"
        ),
        
        # Pagination buttons with animation
        pageButtonStyle = list(
          background = "#ffffff",
          border = "1px solid #90CAF9",
          color = "#0D47A1",
          borderRadius = "6px",
          padding = "4px 10px",
          margin = "0 3px",
          transition = "all 0.2s ease-in-out",
          boxShadow = "0 1px 3px rgba(0,0,0,0.1)",
          fontWeight = "500"
        ),
        pageButtonHoverStyle = list(
          background = "#E3F2FD",
          border = "1px solid #42A5F5",
          transform = "scale(1.05)"
        ),
        pageButtonActiveStyle = list(
          background = "#1E88E5",
          color = "white",
          transform = "scale(1.05)"
        )
      )
    ),
    
    # Menggunakan JavaScript untuk mengubah jumlah data yang ditampilkan secara dinamis
    tags$script(HTML("
      document.getElementById('pageSizeSelect').addEventListener('change', function() {
        const newSize = parseInt(this.value);
        const tbl = window.reactable.getInstance('myTable');
        if (tbl) tbl.setPageSize(newSize);
      });
    "))
  )
)
Showing entries

1.2 Deskripsi Dataset

# Library
library(readr)
library(knitr)
library(kableExtra)

# Baca Data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Klasifikasi Data
data_classification <- data.frame(
  Column = c("Hospital", "Treatment", "Region", "SmokingStatus",
            "Age", "BMI", "SystolicBP", "Cholesterol", "ExerciseHours",
            "ComorbidityScore", "RecoveryTime", "HealthScore"),
  DataType = c("Nominal", "Nominal", "Nominal", "Nominal",
                "Discrete", "Continuous", "Discrete", "Discrete",
                "Continuous", "Discrete", "Continuous", "Continuous"),
  Subtype = c("Categorical", "Categorical", "Categorical", "Categorical",
           "Numerical", "Numerical", "Numerical", "Numerical",
           "Numerical", "Numerical", "Numerical", "Numerical")
)

# Tabel
data_classification %>%
  kable(
    align = c("c", "c", "c"),
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    font_size = 16,
    full_width = TRUE
  ) %>%
  row_spec(0, align = "center")
Column DataType Subtype
Hospital Nominal Categorical
Treatment Nominal Categorical
Region Nominal Categorical
SmokingStatus Nominal Categorical
Age Discrete Numerical
BMI Continuous Numerical
SystolicBP Discrete Numerical
Cholesterol Discrete Numerical
ExerciseHours Continuous Numerical
ComorbidityScore Discrete Numerical
RecoveryTime Continuous Numerical
HealthScore Continuous Numerical

1.3 Visualisasi

1.3.1 Bar Chart

Bar chart adalah jenis visualisasi data yang digunakan untuk merepresentasikan data kategorikal dengan batang persegi panjang. Tinggi (atau panjang) setiap batang sesuai dengan nilai atau frekuensi suatu kategori, sehingga memudahkan untuk membandingkan kuantitas di berbagai kelompok.

Bar Chart sangat cocok untuk:

  • Data numerik diskrit - angka yang hanya dapat mengambil nilai tertentu (misalnya, jumlah barang yang dibeli).

  • Data kategoris ordinal kategori dengan urutan alami (misalnya, tingkat kepuasan pelanggan: Rendah, Sedang,Tinggi).

# Library
library(readxl)
library(dplyr)
library(ggplot2)
library(plotly)
library(readr)

# Baca Data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Urutkan Treatment berdasarkan rata-rata RecoveryTime
data <- data %>%
  mutate(Treatment = reorder(Treatment, RecoveryTime, FUN = mean))

# Bikin Grafik Dasar ggplot
p <- ggplot(data, aes(x = Treatment, y = RecoveryTime, fill = Treatment)) +
  stat_summary(fun = mean, geom = "bar", color = "white", width = 0.6) +
  scale_fill_manual(values = c("#A8DADC", "#FFC8DD", "#FFAFCC", "#BDE0FE", "#CDB4DB")) +
  labs(
    title = "Average Recovery Time per Treatment",
    x = "Treatment Type",
    y = "Average Recovery Time"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, color = "#444"),
    axis.title = element_text(color = "#555"),
    axis.text = element_text(color = "#555"),
    legend.position = "none",
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank()
  )

# Jadikan interaktif
ggplotly(p, tooltip = c("x", "y"))

Interpretasi

  • Therapy memiliki rata-rata waktu pemulihan paling rendah, yaitu sekitar 13 hari.

  • Medication menempati posisi kedua dengan rata-rata waktu pemulihan sekitar 14 hari.

  • Surgery memiliki rata-rata waktu pemulihan paling tinggi, yaitu lebih dari 20 hari.

    Hal ini menunjukkan bahwa surgery cenderung membutuhkan waktu pemulihan yang lebih lama dibandingkan dengan jenis perawatan lainnya. Sebaliknya, therapy dan medication memiliki waktu pemulihan yang lebih singkat. Dari hasil analisis ini, kita bisa simpulkan bahwa jenis perawatan berpengaruh terhadap lama waktu pemulihan pasien.

1.3.2 Histogram

Histogram adalah representasi grafis dari distribusi data numerik. Histogram membagi data ke dalam interval, yang dikenal sebagai bin, dan menampilkan frekuensi titik data dalam setiap bin. Visualisasi ini membantu mengidentifikasi pola seperti tendensi sentral, sebaran, kemiringan, dan keberadaan beberapa modus dalam data.

Histogram sangat efektif untuk:

  • Memvisualisasikan Distribusi: Memberikan gambaran yang jelas tentang bagaimana data didistribusikan di berbagai rentang, membantu mengidentifikasi bentuk distribusi (misalnya, normal, miring, bimodal).

  • Mengidentifikasi Tendensi Sentral dan Penyebaran Dengan mengamati puncak histogram, seseorang dapat menyimpulkan nilai sentral data. Lebar histogram menunjukkan variabilitas atau penyebaran data.

  • Mendeteksi Kemiringan Asimetri histogram dapat mengungkapkan apakah data miring ke kiri atau kanan, yang menunjukkan potensi bias dalam proses pengumpulan data.

  • Mengenali Beberapa Mode Histogram dapat menunjukkan jika data memiliki beberapa puncak (mode), yang menunjukkan adanya subkelompok yang berbeda dalam kumpulan data.

# Library
library(readxl)
library(dplyr)
library(ggplot2)
library(plotly)

# Baca Data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Bikin Histogram
p <- ggplot(data, aes(x = HealthScore, fill = SmokingStatus)) +
  geom_histogram(alpha = 0.8, bins = 30, color = "white") +
  scale_fill_manual(values = c("#FFC8DD", "#BDE0FE", "#CDB4DB", "#A8DADC")) +
  labs(
    title = "Health Score Distribution by Smoking Status",
    x = "Health Score",
    y = "Count",
    fill = "Smoking Status"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, color = "#444"),
    axis.title = element_text(color = "#555"),
    axis.text = element_text(color = "#555"),
    legend.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )

# Jadikan Interaktif
ggplotly(p, tooltip = c("x", "y", "fill"))

Interpretasi

  • Kelompok Never (tidak pernah merokok) cenderung memiliki Health Score yang lebih tinggi, memiliki puncak distribusi mendekati skor 100.

  • Kelompok Former (pernah merokok) memiliki distribusi di tengah dengan Health Score berada pada kisaran 75–90.

  • Kelompok Current (masih merokok) memiliki penyebaran skor yang lebih lebar tapi sebagian berada di kisaran 70–85 dan yang mencapai skor tinggi cenderung lebih sedikit.

    Hal ini menunjukkan bahwa kebiasaan merokok berpengaruh terhadap skor kesehatan, di mana semakin rendah paparan terhadap rokok, semakin baik skor kesehatannya.

1.3.3 Boxplot

Boxplot adalah teknik visualisasi data yang menampilkan distribusi, sebaran, dan potensi outlier dari suatu variabel kontinu melalui statistik ringkasannya minimum, kuartil pertama (Q1), median, kuartil ketiga (Q3), dan maksimum. Boxplot memberikan gambaran ringkas tentang bagaimana nilai data tersebar dan di mana mereka terkonsentrasi.

Boxplot khususnya berguna untuk:

  • Membandingkan Distribusi di Seluruh Kelompok:Mengungkapkan perbedaan dalam penyebaran data dan kecenderungan sentral di seluruh kategori (misalnya, jenis produk atau tingkatan pelanggan).

  • Mendeteksi Outlier: Mengidentifikasi titik data yang luar biasa tinggi atau rendah yang mungkin mengindikasikan kesalahan data atau kasus khusus.

  • Menilai Simetri dan Kemiringan Data: Mengamati apakah data terdistribusi secara merata atau condong ke nilai yang lebih tinggi atau lebih rendah.

# Library
library(plotly)
library(readr)

# Baca data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Boxplot interaktif
fig <- plot_ly(
  data = data,
  x = ~Region,
  y = ~SystolicBP,
  color = ~Region,
  type = "box",
  colors = c("#FFC1CC", "#FFD6A5", "#FFD6A5", "#C1E1C1", "#CDB4DB")
)

# Tambah layout
fig <- fig %>%
  layout(
    title = "Distribusi SystolicBP Berdasarkan Region",
    xaxis = list(title = "Region"),
    yaxis = list(title = "Systolic Blood Pressure"),
    boxmode = "group",
    showlegend = FALSE
  )

fig

Interpretasi

  • Rural: Median systolicBP sekitar 130 mmHg, sebaran data cukup luas dengan dua outlier di atas 170 mmHg dan satu di bawah 90 mmHg, tekanan darah di wilayah rural relatif tinggi.

  • Suburban: Median lebih tinggi, sekitar 132–135 mmHg, sebaran data agak luas tapi memiliki lebih banyak outlier tinggi hingga 170-an mmHg dan outlier di bawah 100 mmHg, di wilayah suburban terdapat beberapa pasien yang memiliki tekanan darah tinggi.

  • Urban: Median sekitar 125–130 mmHg, sebaran data lebih sempit dan lebih sedikit outlier, tekanan darah di wilayah urban cenderung lebih stabil.

Hal ini menunjukkan bahwa wilayah tempat tinggal dapat memengaruhi kondisi tekanan darah seseorang.

1.3.4 Pie Chart

Diagram Lingkaran adalah grafik statistik melingkar yang dibagi menjadi beberapa bagian untuk menggambarkan proporsi numerik dalam suatu kumpulan data. Setiap bagian lingkaran mewakili kontribusi suatu kategori terhadap keseluruhan, sehingga ideal untuk menunjukkan hubungan antar bagian.

Diagram lingkaran paling baik digunakan ketika:

  • Dataset berisi sejumlah kecil kategori.

  • Anda ingin menekankan proporsi atau persentase relatif.

  • Totalnya berjumlah 100% dari kumpulan data.

Namun, diagram lingkaran kurang efektif jika terdapat terlalu banyak kategori atau jika perbedaan antar irisan kecil dalam kasus seperti ini, diagram batang seringkali lebih cocok

# Library
library(plotly)
library(readr)
library(dplyr)

# Baca data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Hitung jumlah data per hospital
hospital_count <- data %>%
  count(Hospital)

# Pie chart interaktif
fig <- plot_ly(
  hospital_count,
  labels = ~Hospital,
  values = ~n,
  type = 'pie',
  hole = 0.5,
  textinfo = 'label+percent',
  insidetextorientation = 'radial',
  marker = list(colors = c("#FFC1CC", "#B0E0E6", "#E6E6FA", "#C1E1C1", "#FFFACD"))
)

fig <- fig %>%
  layout(
    title = "Proporsi Pasien Berdasarkan Hospital",
    showlegend = FALSE
  )

fig

Interpretasi

  • Setiap rumah sakit menangani jumlah pasien yang hampir merata.

  • Hospital_A dan Hospital_D memiliki jumlah pasien sedikit lebih banyak dibandingkan yang lain, hal ini menunjukkan bahwa kedua rumah sakit tersebut mungkin memiliki kapasitas atau daya tarik layanan yang sedikit lebih tinggi.

  • Hospital_E memiliki proporsi pasien paling sedikit tapi tidak terlalu jauh perbedaannya

Hal ini dapat disimpulkan bahwa distribusi pasien di lima rumah sakit sudah cukup merata tanpa ada satu rumah sakit yang dominan menangani pasien.

1.3.5 Density Plot

Density plot adalah grafik yang menunjukkan sebaran (distribusi) data numerik dalam bentuk kurva halus. Kurva ini menggambarkan di mana data paling sering muncul — jadi mirip histogram, tapi tampilannya lebih halus.

Density Plot digunakan untuk:

  • Melihat bentuk distribusi data, apakah data condong ke kanan (positif), ke kiri (negatif), atau simetris.

  • Membandingkan distribusi antar kelompok

  • Menemukan konsentrasi data (titik padat), titik puncak kurva menunjukkan nilai yang paling sering muncul (mirip mode).

# Library
library(ggplot2)
library(plotly)

# Baca data
data <- read.csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Density Plot
p <- ggplot(data, aes(x = Cholesterol, fill = Treatment)) +
  geom_density(alpha = 0.7, color = "white", size = 0.3) +
  scale_fill_manual(values = c("#FFD6A5", "#FFB5E8", "#B5DEFF", "#C8FFD4", "#FFF5BA")) +
  labs(
    title = "Density Plot Kadar Kolesterol Berdasarkan Jenis Treatment",
    subtitle = "Arahkan kursor untuk melihat detail tiap distribusi treatment",
    x = "Kadar Kolesterol",
    y = "Kepadatan (Density)",
    fill = "Jenis Treatment"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, size = 15),
    plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 11),
    legend.position = "right"
  )

# Jadikan interaktif
ggplotly(p)

Interpretasi

  • Kurvanya agak mengerucut berarti rata-rata pasien punya kadar kolesterol di tengah-tengah, tidak terlalu tinggi atau terlalu rendah.

  • Kurva surgery, therapy, dan medication tumpang tindih berarti bisa dikatakan bahwa hasilnya mirip antar treatment.

  • Titik puncak kurva ada disekitar 180-220, rata-rata kadar kolesterol pasien ada di sekisaran 180-220 untuk semua jenis treatment.

2. Central Tendency Analysis

Central Tendency adalah ukuran statistik yang merepresentasikan nilai tipikal atau sentral dari suatu kumpulan data. Ukuran ini bertujuan untuk memberikan satu nilai yang paling mewakili keseluruhan data, sehingga memungkinkan kita memahami di mana sebagian besar nilai data terkonsentrasi. Tiga ukuran tendensi sentral yang paling umum adalah: Mean, Median, dan Modus.

a. Mean

Rata-rata diperoleh dengan membagi jumlah semua nilai data dengan jumlah total observasi. Nilai ini cocok untuk tipe data interval dan rasio.

\[ \bar{X} = \frac{\sum_{i=1}^{n} X_i}{n} \] Di mana:

  • \(\bar{X}\) = rata-rata
  • \(X_i\) = setiap nilai data
  • \(n\) = jumlah pengamatan

b. Median

Median adalah nilai tengah dari kumpulan data yang diurutkan. Median cocok untuk data ordinal, interval, dan rasio. Langkah-langkah untuk Mencari Median:

  1. Susunlah data dalam urutan menaik.

  2. Jika jumlah titik data ganjil berada pada posisi \(\frac{n+1}{2}\)

  3. Jika genap, median adalah rata-rata dari dua nilai tengah.

c. Modus

Modus adalah nilai yang paling sering muncul dalam suatu dataset. Modus dapat digunakan untuk data nominal, ordinal, interval, atau rasio.

2.1 Visualisasi untuk Central Tendency

Memahami ukuran central tendency mean median, dan modus -lebih intuitif jika didukung oleh visualisasi. Representasi grafis seperti histogram dan boxplot membantu mengungkap bentuk, sebaran, dan keseimbangan yang mendasari suatu kumpulan data. Melalui alat visual ini, kita dapat mengidentifikasi apakah data tersebut simetris miring, kategoris atau multimodal.

Setiap visualisasi memberikan wawasan yang unik:

  • Histogram menunjukkan distribusi frekuensi dan bagaimana ukuran central selaras dengan konsentrasi data.

  • Kotak-kotak menyorot median, kuartil, dan keberadaan outlier dalam format yang ringkas.

Pada subbagian berikut, kita akan mengeksplorasi bagaimana kecenderungan sentral berperilaku dalam kondisi yang berbeda visualisasi histogram dan boxplot: menggunakan

a. Simetris dan Tanpa Outlier ketika data terdistribusi secara merata di sekitar pusat.

b. Nilai Ekstrem (Miring) ketika outlier menarik nilai rata-rata ke satu arah.

c. Variabel Kategorikal - ketika data mewakili kelompok atau kelas yang berbeda.

d. Lebih Dari Satu Modus ketika data memiliki beberapa puncak atau pusat konsentrasi.

a. Simetris dan Tidak Ada Outlier

Distribusi simetris terjadi ketika nilai-nilai data tersebar merata di sekitar titik pusat, menciptakan pola yang seimbang dan berbentuk lonceng. Dalam hal ini, nilai rata-rata median, dan modus semuanya berada pada atau mendekati titik pusat yang sama. Hal ini menunjukkan bahwa tidak ada outlier atau kemiringan signifikan yang menarik data ke satu sisi.

b. Nilai Ekstrem (Miring)

Distribusi miring terjadi ketika nilai-nilai data tidak terdistribusi secara simetris di sekitar pusat artinya salah satu ekor distribusi lebih panjang atau lebih melebar daripada yang lain. Kemiringan ini sering kali disebabkan oleh nilai-nilai ekstrem (outlier) yang menarik rata-rata ke satu arah, sementara median dan modus tetap mendekati puncak data.

Ketika suatu set data berisi nilai ekstrem tinggi atau rendah, distribusinya menjadi miring positif (miring ke kanan) atau miring negatif (miring ke kiri). Distorsi ini memengaruhi posisi ukuran tendensi sentral dan memberikan wawasan berharga tentang perilaku data yang mendasarinya.

c.Variabel Kategori

Variabel kategori membagi data ke dalam kelompok atau kategori yang berbeda. Ketika dikombinasikan dengan variabel numerik, kita dapat menganalisis perbedaan distribusi nilai numerik di berbagai kategori. Boxplot merupakan visualisasi yang sangat baik untuk tujuan ini diagram ini menunjukkan median, kuartil, rentang, dan outlier dalam setiap kelompok.

d. Lebih Dari Satu Modus

Dalam banyak kumpulan data dunia nyata, distribusi nilai tidak selalu membentuk satu puncak yang halus. Sebaliknya, beberapa kumpulan data menunjukkan dua atau lebih puncak yang berbeda, yang dikenal sebagai beberapa modus. Setiap modus mewakili sebuah klaster tempat nilai-nilai cenderung terkonsentrasi artinya data memiliki beberapa wilayah dengan frekuensi tinggi, alih-alih satu lokasi sentral.

Tidak seperti histogram, boxplot tidak menampilkan jumlah puncak yang tepat, tetapi menunjukkan dengan jelas bahwa data tidak terdistribusi secara simetris misalnya, garis median mungkin tidak berada di tengah, dan kumis mungkin memanjang tidak merata ke satu sisi. Bersama-sama, histogram dan boxplot memberikan wawasan yang saling melengkapi:

  • histogram mengungkapkan keseluruhan (dan beberapa mode), bentuk

  • sementara boxplot menekankan penyebaran dan kemiringan data.

2.2 Menghitung Mean, Median, Modus

# Library
library(readr)
library(dplyr)
library(tidyr)
library(knitr)
library(kableExtra)

# Baca Data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Pilih Kolom Numerik
numeric_cols <- c("Age", "BMI", "SystolicBP", 
                  "Cholesterol", "ExerciseHours", "ComorbidityScore",
                  "RecoveryTime", "HealthScore")

# Hitung Mean, Median, dan Mode
central_tendency <- data %>%
  select(all_of(numeric_cols)) %>%
  summarise(across(everything(),
                   list(
                     Mean = ~round(mean(., na.rm = TRUE), 2),
                     Median = ~round(median(., na.rm = TRUE), 2),
                     Mode = ~as.numeric(names(sort(table(.), decreasing = TRUE)[1]))
                   )))

# Ubah ke Format Tabel Panjang
central_tendency_long <- central_tendency %>%
  pivot_longer(cols = everything(),
               names_to = c("Variable", ".value"),
               names_sep = "_")

# Tampilkan Hasil dalam Tabel
central_tendency_long %>%
  kbl(caption = "Ukuran Pemusatan (Central Tendency) Variabel Numerik",
      align = "c") %>%
  kable_styling(full_width = TRUE,
                bootstrap_options = c("striped", "hover", "condensed"))
Ukuran Pemusatan (Central Tendency) Variabel Numerik
Variable Mean Median Mode
Age 51.88 52.0 34.0
BMI 25.18 25.1 23.2
SystolicBP 130.42 130.0 131.0
Cholesterol 199.64 200.0 197.0
ExerciseHours 2.85 2.6 2.3
ComorbidityScore 0.76 1.0 0.0
RecoveryTime 14.54 14.2 14.0
HealthScore 85.00 84.8 100.0

Interpretasi

Mayoritas pasien berada pada kelompok usia paruh baya, dengan nilai BMI yang cenderung mendekati kategori overweight. Tekanan darah sistolik dan kadar kolesterol menunjukkan kondisi yang hampir mencapai batas atas normal. Tingkat aktivitas fisik pasien masih tergolong rendah, ditunjukkan oleh rata-rata waktu olahraga yang singkat setiap minggunya. Beberapa pasien juga memiliki penyakit penyerta, sebagaimana terlihat dari skor komorbiditas yang tidak nol. Waktu pemulihan pasien relatif stabil dengan nilai rata-rata yang sedang. Meskipun demikian, skor kesehatan secara umum masih menunjukkan kondisi yang baik, walau ada beberapa faktor risiko seperti BMI dan aktivitas fisik yang perlu menjadi perhatian agar kesehatan tetap terjaga.

2.3 Analisis Perbandingan Dua Variabel (BMI vs ExerciseHours)

# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)

# Baca data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Bersihkan nama kolom
colnames(data) <- gsub(" ", "", colnames(data))
colnames(data) <- tolower(colnames(data))

# Pilih kolom yang dibutuhkan
df <- data %>% select(bmi, exercisehours)

# Kategorikan BMI
df <- df %>%
  mutate(BMICategory = case_when(
    bmi < 18.5 ~ "Underweight",
    bmi < 25 ~ "Normal",
    bmi < 30 ~ "Overweight",
    TRUE ~ "Obese"
  ))

# Hitung nilai pusat (mean, median, mode)
global_mean   <- mean(df$exercisehours, na.rm = TRUE)
global_median <- median(df$exercisehours, na.rm = TRUE)
global_mode   <- as.numeric(names(sort(table(df$exercisehours), decreasing = TRUE)[1]))

line_data <- data.frame(
  Type = c("Mean", "Median", "Mode"),
  y = c(global_mean, global_median, global_mode)
)

p <- ggplot(df, aes(x = BMICategory, y = exercisehours)) +
  geom_boxplot(
    aes(fill = BMICategory),
    alpha = 0.8,
    outlier.color = "#FF6F91",
    outlier.size = 2.5,
    show.legend = FALSE
  ) +
  geom_hline(
    data = line_data,
    aes(yintercept = y, linetype = Type, color = Type),
    size = 1.3
  ) +
  scale_color_manual(values = c(
    "Mean" = "#6A5ACD", 
    "Median" = "#00C49A",
    "Mode" = "#FF6F61"
  )) +
  scale_linetype_manual(values = c("Mean" = "solid", "Median" = "dotted", "Mode" = "dashed")) +
  scale_fill_manual(values = c(
    "Underweight" = "#FFD6E0",
    "Normal" = "#A0E7E5", 
    "Overweight" = "#B4F8C8",
    "Obese" = "#FBE7C6" 
  )) +
  labs(
    title = "Perbandingan Exercise Hours Berdasarkan Kategori BMI",
    subtitle = "Boxplot dengan garis Mean, Median, dan Mode (pastel kontras aesthetic)",
    x = "BMI Category",
    y = "Exercise Hours",
    color = "Measure",
    linetype = "Measure"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 17, color = "#333333"),
    plot.subtitle = element_text(hjust = 0.5, size = 12, color = "#555555"),
    axis.text.x = element_text(angle = 15, hjust = 1, size = 11, color = "#444444"),
    panel.grid.minor = element_blank()
  )

# Konversi ke Plotly interaktif
pp <- ggplotly(p)

# Hilangkan legend boxplot
for (i in seq_along(pp$x$data)) {
  if (pp$x$data[[i]]$type %in% c("box", "scatter")) {
    if (is.null(pp$x$data[[i]]$mode) || pp$x$data[[i]]$mode == "markers") {
      pp$x$data[[i]]$showlegend <- FALSE
    }
  }
}

# Rapikan nama legend garis
pp$x$data[[length(pp$x$data)-2]]$name <- "Mean"
pp$x$data[[length(pp$x$data)-1]]$name <- "Median"
pp$x$data[[length(pp$x$data)]]$name   <- "Mode"

pp

Interpretasi

  • Normal

Mean, median, dan mode berada di sekitar 2,5–3 jam/minggu, menunjukkan distribusi yang cukup seimbang. Kelompok ini punya variasi paling besar, menandakan banyak yang rutin berolahraga.

  • Obese

Ketiga ukuran pemusatan (mean, median, mode) berada di bawah 2 jam/minggu, menandakan kelompok ini paling jarang berolahraga. Sebaran datanya sempit, menandakan pola olahraga yang relatif seragam dan rendah.

  • Overweight

Median dan mode hampir sama (sekitar 2,5 jam), sedangkan mean sedikit lebih tinggi karena ada beberapa individu dengan jam olahraga lebih banyak. Menunjukkan aktivitas sedang dengan sedikit penyimpangan ke arah nilai tinggi.

  • Underweight

Rata-rata (mean) dan median hampir sejajar di sekitar 2 jam, sedangkan mode sedikit lebih rendah. Artinya, sebagian besar kelompok ini olahraga ringan, tapi ada beberapa outlier yang olahraga jauh lebih lama (hingga 7–8 jam).

Hal ini menunjukkan bahwa tingkat aktivitas fisik berbanding terbalik dengan BMI — makin aktif seseorang, makin besar peluang memiliki BMI yang normal.

2.4 Visualisasi Central Tendency

2.4.1 BMI

# Bersihkan Environment
rm(list = ls())

# Library
library(readr)
library(dplyr)
library(plotly)

# Load Dataset
df <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Fungsi: Histogram + Density + Central Tendency
create_hist_plot <- function(.data, col_name, show_legend = TRUE) {
  
  # Ambil data kolom yang dipilih
  x <- .data[[col_name]]
  x <- x[!is.na(x)]
  
  # Hitung nilai pusat (central tendency)
  mean_val   <- mean(x)
  median_val <- median(x)
  mode_val   <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
  
  # Hitung density & histogram untuk skala
  dens <- density(x)
  hist_cal <- hist(x, plot = FALSE)
  scale_factor <- max(hist_cal$counts) / max(dens$y)
  
  # Plot Interaktif
  plot_ly() %>%
    
    # Histogram
    add_histogram(
      x = x,
      nbinsx = 15,
      opacity = 0.55,
      marker = list(color = "#6FB7FF"),
      name = "Histogram",
      showlegend = show_legend
    ) %>%
    
    # Kurva Density
    add_lines(
      x = dens$x,
      y = dens$y * scale_factor,
      name = "Density Curve",
      line = list(width = 3, color = "#0B3C5D"),
      showlegend = show_legend
    ) %>%
    
    # Garis Mean
    add_segments(
      x = mean_val, xend = mean_val,
      y = 0, yend = max(hist_cal$counts),
      name = "Mean",
      line = list(color = "red", width = 3),
      showlegend = show_legend
    ) %>%
    
    # Garis Median
    add_segments(
      x = median_val, xend = median_val,
      y = 0, yend = max(hist_cal$counts),
      name = "Median",
      line = list(color = "green", width = 3, dash = "dash"),
      showlegend = show_legend
    ) %>%
    
    # Garis Modus
    add_segments(
      x = mode_val, xend = mode_val,
      y = 0, yend = max(hist_cal$counts),
      name = "Mode",
      line = list(color = "blue", width = 3, dash = "dot"),
      showlegend = show_legend
    ) %>%
    
    # Layout: Judul & Label Sumbu
    layout(
      title = list(
        text = paste("<b>Distribusi", col_name, "</b>"),
        x = 0.5,
        xanchor = "center",
        font = list(size = 20)
      ),
      xaxis = list(title = col_name),
      yaxis = list(title = "Frequency"),
      legend = list(orientation = "h", y = -0.2),
      margin = list(t = 80, b = 70)
    )
}

# Jalankan untuk kolom BMI
create_hist_plot(df, "BMI", TRUE)

Interpretasi

  • Grafiknya menunjukkan bahwa sebagian besar pasien punya BMI di sekitar 20–25, artinya berat badan normal.

  • Grafiknya agak miring ke kanan, ada sedikit orang yang BMI-nya lebih tinggi (agak gemuk atau obesitas).

  • Puncak histogram ada di kisaran 22–25, berarti nilai BMI paling sering muncul di sekitar angka itu — ini termasuk kategori berat badan normal.

  • Kurva density membentuk lengkungan tinggi di tengah (sekitar BMI 22–25) lalu menurun ke kanan, tandanya jumlah orang dengan BMI tinggi lebih sedikit.

Hal ini menunjukkan bahwa distribusi BMI kebanyakan normal tapi sebagian kecil yang cenderung ke arah berat badan berlebih.

2.4.2 ExerciseHours

# Bersihkan Environment 
rm(list = ls())

# Library yang dibutuhkan
library(readr)
library(dplyr)
library(plotly)

# Baca data
df <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Fungsi: Histogram + Density + Central Tendency
create_hist_plot <- function(.data, col_name, show_legend = TRUE) {
  
  # Ambil data kolom yang dipilih
  x <- .data[[col_name]]
  x <- x[!is.na(x)]
  
  # Hitung nilai pusat (central tendency)
  mean_val   <- mean(x)
  median_val <- median(x)
  mode_val   <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
  
  # Hitung density & histogram untuk skala
  dens <- density(x)
  hist_cal <- hist(x, plot = FALSE)
  scale_factor <- max(hist_cal$counts) / max(dens$y)
  
  # Plot Interaktif
  plot_ly() %>%
    
    # Histogram
    add_histogram(
      x = x,
      nbinsx = 15,
      opacity = 0.55,
      marker = list(color = "#6FB7FF"),
      name = "Histogram",
      showlegend = show_legend
    ) %>%
    
    # Kurva Density
    add_lines(
      x = dens$x,
      y = dens$y * scale_factor,
      name = "Density Curve",
      line = list(width = 3, color = "#0B3C5D"),
      showlegend = show_legend
    ) %>%
    
    # Garis Mean
    add_segments(
      x = mean_val, xend = mean_val,
      y = 0, yend = max(hist_cal$counts),
      name = "Mean",
      line = list(color = "red", width = 3),
      showlegend = show_legend
    ) %>%
    
    # Garis Median
    add_segments(
      x = median_val, xend = median_val,
      y = 0, yend = max(hist_cal$counts),
      name = "Median",
      line = list(color = "green", width = 3, dash = "dash"),
      showlegend = show_legend
    ) %>%
    
    # Garis Modus
    add_segments(
      x = mode_val, xend = mode_val,
      y = 0, yend = max(hist_cal$counts),
      name = "Mode",
      line = list(color = "blue", width = 3, dash = "dot"),
      showlegend = show_legend
    ) %>%
    
    # Layout: Judul & Label Sumbu
    layout(
      title = list(
        text = paste("<b>Distribusi", col_name, "</b>"),
        x = 0.5,
        xanchor = "center",
        font = list(size = 20)
      ),
      xaxis = list(title = col_name),
      yaxis = list(title = "Frequency"),
      legend = list(orientation = "h", y = -0.2),
      margin = list(t = 80, b = 70)
    )
}

# Jalankan untuk kolom ExerciseHours
create_hist_plot(df, "ExerciseHours", TRUE)

Interpretasi

  • Bentuk grafik miring ke kiri (left-skewed), artinya kebanyakan pasien berolahraga dengan durasi pendek, sementara hanya beberapa pasien yang berolahraga dengan durasi lama (lebih dari 6 jam).

  • Puncak histogram paling tinggi ada di sekitar 1–3 jam yang berarti mayoritas pasien berolahraga sekitar 1–3 jam.

  • Kurva Density membentuk lengkungan tinggi di awal (sekitar 2 jam) lalu menurun ke kanan.

  • Nilai rata-rata lebih kecil dari median, menandakan adanya sebagian pasien yang jarang berolahraga.

Hal ini menunjukkan bahwa kebanyakan pasien melakukan olahraga dengan durasi yang pendek, sementara hanya sedikit yang rutin berolahraga lama.

3. Measures of Dispersion

Jika Central Tendency menunjukkan nilai tengah dari suatu data, maka Measures of Dispersion menjelaskan seberapa jauh data menyebar dari nilai tengah tersebut. Jadi, penyebaran menggambarkan tingkat variasi atau keberagaman data. Dua kumpulan data bisa memiliki rata-rata yang sama, tapi penyebarannya bisa sangat berbeda — satu bisa rapat, yang lain bisa tersebar luas.

a. Range

Range adalah ukuran dispersi yang paling sederhana, yang mewakili selisih antara observasi terbesar dan terkecil dalam suatu kumpulan data. Range memberikan gambaran singkat tentang seberapa luas penyebaran data.

Rumus:

\[ Range = X_{max} - X_{min} \]

Range yang lebih besar menunjukkan variabilitas yang lebih besar di antara nilai-nilai data, sementara range yang lebih kecil menunjukkan bahwa data lebih terkonsentrasi di sekitar rata-rata. Range ini mudah dihitung dan dipahami, menjadikannya ukuran yang berguna untuk memberikan estimasi cepat dan kasar tentang seberapa luas penyebaran data. Namun, range ini memiliki keterbatasan yang perlu diperhatikan: range ini sangat sensitif terhadap outlier dan tidak memperhitungkan distribusi nilai antara observasi terkecil dan terbesar.

b. Variances

Variances mengukur rata-rata deviasi kuadrat dari rata-rata. Variances mengkuantifikasi seberapa besar setiap titik data berbeda dari rata-rata, yang mencerminkan tingkat penyebaran dalam kumpulan data.

Rumus:

  • Untuk suatu populasi:

\[ \sigma^2 = \frac{\sum_{i=1}^{N}(X_i - \mu)^2}{N} \]

  • Untuk sample:

\[ s^2 = \frac{\sum_{i=1}^{n}(X_i - \bar{X})^2}{n-1} \]

Variances yang lebih tinggi menunjukkan bahwa titik-titik data menyebar lebih luas dari rata-rata, sementara variances yang lebih rendah menunjukkan bahwa titik-titik data tersebut mengelompok lebih rapat. Variances memperhitungkan semua titik data dalam suatu set data, bukan hanya nilai ekstremnya, dan berfungsi sebagai dasar untuk pengukuran statistik yang lebih maju seperti deviasi standar dan ANOVA. Namun, karena variances dinyatakan dalam satuan kuadrat, interpretasinya secara langsung mungkin kurang intuitif. Selain itu, variances sensitif terhadap nilal ekstrem, yang dapat memengaruhi ukuran variabilitas secara tidak proporsional.

c. Standard Deviation

Standard Deviation (SD) adalah akar kuadrat dari variances. SD mengukur jarak rata-rata setiap titik data dari rata-rata dan dinyatakan dalam satuan yang sama dengan data asli.

Rumus:

  • Untuk suatu populasi:

    \[ \sigma = \sqrt{\frac{\sum_{i=1}^{N}(X_i - \mu)^2}{N}} \]

  • Untuk sample:

\[ s = \sqrt{\frac{\sum_{i=1}^{n}(X_i - \bar{X})^2}{n-1}} \]

Standard Deviation yang rendah menunjukkan bahwa titik-titik data dekat dengan rata-rata, yang mencerminkan variabilitas rendah dalam dataset, sementara standard deviation yang tinggi menunjukkan bahwa titik-titik data lebih tersebar luas, yang menunjukkan variabilitas yang lebih tinggi. Salah satu keuntungan utama standard deviation adalah bahwa ia dinyatakan dalam satuan yang sama dengan data asli, membuatnya lebih mudah untuk ditafsirkan dibandingkan dengan variances. Ini juga banyak digunakan dalam statistik deskriptif dan inferensial untuk menilai konsistensi dan reliabilitas data. Namun, standard deviation dipengaruhi oleh outlier, yang dapat mendistorsi ukuran penyebaran, dan mengasumsikan bahwa distribusi data kira-kira normal agar interpretasinya paling bermakna.

Interquartile Range (IQR)

IQR (Interquartile Range) adalah rentang antar kuartil yang menunjukkan seberapa lebar penyebaran 50% data di tengah dari suatu kumpulan data.

Rumus:

\[ \text{IQR} = Q_3 - Q_1 \]

3.1 Menghitung Range, Variance, Standart Deviation, dan Interquartile Range (IQR)

# Library
library(readr)
library(dplyr)
library(DT)

# Load dataset
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Bersihkan nama kolom
colnames(data) <- gsub(" ", "", colnames(data))
colnames(data) <- tolower(colnames(data))

# Pilih variabel
df <- data %>% select(bmi, exercisehours)

# Hitung summary statistik untuk masing-masing variabel
summary_stats <- df %>%
  summarise(
    Mean_BMI = mean(bmi, na.rm = TRUE),
    Min_BMI = min(bmi, na.rm = TRUE),
    Max_BMI = max(bmi, na.rm = TRUE),
    Range_BMI = Max_BMI - Min_BMI,
    Variance_BMI = var(bmi, na.rm = TRUE),
    SD_BMI = sd(bmi, na.rm = TRUE),
    IQR_BMI = IQR(bmi, na.rm = TRUE),
    
    Mean_Exercise = mean(exercisehours, na.rm = TRUE),
    Min_Exercise = min(exercisehours, na.rm = TRUE),
    Max_Exercise = max(exercisehours, na.rm = TRUE),
    Range_Exercise = Max_Exercise - Min_Exercise,
    Variance_Exercise = var(exercisehours, na.rm = TRUE),
    SD_Exercise = sd(exercisehours, na.rm = TRUE),
    IQR_Exercise = IQR(exercisehours, na.rm = TRUE)
  )

# Ubah jadi format tabel rapi
summary_long <- tibble(
  Variable = c("BMI", "Exercise Hours"),
  Mean = c(summary_stats$Mean_BMI, summary_stats$Mean_Exercise),
  Min = c(summary_stats$Min_BMI, summary_stats$Min_Exercise),
  Max = c(summary_stats$Max_BMI, summary_stats$Max_Exercise),
  Range = c(summary_stats$Range_BMI, summary_stats$Range_Exercise),
  Variance = c(summary_stats$Variance_BMI, summary_stats$Variance_Exercise),
  SD = c(summary_stats$SD_BMI, summary_stats$SD_Exercise),
  IQR = c(summary_stats$IQR_BMI, summary_stats$IQR_Exercise)
)

# Tampilkan tabel interaktif
datatable(
  summary_long %>%
    mutate(across(where(is.numeric), ~round(., 2))),
  options = list(
    dom = 't',        
    paging = FALSE,
    ordering = FALSE
  ),
  rownames = FALSE
)

Interpretasi

Berdasarkan hasil analisis, rata-rata BMI responden adalah 25,18 yang menunjukkan bahwa sebagian besar individu berada pada kategori overweight. Nilai BMI berkisar antara 13 hingga 40,7 menggambarkan adanya perbedaan kondisi tubuh yang cukup besar di antara responden.Rata-rata waktu olahraga per minggu tercatat sebesar 2,85 jam yang tergolong rendah. Bahkan, terdapat beberapa responden yang tidak berolahraga sama sekali, sementara sebagian lainnya berolahraga hingga 9 jam per minggu. Hal ini menunjukkan adanya variasi yang cukup besar dalam kebiasaan aktivitas fisik.

Secara keseluruhan, hasil ini mengindikasikan bahwa tingkat aktivitas fisik responden relatif rendah, dan kondisi tersebut berpotensi berhubungan dengan nilai BMI yang cenderung tinggi pada sebagian besar individu.

3.2 Visualisasi Measures of Dispersion

3.2.1 Boxplot

# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
library(tidyr)

# Baca data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Bersihkan nama kolom
colnames(data) <- gsub(" ", "", colnames(data))
colnames(data) <- tolower(colnames(data))

# Pilih kolom yang dibutuhkan
df <- data %>% select(bmi, exercisehours)

# Ubah ke format long
df_long <- df %>%
  pivot_longer(cols = everything(),
               names_to = "Variable",
               values_to = "Value")

# Hitung summary untuk mean label
summary_df <- df_long %>%
  group_by(Variable) %>%
  summarise(Mean = mean(Value, na.rm = TRUE))

# Plot violin + boxplot (static)
p <- ggplot(df_long, aes(x = Variable, y = Value, fill = Variable)) +
  geom_violin(alpha = 0.5, trim = FALSE, color = NA) +
  geom_boxplot(width = 0.15, outlier.color = "hotpink", alpha = 0.6) +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 3,
               fill = "#007FFF", color = "black") +
  geom_text(data = summary_df,
            aes(x = Variable, y = Mean + 3,
                label = paste0("Mean = ", round(Mean, 2))),
            color = "#007FFF", size = 3.5, fontface = "bold",
            inherit.aes = FALSE) +
  labs(
    title = "Distribusi & Penyebaran Data BMI dan Exercise Hours",
    subtitle = "Visualisasi interaktif violin + boxplot untuk menunjukkan variabilitas",
    x = "",
    y = "Nilai",
    caption = "Sumber: Hospital Dataset"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 11)
  ) +
  scale_fill_manual(values = c("#A0E7E5", "#B4F8C8"))

# Buat tabel interaktif
ggplotly(p, tooltip = c("x", "y"))

Interpretasi

  • Nilai rata-rata BMI adalah 25.18, artinya kebanyakan pasien punya berat badan normal sampai sedikit berlebih.

  • Sebagian besar nilai BMI ada di antara 20 sampai 30, tapi ada juga beberapa pasien yang BMI-nya tinggi banget (di atas 35).

Interpretasi Exercise Hours

  • Rata-rata waktu olahraga pasien hanya sekitar 2.85 jam.

  • Sebagian besar pasien olahraga hanya sebentar, sehingga sedikit pasien yang berolahraga lama (lebih dari 6 jam).

  • Nilai BMI lebih bervariasi, berat badan pasien berbeda-beda.

Kebanyakan pasien punya BMI normal, tapi masih ada yang gemuk atau obesitas. Sementara itu, rata-rata waktu olahraga masih rendah, menandakan banyak pasien belum berolahraga cukup lama.

3.2.2 Histogram

# Library
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
library(tidyr)

# Baca data
data <- read_csv("C:/Users/HYPE AMD/Desktop/Midterm Exam/Hospital Dataset.csv")

# Bersihkan nama kolom
colnames(data) <- gsub(" ", "", colnames(data))
colnames(data) <- tolower(colnames(data))

# Pilih kolom yang dibutuhkan
df <- data %>% select(bmi, exercisehours)

# Ubah ke format long
df_long <- df %>%
  pivot_longer(cols = everything(),
               names_to = "Variable",
               values_to = "Value")

# Hitung nilai mean & density peak untuk posisi label
density_peaks <- df_long %>%
  group_by(Variable) %>%
  summarise(PeakY = max(density(Value, na.rm = TRUE)$y))

summary_df <- df_long %>%
  group_by(Variable) %>%
  summarise(Mean = mean(Value, na.rm = TRUE))

label_data <- left_join(summary_df, density_peaks, by = "Variable")

# Plot histogram + density + mean line
p <- ggplot(df_long, aes(x = Value, fill = Variable)) +
  geom_histogram(aes(y = after_stat(density)),
                 alpha = 0.5, color = "black", bins = 40,
                 position = "identity") +
  geom_density(alpha = 0.3, size = 1, color = "darkblue") +
  geom_vline(data = summary_df, aes(xintercept = Mean, color = Variable),
             linetype = "dashed", size = 1) +
  geom_text(
    data = label_data,
    aes(x = Mean, y = PeakY + 0.005,
        label = paste0("Mean = ", round(Mean, 2))),
    color = "#0077B6", size = 3.5, fontface = "bold",
    inherit.aes = FALSE
  ) +
  facet_wrap(~Variable, ncol = 1, scales = "free_y") +
  scale_fill_manual(values = c("#A0E7E5", "#B4F8C8")) +
  scale_color_manual(values = c("#72DDF7", "#FFAEBC")) +
  labs(
    title = "Distribusi Data BMI dan Exercise Hours",
    subtitle = "Histogram + Density plot dengan garis Mean (interaktif)",
    x = "Nilai",
    y = "Kepadatan (Density)",
    caption = "Sumber: Hospital Dataset"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 11)
  )

# Jadikan interaktif
ggplotly(p, tooltip = c("x", "y"))

Interpretasi

  • BMI memiliki kepadatan tertinggi di rentang 23–27, menunjukkan sebagian besar pasien memiliki BMI sedikit di atas normal. Rata-rata BMI 25,18 sejalan dengan area paling padat.

  • Exercise hours memiliki kepadatan tertinggi di 1–3 jam/minggu, menandakan kebanyakan pasien hanya berolahraga sedikit. Rata-ratanya 2,85 jam/minggu yang tergolong rendah.

  • Mayoritas pasien memiliki BMI cenderung tinggi dan jam olahraga rendah.

Kepadatan data menunjukkan bahwa kurangnya aktivitas fisik kemungkinan berkontribusi terhadap tingginya BMI, meskipun hubungan pastinya perlu analisis lebih lanjut.

3.2.3 Scatter Plot

# Library
library(ggplot2)
library(plotly)

# Simulasi data berdasarkan tabel
set.seed(123)
data <- data.frame(
  BMI = rnorm(100, mean = 25.18, sd = 4.02),
  ExerciseHours = rnorm(100, mean = 2.85, sd = 1.6)
)

# Batasi nilai sesuai rentang tabel
data$BMI <- pmin(pmax(data$BMI, 13), 40.7)
data$ExerciseHours <- pmin(pmax(data$ExerciseHours, 0), 9)

# Buat kategori BMI
data$BMI_Group <- cut(
  data$BMI,
  breaks = c(-Inf, 18.5, 25, 30, Inf),
  labels = c("Underweight", "Normal", "Overweight", "Obese")
)

# Plot dengan warna kontras antar kategori
p <- ggplot(data, aes(x = ExerciseHours, y = BMI, color = BMI_Group)) +
  geom_point(size = 4, alpha = 0.8) +
  scale_color_manual(values = c("#0072B2", "#009E73", "#E69", "#559B90")) +
  geom_hline(yintercept = mean(data$BMI), linetype = "dashed", color = "black") +
  geom_vline(xintercept = mean(data$ExerciseHours), linetype = "dotted", color = "gray40") +
  labs(
    title = "Scatterplot: BMI vs Exercise Hours",
    x = "Exercise Hours (Jam Olahraga per Minggu)",
    y = "BMI (Body Mass Index)",
    color = "Kategori BMI"
  ) +
  theme_minimal(base_size = 14) +
  theme(plot.title = element_text(face = "bold", size = 16))

# Buat tabel interaktif
ggplotly(p, tooltip = c("x", "y", "color"))

Interpretasi

  • pasien dengan BMI Normal cenderung berolahraga lebih banyak, terlihat dengan banyaknya titik yang berada di sisi kanan grafik.

  • pasien dengan BMI Overweight dan Obese lebih banyak terdistribusi di bagian kiri grafik (kurang dari 3 jam olahraga per minggu), yang menunjukkan hubungan antara kurangnya olahraga dengan kenaikan BMI.

  • pasien dengan BMI Underweight sebagian besar terdistribusi di sisi kiri grafik, dengan jam olahraga yang cenderung lebih sedikit dibandingkan kategori lainnya.

Secara keseluruhan, terdapat kecenderungan bahwa pasien dengan BMI lebih tinggi (Overweight dan Obese) berolahraga lebih sedikit, sementara pasien dengan BMI normal berolahraga dalam jumlah yang lebih banyak.

4. Summary and Interpretation

Analisis ini bertujuan untuk memahami karakteristik pasien serta hubungan antara faktor-faktor kesehatan seperti Age, BMI, SystolicBP, ExerciseHours, dan SmokingStatus terhadap RecoveryTime dan HealthScore. Hasil perhitungan statistik dan visualisasi menunjukkan bahwa sebagian besar data memiliki pola yang cukup teratur dengan beberapa perbedaan penting di antara variabelnya.

Variabel yang paling konsisten adalah HealthScore dan ExerciseHours, karena nilai sebarannya relatif kecil dan cenderung seragam antar pasien. Hal ini mengindikasikan bahwa kondisi kesehatan umum dan kebiasaan olahraga pasien cukup stabil. Sebaliknya, variabel seperti BMI, SystolicBP, dan terutama RecoveryTime menunjukkan variasi yang tinggi, menandakan adanya perbedaan signifikan dalam kondisi fisik dan proses pemulihan tiap pasien.

Dari hasil visualisasi, terlihat bahwa pasien yang menjalani Therapy memiliki waktu pemulihan tercepat, sedangkan Surgery membutuhkan waktu paling lama. Distribusi data pada histogram dan boxplot juga memperlihatkan pola mendekati normal dengan beberapa outlier. Secara keseluruhan, analisis ini menegaskan bahwa jenis perawatan, kebiasaan hidup, dan kondisi awal pasien berperan penting dalam menentukan hasil kesehatan akhir.

5. Video Explanation

Berikut video presentasi kami terkait penjelasan hasil analisis kami

Klik gambar untuk menonton video

6. References

[1] Siregar, B. (n.d.). Introduction to statistics. dsciencelabs. https://bookdown.org/dsciencelabs/intro_statistics/Preface.html

[2] Siregar, B. (n.d.). Introduction to statistics: Chapter 2 Data Exploration. dsciencelabs. https://bookdown.org/dsciencelabs/intro_statistics/02-Data_Exploration.html

[3] Siregar, B. (n.d.). Introduction to statistics: Chapter 3 Basic Data Visualizations. dsciencelabs. https://bookdown.org/dsciencelabs/intro_statistics/03-Basic_Visualizations.html

[4] Siregar, B. (n.d.). Introduction to statistics: Chapter 4 Central Tendency. dsciencelabs. https://bookdown.org/dsciencelabs/intro_statistics/04-Central_Tendency.html

[5] Siregar, B. (n.d.). Introduction to statistics: Chapter 5 Statistical Dispersion. dsciencelabs. https://bookdown.org/dsciencelabs/intro_statistics/05-Statistical_Dispersion.html