df <- read.csv("C:/Users/ASUS/Documents/PSD/heart.csv")
head(df)
## age sex cp trestbps chol fbs restecg thalach exang oldpeak slope ca thal
## 1 63 1 3 145 233 1 0 150 0 2.3 0 0 1
## 2 37 1 2 130 250 0 1 187 0 3.5 0 0 2
## 3 41 0 1 130 204 0 0 172 0 1.4 2 0 2
## 4 56 1 1 120 236 0 1 178 0 0.8 2 0 2
## 5 57 0 0 120 354 0 1 163 1 0.6 2 0 2
## 6 57 1 0 140 192 0 1 148 0 0.4 1 0 1
## target
## 1 1
## 2 1
## 3 1
## 4 1
## 5 1
## 6 1
str(df)
## 'data.frame': 303 obs. of 14 variables:
## $ age : int 63 37 41 56 57 57 56 44 52 57 ...
## $ sex : int 1 1 0 1 0 1 0 1 1 1 ...
## $ cp : int 3 2 1 1 0 0 1 1 2 2 ...
## $ trestbps: int 145 130 130 120 120 140 140 120 172 150 ...
## $ chol : int 233 250 204 236 354 192 294 263 199 168 ...
## $ fbs : int 1 0 0 0 0 0 0 0 1 0 ...
## $ restecg : int 0 1 0 1 1 1 0 1 1 1 ...
## $ thalach : int 150 187 172 178 163 148 153 173 162 174 ...
## $ exang : int 0 0 0 0 1 0 0 0 0 0 ...
## $ oldpeak : num 2.3 3.5 1.4 0.8 0.6 0.4 1.3 0 0.5 1.6 ...
## $ slope : int 0 0 2 2 2 1 1 2 2 2 ...
## $ ca : int 0 0 0 0 0 0 0 0 0 0 ...
## $ thal : int 1 2 2 2 2 1 2 3 3 2 ...
## $ target : int 1 1 1 1 1 1 1 1 1 1 ...
# 1. Menghitung jumlah nilai kosong (NA) di setiap kolom untuk mendeteksi data yang hilang.
cat("Jumlah missing values per kolom:/n")
## Jumlah missing values per kolom:/n
colSums(is.na(df))
## 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
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
# 2. Memeriksa data yang tercatat ganda dan menangani
duplicate_rows <- df[duplicated(df), ]
cat("Jumlah baris duplikat:", nrow(duplicate_rows), "/n")
## Jumlah baris duplikat: 1 /n
# Menghapus duplikat
df_clean <- df[!duplicated(df), ]
# 3. Membuat fungsi untuk mendeteksi outlier menggunakan metode IQR, lalu diterapkan pada kolom numerik dan mencetak jumlah outlier pada masing-masing kolom.
# Fungsi deteksi outlier dengan IQR
detect_outliers <- function(x) {
Q1 <- quantile(x, 0.25, na.rm = TRUE)
Q3 <- quantile(x, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
sum(x < (Q1 - 1.5 * IQR) | x > (Q3 + 1.5 * IQR), na.rm = TRUE)
}
# Menerapkan fungsi pada kolom numerik
numeric_cols <- df_clean[, sapply(df_clean, is.numeric), drop = FALSE]
outlier_counts <- sapply(numeric_cols, detect_outliers)
# Menampilkan hasil
cat("\nJumlah outlier per kolom numerik:\n")
##
## Jumlah outlier per kolom numerik:
print(outlier_counts)
## age sex cp trestbps chol fbs restecg thalach
## 0 0 0 9 5 45 0 1
## exang oldpeak slope ca thal target
## 0 5 0 24 2 0
# 4. Analisis statistik deskriptif untuk variabel numerik
cat("/nStatistik deskriptif:/n")
## /nStatistik deskriptif:/n
summary(df_clean[, sapply(df_clean, is.numeric)])
## 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
# Tambah label kategorik untuk fbs dan target
df_clean <- df_clean %>%
mutate(
fbs_label = ifelse(fbs == 1, ">120 mg/dL", "<=120 mg/dL"),
target_label = ifelse(target == "Ya", "Heart Disease", "Tidak")
)
# Hitung jumlah berdasarkan kombinasi fbs dan target
fbs_heart_table <- df_clean %>%
group_by(fbs_label, target_label) %>%
summarise(jumlah = n(), .groups = 'drop')
# Tampilkan tabel
fbs_heart_table
## # A tibble: 4 × 3
## fbs_label target_label jumlah
## <chr> <chr> <int>
## 1 <=120 mg/dL Heart Disease 141
## 2 <=120 mg/dL Tidak 116
## 3 >120 mg/dL Heart Disease 23
## 4 >120 mg/dL Tidak 22
# Visualisasi
ggplot(fbs_heart_table, aes(x = fbs_label, y = jumlah, fill = target_label)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Perbandingan Heart Disease Berdasarkan Kadar Gula Darah",
x = "Kadar Gula Darah", y = "Jumlah",
fill = "Heart Disease") +
scale_fill_manual(values = c("yellow", "blue")) +
theme_minimal()
# Label untuk jenis nyeri dada (chest pain)
# 0 = Typical angina
# 1 = Atypical angina
# 2 = Non-anginal pain
# 3 = Asymptomatic
df_clean <- df_clean %>%
mutate(
cp_label = factor(cp,
levels = c(0, 1, 2, 3),
labels = c("Typical angina", "Atypical angina", "Non-anginal pain", "Asymptomatic"))
)
# Hitung jumlah masing-masing jenis nyeri dada pada penderita heart disease
chest_pain_count <- df_clean %>%
filter(target == "Ya") %>%
group_by(cp_label) %>%
summarise(jumlah = n(), .groups = 'drop') %>%
arrange(desc(jumlah))
# Tampilkan tabel
chest_pain_count
## # A tibble: 4 × 2
## cp_label jumlah
## <fct> <int>
## 1 Non-anginal pain 68
## 2 Atypical angina 41
## 3 Typical angina 39
## 4 Asymptomatic 16
# Visualisasi jenis nyeri dada pada penderita heart disease
ggplot(chest_pain_count, aes(x = reorder(cp_label, -jumlah), y = jumlah, fill = cp_label)) +
geom_bar(stat = "identity") +
labs(title = "Jenis Nyeri Dada pada Penderita Heart Disease",
x = "Jenis Nyeri Dada", y = "Jumlah") +
theme_minimal() +
theme(legend.position = "none")
library(ggplot2)
# Fungsi untuk membuat barplot proporsi
plot_proporsi <- function(var, title_var) {
ggplot(df_clean, aes_string(x = var, fill = "target")) +
geom_bar(position = "fill") +
scale_y_continuous(labels = function(x) paste0(round(x * 100, 1), "%")) + # manual persen
labs(title = paste("Proporsi Heart Disease berdasarkan", title_var),
x = title_var, y = "Proporsi", fill = "Heart Disease") +
scale_fill_manual(values = c("Tidak" = "skyblue", "Ya" = "lightyellow")) +
theme_minimal()
}
# Coba plot untuk 'cp' dan 'thal'
plot_proporsi("cp", "Chest Pain Type")
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
plot_proporsi("thal", "Thalassemia Type")
# Plot untuk cp, ca, dan thal
plot_proporsi("cp_label", "Jenis Nyeri Dada (cp)")
Berdasarkan visualisasi proporsi penyakit jantung berdasarkan variabel cp (jenis nyeri dada) mengungkapkan bahwa mayoritas penderita berada pada kategori Asymptomatic (tidak merasakan nyeri dada). Temuan ini mengindikasikan bahwa risiko penyakit jantung tetap tinggi meskipun seseorang tidak mengalami keluhan nyeri dada khas. Sebaliknya, individu yang merasakan Typical angina atau Atypical angina justru lebih banyak yang tidak terdiagnosis penyakit jantung, kemungkinan karena nyeri yang dirasakan bukan berasal dari jantung.
plot_proporsi("ca", "Jumlah Pembuluh yang Diwarnai (ca)")
Berdasarkan variabel ca (jumlah pembuluh darah utama yang terlihat melalui angiografi), terlihat bahwa proporsi penderita penyakit jantung cenderung lebih tinggi pada individu dengan ca = 0. Kondisi ini dapat mengindikasikan bahwa tidak tampaknya pembuluh darah utama mungkin disebabkan oleh adanya penyumbatan atau kerusakan serius, yang berkontribusi pada peningkatan risiko penyakit jantung. Sebaliknya, semakin banyak pembuluh darah yang terlihat (ca = 1 hingga 3), proporsi penderita jantung menurun, yang dapat mencerminkan kondisi pembuluh darah yang lebih sehat.
plot_proporsi("thal", "Hasil Tes Thalassemia (thal)")
Berdasarkan variabel thal (hasil tes thalassemia), terlihat bahwa kategori Reversible Defect memiliki proporsi tertinggi penderita penyakit jantung. Temuan ini mengindikasikan bahwa defek reversibel yang muncul saat dilakukan tes stres merupakan indikator kuat adanya gangguan pada jantung. Sebaliknya, pada kategori Normal, proporsi penderita jauh lebih rendah, yang menunjukkan bahwa hasil tes thal yang normal berkorelasi erat dengan kondisi jantung yang sehat.
# Scatter plot biasa hubungan age vs thalach
# Scatter plot dengan garis tren linier
ggplot(df_clean, aes(x = age, y = thalach, color = target)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE, color = "gray40", linewidth = 1) +
scale_color_manual(values = c("Tidak" = "lightgreen", "Ya" = "skyblue")) +
labs(title = "Hubungan antara Usia dan Denyut Jantung Maksimum (thalach)",
x = "Usia", y = "Thalach (detak jantung maksimum)",
color = "Heart Disease") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Untuk mengeksplorasi hubungan antara usia (age) dan denyut jantung maksimum (thalach), dilakukan visualisasi berupa scatter plot yang dilengkapi dengan garis tren linier. Hasil visualisasi menunjukkan adanya kecenderungan penurunan nilai thalach seiring bertambahnya usia, yang mengindikasikan adanya hubungan negatif antara kedua variabel tersebut. Analisis korelasi Pearson dilakukan untuk menguatkan temuan ini, dan menghasilkan nilai korelasi negatif, yang berarti semakin tinggi usia seseorang, semakin rendah denyut jantung maksimumnya. Selanjutnya, model regresi linier sederhana digunakan untuk memodelkan hubungan ini, dan hasilnya menunjukkan bahwa variabel usia memiliki koefisien negatif yang signifikan secara statistik. Hal ini menegaskan bahwa terdapat hubungan terbalik yang signifikan antara usia dan thalach pada data yang dianalisis.
library(reshape2)
## Warning: package 'reshape2' was built under R version 4.3.3
# Menghitung korelasi
cor_matrix <- cor(df_clean[sapply(df_clean, is.numeric)])
# Memuat library reshape2
library(reshape2)
# Mengubah matriks korelasi menjadi bentuk long untuk heatmap
cor_data <- melt(cor_matrix)
# Visualisasi heatmap korelasi
ggplot(cor_data, aes(x = Var1, y = Var2, fill = value)) +
geom_tile(color = "white") +
scale_fill_gradient2(low = "green", high = "orange", mid = "white",
midpoint = 0, limit = c(-1,1), space = "Lab",
name="Correlation") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 1,
size = 12, hjust = 1)) +
coord_fixed() +
ggtitle("Heatmap Korelasi Variabel Numerik")
Heatmap tersebut menggambarkan tingkat korelasi antar variabel numerik dalam dataset kesehatan jantung. Terlihat beberapa korelasi yang cukup mencolok, seperti hubungan negatif antara thalach (detak jantung maksimum) dengan age (usia), serta korelasi negatif antara slope dan oldpeak, yang menandakan hubungan terbalik yang cukup kuat di antara pasangan variabel tersebut. Selain itu, variabel cp (jenis nyeri dada) menunjukkan korelasi positif dengan thalach dan korelasi negatif dengan exang (angina yang dipicu oleh aktivitas fisik). Di sisi lain, variabel seperti fbs (kadar gula darah puasa) dan restecg (hasil elektrokardiogram saat istirahat) tampak memiliki korelasi yang lemah atau hampir tidak ada dengan variabel lainnya. Temuan ini mengindikasikan bahwa tidak semua variabel memberikan kontribusi yang signifikan, sehingga pemilihan fitur yang tepat menjadi penting dalam analisis atau pemodelan lebih lanjut.
Berdasarkan eksplorasi data kesehatan jantung yang dilakukan,
berikut ringkasan hasil analisis:
- Pembersihan Data: Tidak ditemukan data yang hilang, dan data duplikat
berhasil dihapus. Beberapa outlier terdeteksi, namun belum dihapus untuk
menjaga integritas data. - Jenis Kelamin: Penderita penyakit jantung
didominasi oleh laki-laki. - Usia: Rentang usia 50–60 tahun paling
banyak mengalami penyakit jantung dan menunjukkan kadar gula darah di
atas 120 mg/dL. - Kadar Gula Darah: Sebagian besar penderita justru
memiliki kadar gula ≤120 mg/dL, menunjukkan bahwa gula darah tinggi
bukan faktor dominan dalam dataset ini. -Jenis Nyeri Dada (cp): Kategori
Asymptomatic paling banyak dialami oleh penderita, menandakan bahwa
risiko tetap tinggi meski tanpa gejala nyeri dada yang khas. - Pembuluh
Darah (ca): Risiko penyakit jantung cenderung lebih tinggi pada individu
dengan ca = 0, kemungkinan karena tidak terdeteksinya pembuluh darah
utama akibat penyumbatan. - Thalassemia (thal): Kategori Reversible
Defect paling umum pada penderita penyakit jantung, menunjukkan indikasi
gangguan yang muncul saat tes stres. - Usia vs. Thalach: Terdapat
hubungan negatif yang jelas—semakin tua usia, semakin rendah denyut
jantung maksimum (thalach). - Korelasi Variabel (Heatmap):
Teridentifikasi korelasi signifikan, seperti hubungan negatif antara age
dan thalach, serta korelasi positif antara cp dan thalach.
Pencegahan Penyakit Jantung
Berdasarkan hasil di atas, beberapa langkah pencegahan yang dapat
diambil:
- Pemeriksaan Rutin: Lakukan pengecekan kesehatan secara berkala,
termasuk tes thalassemia dan angiografi pembuluh darah. - Olahraga
Teratur: Jaga kebugaran jantung agar thalach tetap optimal, terutama
pada usia lanjut. - Waspada Meski Tanpa Gejala: Risiko penyakit tetap
tinggi meski tanpa nyeri dada khas. - Pantau Kesehatan Secara
Menyeluruh: Meskipun kadar gula darah normal, tetap perhatikan tekanan
darah, kolesterol, dan gaya hidup. - Gaya Hidup Sehat: Kelola stres,
konsumsi makanan bergizi, dan hindari kebiasaan buruk untuk menjaga
kesehatan jantung.
Buat diagram yang sama dengan contoh. Serta jelaskan maksud setiap dari bagian sintax tersebut
# 1. Input 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))
)
# 2. Visualisasi dengan ggplot2 + garis regresi
library(ggplot2)
ggplot(data, aes(x = Konsumsi_GWh, y = Biaya_per_kWh, color = Konsumen)) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE, linewidth = 1) + # Tambahan garis linear per grup
labs(
title = "Hubungan Konsumsi Listrik dan Biaya per kWh",
x = "Konsumsi (GWh)",
y = "Biaya per kWh (Rp)"
) +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Penjelasan Sintaks:
- data.frame(…): Digunakan untuk membentuk sebuah tabel data dengan tiga
kolom utama, yaitu Konsumsi, Biaya, dan Jenis Konsumen. - rep(…):
Berfungsi untuk mengulang nilai nama jenis konsumen sesuai jumlah data
masing-masing kategori agar kolom Jenis Konsumen memiliki panjang yang
konsisten. - library(ggplot2): Memanggil package ggplot2 yang digunakan
untuk membuat berbagai bentuk visualisasi data di R. - ggplot(data,
aes(…)): Membuat objek awal untuk visualisasi dengan mendefinisikan
estetika grafik, yaitu: x = Konsumsi_GWh: Menentukan sumbu horizontal
sebagai konsumsi energi dalam GWh. y = Biaya_per_kWh: Menentukan sumbu
vertikal sebagai biaya listrik per kWh. color = Konsumen: Memberikan
warna yang berbeda untuk tiap jenis konsumen. - geom_point(size = 3):
Menampilkan data dalam bentuk titik-titik pada plot, dengan ukuran titik
diset ke 3 agar lebih jelas terlihat. - labs(…): Menambahkan elemen
deskriptif pada grafik, seperti judul grafik dan label sumbu x dan y. -
theme_minimal(): Menggunakan tema visual yang bersih dan sederhana untuk
meningkatkan keterbacaan grafik. - geom_smooth(method = “lm”, se =
FALSE): Menambahkan garis tren regresi linier untuk menunjukkan arah
hubungan antara konsumsi dan biaya, tanpa menampilkan area deviasi
standarnya.
Interpretasi
Visualisasi yang menunjukkan hubungan antara konsumsi listrik (dalam
GWh) dan biaya per kWh di berbagai jenis konsumen mengungkap pola yang
konsisten: semakin tinggi konsumsi listrik, semakin rendah biaya per kWh
yang dibayarkan. Pada segmen rumah tangga, pelanggan dengan konsumsi
besar cenderung menikmati tarif listrik yang lebih murah dibandingkan
pelanggan dengan konsumsi rendah. Pola yang serupa juga terlihat pada
sektor industri, di mana konsumen industri berskala besar mendapatkan
tarif lebih rendah, kemungkinan karena adanya kebijakan tarif khusus
atau insentif dari pemerintah untuk mendorong efisiensi energi dan
peningkatan produksi. Segmen kantor pemerintahan memperlihatkan tren
yang sejalan, meskipun data yang tersedia lebih terbatas sehingga
analisis lebih lanjut perlu dilakukan dengan hati-hati. Di sisi lain,
pada UMKM, tarif listrik per kWh juga tampak menurun seiring dengan
meningkatnya konsumsi, yang mungkin mencerminkan adanya dukungan tarif
bagi usaha kecil. Secara umum, terdapat korelasi negatif antara jumlah
konsumsi dan tarif per kWh di seluruh segmen konsumen, menunjukkan
penerapan kebijakan tarif berbasis volume konsumsi. Meskipun strategi
ini memberikan keuntungan bagi konsumen dengan konsumsi besar, penting
untuk mempertimbangkan dampaknya terhadap efisiensi energi dan keadilan
tarif antar kelompok pengguna.