Link data https://www.kaggle.com/code/farzadnekouei/heart-disease-prediction/input
Penjelasan variabel dan skala data :
Age adalah usia pasien dalam tahun dan termasuk skala rasio
Sex adalah jenis kelamin pasien dimana 0 untuk perempuan dan 1 untuk laki-laki, termasuk skala nominal
Cp (chest pain type) adalah tipe nyeri dada dan termasuk skala ordinal yang memiliki nilai yaitu :
0 untuk typical angina berarti nyeri dada khas karena masalah jantung
1 untuk atypical angina berarti nyeri dada tidak khas
2 untuk non anginal plain berarti bukan nyeri jantung
3 untuk asymptomatic berarti tidak ada gejala nyeri,
Trestbps (resting blood pressure) adalah tekanan darah saat istirahat dengan satuan mm Hg dan termasuk skala rasio
Chol (serum cholesterol) adalah kadar kolesterol dalam darah dengan satuan mg/dl dan termasuk skala rasio
Fbs (fasting blood sugar) adalah gula darah puasa dimana 1 untuk ya (>120 mg/dl berarti tinggi) dan 0 untuk tidak (<= 120 mg/dl berarti normal), termasuk skala nominal
Restecg (resting electrocardiographic results) adalah hasil EKG istirahat dan termasuk skala ordinal yang memiliki nilai yaitu :
0 untuk normal
1 untuk ada kelainan gelombang ST-T
2 untuk hipertrofi ventrikel kiri
Thalag (maximum heart rate achieved) adalah denyut jantung maksimum yang dicapai saat uji stres dengan satuan bpm dan termasuk skala rasio
Exang (exercise induced angina) adalah nyeri dada yang dipicu oleh olahraga dimana 1 untuk ya dan 0 untuk tidak, termasuk skala nominal
Oldpeak (ST Depression Induced by Exercise) untuk mengukur seberapa besar penurunan segmen ST saat olahraga dibandingkan dengan kondisi istirahat dengan satuan mm dan termasuk skala interval
Slope adalah kemiringan segmen ST saat puncak latihan bernilai 0 untuk menurun, 1 untuk datar dan 2 untuk menanjak, termasuk skala ordinal
Ca (number of major vessels) adalah jumlah pembuluh darah besar yang terlihat saat fluoroskopi bernilai 0 sampai 3, termasuk skala ordinal
Thal (thalassemia) adalah hasil tes thal dan termasuk skala ordinal yang memiliki nilai yaitu :
0 untuk tidak diketahui
1 untuk fixed defect artinya kerusakan permanen pada aliran darah jantung (tampak saat istirahat & tetap saat olahraga)
2 untuk tidak ada kelainan atau normal
3 untuk reversible defect artinya gangguan yang hanya muncul saat olahraga dan menghilang saat istirahat (menandakan potensi penyakit jantung)
Target untuk menunjukkan apakah mengidap penyakit jantung dan termasuk skala nominal
# Baca file heart.csv
data <- read.csv("D:\\KAMPUS MBA\\PSD\\heart.csv")
# Jumlah nilai yang hilang di setiap kolom
colSums(is.na(data))
## age sex cp trestbps chol fbs restecg thalach
## 0 0 0 0 0 0 0 0
## exang oldpeak slope ca thal target
## 0 0 0 0 0 0
data$chol[is.na(data$chol)] <- median(data$chol, na.rm = TRUE)
# Cek jumlah baris duplikat
sum(duplicated(data))
## [1] 1
#Penangan duplikat
data <- data[!duplicated(data), ]
# Hapus data duplikat
data <- data[!duplicated(data), ]
# Buat boxplot untuk semua variabel numerik
num_vars <- sapply(data, is.numeric)
boxplot(data[, num_vars], main = "Boxplot Variabel Numerik", las = 2, col = "rosybrown1")
data <- subset(data, chol <= 600)
# Statistika deskriptif
summary(data[, num_vars])
## age sex cp trestbps
## Min. :29.00 Min. :0.0000 Min. :0.0000 Min. : 94.0
## 1st Qu.:48.00 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:120.0
## Median :55.50 Median :1.0000 Median :1.0000 Median :130.0
## Mean :54.42 Mean :0.6821 Mean :0.9636 Mean :131.6
## 3rd Qu.:61.00 3rd Qu.:1.0000 3rd Qu.:2.0000 3rd Qu.:140.0
## Max. :77.00 Max. :1.0000 Max. :3.0000 Max. :200.0
## chol fbs restecg thalach
## Min. :126.0 Min. :0.000 Min. :0.0000 Min. : 71.0
## 1st Qu.:211.0 1st Qu.:0.000 1st Qu.:0.0000 1st Qu.:133.2
## Median :240.5 Median :0.000 Median :1.0000 Median :152.5
## Mean :246.5 Mean :0.149 Mean :0.5265 Mean :149.6
## 3rd Qu.:274.8 3rd Qu.:0.000 3rd Qu.:1.0000 3rd Qu.:166.0
## Max. :564.0 Max. :1.000 Max. :2.0000 Max. :202.0
## exang oldpeak slope ca
## Min. :0.0000 Min. :0.000 Min. :0.000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.000 1st Qu.:1.000 1st Qu.:0.0000
## Median :0.0000 Median :0.800 Median :1.000 Median :0.0000
## Mean :0.3278 Mean :1.043 Mean :1.397 Mean :0.7185
## 3rd Qu.:1.0000 3rd Qu.:1.600 3rd Qu.:2.000 3rd Qu.:1.0000
## Max. :1.0000 Max. :6.200 Max. :2.000 Max. :4.0000
## thal target
## Min. :0.000 Min. :0.000
## 1st Qu.:2.000 1st Qu.:0.000
## Median :2.000 Median :1.000
## Mean :2.315 Mean :0.543
## 3rd Qu.:3.000 3rd Qu.:1.000
## Max. :3.000 Max. :1.000
Tidak ditemukan missing values pada seluruh kolom data, semua nilai dalam dataset telah terisi lengkap sehingga tidak diperlukan penanganan terhadap nilai hilang. Ditemukan 1 baris duplikat. Data duplikat dapat menyebabkan bias dalam analisis karena mengulang informasi yang sama. Menghapus duplikat membuat data lebih akurat dan representatif. Kemudian, untuk penanganan outlier yang sangat ekstrem dan tidak masuk akal bisa dihapus menggunakan metode IQR. Namun, dalam data ini tidak dihapus karena nilai-nilainya masih memungkinkan secara medis.
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.3
ggplot(data[data$target == 1, ], aes(x = factor(sex), fill = factor(sex))) +
geom_bar() +
scale_fill_manual(values = c("0" = "rosybrown1", "1" = "rosybrown"),
labels = c("0" = "Perempuan", "1" = "Laki-laki")) +
labs(title = "Jumlah Penderita Penyakit Jantung Berdasarkan Jenis Kelamin",
x = "Jenis Kelamin (0 = Perempuan, 1 = Laki-laki)",
y = "Jumlah Pasien",
fill = "Jenis Kelamin")
ggplot(data[data$target == 1, ], aes(x = age)) +
geom_histogram(binwidth = 1, fill = "rosybrown3", color = "black") +
labs(title = "Distribusi Usia Penderita Penyakit Jantung",
x = "Usia",
y = "Jumlah Pasien")
ggplot(data[data$fbs == 1, ], aes(x = age)) +
geom_histogram(binwidth = 1, fill = "rosybrown", color = "black") +
labs(title = "Distribusi Usia dengan Gula Darah > 120 mg/dl",
x = "Usia",
y = "Jumlah Pasien")
Jenis kelamin yang paling banyak mengalami Heart desease adalah laki-laki, usia yang paling banyak mengalami heart desease adalah sekitar 50 sampai 55 tahun, dengan puncaknya di sekitar usia 54 sampai 55 tahun, dan usia yang memiliki gula darah lebih besar dari 120 mg/dl adalah sekitar 51 smapai 52 tahun dengan jumlah pasien terbanyak mencapai 5 orang.
# Tabel kontingensi antara fbs dan target (penyakit jantung)
table_fbs_target <- table(data$fbs, data$target)
colnames(table_fbs_target) <- c("Tidak_Sakit_Jantung", "Sakit_Jantung")
rownames(table_fbs_target) <- c("Gula_Darah_Normal", "Gula_Darah_Tinggi")
print(table_fbs_target)
##
## Tidak_Sakit_Jantung Sakit_Jantung
## Gula_Darah_Normal 116 141
## Gula_Darah_Tinggi 22 23
# Proporsi masing-masing baris (per kategori fbs)
prop.table(table_fbs_target, 1)
##
## Tidak_Sakit_Jantung Sakit_Jantung
## Gula_Darah_Normal 0.4513619 0.5486381
## Gula_Darah_Tinggi 0.4888889 0.5111111
# Uji chi square
chisq.test(table_fbs_target)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: table_fbs_target
## X-squared = 0.092408, df = 1, p-value = 0.7611
Berdasarkan analisis data dan uji chi-square menyatakan bahwa tidak terdapat hubungan yang signifikan antara kadar gula darah >120 dengan penyakit jantung (p-value = 0,7611). Meskipun secara persentase penderita penyakit jantung sedikit lebih tinggi pada kelompok dengan gula darah tinggi sebesar 51,1% dibandingkan dengan yang normal sebesar 54,9%, perbedaan ini tidak signifikan. Bahkan penderita penyakit jantung lebih banyak berasal dari kelompok dengan gula darah normal karena ukuran kelompoknya lebih besar. Oleh karena itu, kadar gula darah >120 tidak dapat disimpulkan sebagai faktor yang paling banyak berhubungan dengan penyakit jantung dalam data ini.
# Buat tabel kontingensi antara cp dan target
table_cp_target <- table(data$cp, data$target)
# Ambil hanya baris dengan target = 1 (artinya sakit jantung)
table_cp_target[, "1"]
## 0 1 2 3
## 39 41 68 16
Berdasarkan hasil analisis data menyatakan bahwa jenis nyeri dada yang paling banyak dialami oleh penderita penyakit jantung (target = 1) adalah Non-anginal Pain (cp = 2) dengan jumlah kasus sebanyak 68 orang, artinya banyak penderita penyakit jantung tidak mengalami nyeri dada khas seperti angina, melainkan nyeri yang tidak spesifik.
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# Visualisasi proporsi berdasarkan cp (Chest Pain Type)
p1 <- data %>%
group_by(cp, target) %>%
summarise(count = n(), .groups = "drop") %>%
mutate(prop = count / sum(count)) %>%
ggplot(aes(x = factor(cp), y = prop, fill = factor(target))) +
geom_bar(stat = "identity", position = "dodge") +
scale_fill_manual(values = c("0" = "rosybrown1", "1" = "rosybrown3")) +
labs(title = "Proporsi Heart Disease Berdasarkan Chest Pain (cp)",
x = "Chest Pain Type (cp)",
y = "Proporsi",
fill = "Heart Disease (target)") +
theme_minimal()
# Visualisasi proporsi berdasarkan ca (Jumlah Pembuluh)
p2 <- data %>%
group_by(ca, target) %>%
summarise(count = n(), .groups = "drop") %>%
mutate(prop = count / sum(count)) %>%
ggplot(aes(x = factor(ca), y = prop, fill = factor(target))) +
geom_bar(stat = "identity", position = "dodge") +
scale_fill_manual(values = c("0" = "rosybrown1", "1" = "rosybrown3")) +
labs(title = "Proporsi Heart Disease Berdasarkan Jumlah Pembuluh (ca)",
x = "Number of Major Vessels (ca)",
y = "Proporsi",
fill = "Heart Disease (target)") +
theme_minimal()
# Visualisasi proporsi berdasarkan thal (Thalassemia Type)
p3 <- data %>%
group_by(thal, target) %>%
summarise(count = n(), .groups = "drop") %>%
mutate(prop = count / sum(count)) %>%
ggplot(aes(x = factor(thal), y = prop, fill = factor(target))) +
geom_bar(stat = "identity", position = "dodge") +
scale_fill_manual(values = c("0" = "rosybrown1", "1" = "rosybrown3")) +
labs(title = "Proporsi Heart Disease Berdasarkan Thalassemia (thal)",
x = "Thalassemia Type (thal)",
y = "Proporsi",
fill = "Heart Disease (target)") +
theme_minimal()
# Tampilkan grafik satu per satu
p1
p2
p3
Pada variabel cp, proporsi penderita penyakit jantung paling tinggi di tipe nyeri dada 2 sebesar 77% dan terendah di tipe nyeri dada 0 sebesar 42,9% sehingga tidak monotonic karena semakin berat nyeri tidak berarti semakin tinggi risiko. Kemudian, pada variabel ca, individu dengan jumlah pembuluh darah besar bernilai 0 sebesar 72,4% menunjukkan proporsi tertinggi menderita penyakit jantung dan proporsi tersebut menurun seiring bertambahnya nilai ca sehingga makin besar nilai ca maka makin kecil risiko. Sedangkan pada variabel thal, proporsi penyakit jantung paling tinggi terdapat pada tipe thalassemia 2, sedangkan tipe 3 didominasi oleh individu yang tidak menderita penyakit jantung sehingga tidak monotonic karena urutan risikonya tidak sesuai dengan urutan angkanya.
# Ubah target ke faktor agar mudah dibedakan
data$target <- factor(data$target, labels = c("Tidak Sakit", "Sakit"))
# Scatter plot
ggplot(data, aes(x = age, y = thalach, color = target)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, linetype = "solid") + # untuk lihat pola non-linear
geom_smooth(method = "lm", se = FALSE, linetype = "dashed") + # untuk lihat pola linear
scale_color_manual(values = c("Tidak Sakit" = "rosybrown1", "Sakit" = "rosybrown")) +
labs(title = "Hubungan Age dan Thalach Berdasarkan Status Penyakit Jantung",
x = "Umur (Age)",
y = "Denyut Jantung Maksimal (Thalach)",
color = "Status Jantung") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
Untuk mengetahui arah hubungan antara variabel age dan thalach yang dibedakan untuk seseorang yang memiliki penyakit jantung dan tidak dilakukan dengan cara menbuat scatter plot. Hasilnya menunjukkan hubungan negatif antara umur dan denyut jantung maksimal (thalach) yang dibedakan berdasarkan status penyakit jantung. Terlihat bahwa baik pada individu yang sakit maupun tidak sakit jantung, nilai thalach cenderung menurun seiring bertambahnya usia. Namun, pola penurunan tersebut tidak berbentuk garis lurus melainkan melengkung berarti mengindikasikan hubungan non-linear. Pada individu yang memiliki penyakit jantung, penurunan thalach tampak lebih tajam di usia muda dan mulai melandai seiring bertambahnya usia. Sebaliknya, pada individu yang tidak memiliki penyakit jantung, meskipun penurunan juga terjadi, terdapat sedikit kenaikan kembali di usia tua yang mungkin disebabkan oleh variasi data.
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.3.3
## Warning: package 'tibble' was built under R version 4.3.3
## Warning: package 'tidyr' was built under R version 4.3.3
## Warning: package 'readr' was built under R version 4.3.3
## Warning: package 'purrr' was built under R version 4.3.3
## Warning: package 'stringr' was built under R version 4.3.3
## Warning: package 'forcats' was built under R version 4.3.3
## Warning: package 'lubridate' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.4 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.1
## ✔ readr 2.1.5
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggcorrplot)
## Warning: package 'ggcorrplot' was built under R version 4.3.3
# Ambil hanya kolom numerik
data_num <- data %>% select(where(is.numeric))
# Hitung korelasi
cor_matrix <- cor(data_num, use = "complete.obs")
# Plot heatmap korelasi
ggcorrplot(cor_matrix,
method = "square",
type = "lower",
lab = TRUE,
title = "Heatmap Korelasi Variabel Numerik")
Intensitas warna mencerminkan kekuatan korelasi, warna yang lebih gelap menunjukkan hubungan yang lebih kuat. Terlihat adanya korelasi positif yang cukup kuat antara oldpeak dengan exang sebesar 0.26 dan korelasi negatif yang cukup kuat antara oldpeak dengan thalach sebesar -0.38 dan antara exang dengan thalach sebesar -0.34. Sebaliknya, beberapa variabel seperti fbs dan restecg tampak memiliki korelasi yang lemah dengan variabel lainnya karena warna pada sel-sel yang bersesuaian cenderung mendekati putih atau memiliki nilai korelasi yang kecil.
Hal-hal yang dapat mencegah penyakit jantung adalah menerapkan gaya hidup sehat seperti menjaga pola makan rendah lemak dan kolesterol, rutin berolahraga, menghindari rokok dan alkohol, mengelola stres, serta melakukan pemeriksaan kesehatan secara berkala untuk memantau tekanan darah, kadar gula, dan kolesterol. Sedangkan, aspek yang merupakan indikasi penyakit jantung adalah usia lanjut, jenis kelamin laki-laki, tekanan darah tinggi (trestbps), kadar kolesterol tinggi (chol), nyeri dada tipe tertentu (cp), penurunan segmen ST akibat stres (oldpeak), denyut jantung maksimum rendah (thalach), adanya angina saat beraktivitas (exang), jumlah pembuluh darah yang bermasalah (ca) dan kondisi thalassemia yang tidak normal (thal).
# Buat data
data <- data.frame(
Konsumsi_GWh = c(10,20,30,50,70,90,40,80,120,200,300,400,
15,25,35,50,70,5,10,15,20,25,30,40),
Biaya_per_kWh = c(1500,1450,1400,1350,1300,1250,1300,1250,
1200,1150,1100,1050,1600,1550,1500,1450,
1400,1700,1600,1550,1500,1450,1400,1350),
Konsumen = c(rep("Rumah Tangga", 6),
rep("Industri", 6),
rep("Kantor Pemerintah", 5),
rep("UMKM", 7))
)
# Plot pakai ggplot
ggplot(data, aes(x = Konsumsi_GWh, y = Biaya_per_kWh, color = Konsumen)) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Biaya Listrik per kWh Menurun Seiring Kenaikan Konsumsi",
x = "Total Konsumsi Listrik (GWh)",
y = "Biaya per kWh (Rp/kWh)",
color = "Konsumen") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Grafik tersebut menggambarkan hubungan terbalik antara total konsumsi listrik dengan biaya listrik per kWh untuk berbagai kategori konsumen, yaitu Industri, Kantor Pemerintah, Rumah Tangga, dan UMKM. Terlihat bahwa semakin tinggi total konsumsi listrik, maka biaya listrik semakin menurun untuk semua kategori konsumen. Namun, tingkat penurunan biaya per kWh terhadap peningkatan konsumsi berbeda-beda antar kategori konsumen, yang ditunjukkan oleh kemiringan garis tren yang berbeda, artinya terdapat struktur tarif yang berbeda berdasarkan volume konsumsi dan jenis konsumen.