data <- read.csv("C:/Users/PC-MS/OneDrive/Documents/PSD/heart.csv")
str(data)
## '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 ...
summary(data)
## age sex cp trestbps
## Min. :29.00 Min. :0.0000 Min. :0.000 Min. : 94.0
## 1st Qu.:47.50 1st Qu.:0.0000 1st Qu.:0.000 1st Qu.:120.0
## Median :55.00 Median :1.0000 Median :1.000 Median :130.0
## Mean :54.37 Mean :0.6832 Mean :0.967 Mean :131.6
## 3rd Qu.:61.00 3rd Qu.:1.0000 3rd Qu.:2.000 3rd Qu.:140.0
## Max. :77.00 Max. :1.0000 Max. :3.000 Max. :200.0
## chol fbs restecg thalach
## Min. :126.0 Min. :0.0000 Min. :0.0000 Min. : 71.0
## 1st Qu.:211.0 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:133.5
## Median :240.0 Median :0.0000 Median :1.0000 Median :153.0
## Mean :246.3 Mean :0.1485 Mean :0.5281 Mean :149.6
## 3rd Qu.:274.5 3rd Qu.:0.0000 3rd Qu.:1.0000 3rd Qu.:166.0
## Max. :564.0 Max. :1.0000 Max. :2.0000 Max. :202.0
## exang oldpeak slope ca
## Min. :0.0000 Min. :0.00 Min. :0.000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.00 1st Qu.:1.000 1st Qu.:0.0000
## Median :0.0000 Median :0.80 Median :1.000 Median :0.0000
## Mean :0.3267 Mean :1.04 Mean :1.399 Mean :0.7294
## 3rd Qu.:1.0000 3rd Qu.:1.60 3rd Qu.:2.000 3rd Qu.:1.0000
## Max. :1.0000 Max. :6.20 Max. :2.000 Max. :4.0000
## thal target
## Min. :0.000 Min. :0.0000
## 1st Qu.:2.000 1st Qu.:0.0000
## Median :2.000 Median :1.0000
## Mean :2.314 Mean :0.5446
## 3rd Qu.:3.000 3rd Qu.:1.0000
## Max. :3.000 Max. :1.0000
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
sum(duplicated(data))
## [1] 1
data <- data[!duplicated(data), ]
check_outliers <- function(x) {
Q1 <- quantile(x, 0.25)
Q3 <- quantile(x, 0.75)
IQR <- Q3 - Q1
lower <- Q1 - 1.5 * IQR
upper <- Q3 + 1.5 * IQR
sum(x < lower | x > upper)
}
sapply(data[, sapply(data, is.numeric)], check_outliers)
## 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
summary(data[, sapply(data, 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
Interpretasi 1a:
Data tidak memiliki nilai kosong (NA). Terdapat beberapa baris duplikat
yang berhasil dihapus. Beberapa kolom numerik memiliki nilai ekstrim
(outlier), namun karena konteks medis, outlier dianggap relevan dan
tetap disertakan dalam analisis.
Mengapa Menggunakan Penanganan in== - Duplikat dihapus karena bisa
menyebabkan bias (pengulangan observasi yang sama).
- Outlier tidak dihapus karena dalam data medis, nilai ekstrem bisa
mencerminkan kondisi nyata pasien (misalnya pasien kritis atau tekanan
darah ekstrem).
- Karena tidak ada missing values, tidak dilakukan imputasi atau
penghapusan baris. Data tidak memiliki nilai kosong (NA). Terdapat
beberapa baris duplikat yang berhasil dihapus. Beberapa kolom numerik
memiliki nilai ekstrim (outlier), namun karena konteks medis, outlier
dianggap relevan dan tetap disertakan dalam analisis.
data$sex <- factor(data$sex, labels = c("Female", "Male"))
ggplot(data, aes(x=sex, fill=factor(target))) +
geom_bar(position="dodge", color="black") +
labs(title="Heart Disease by Sex", fill="Heart Disease")
ggplot(data[data$target == 1, ], aes(x=age)) +
geom_histogram(binwidth=5, fill="salmon", color="black") +
labs(title="Age Distribution - With Heart Disease")
ggplot(data[data$fbs == 1, ], aes(x=age)) +
geom_histogram(binwidth=5, fill="orange", color="black") +
labs(title="Age with Fasting Blood Sugar > 120")
Interpretasi 1b:
Laki-laki lebih banyak menderita penyakit jantung. Rentang usia 50–60
tahun merupakan yang paling sering terdiagnosis. Gula darah tinggi
(>120 mg/dl) paling banyak ditemukan pada usia 55–65 tahun.
table_fbs <- table(data$fbs, data$target)
prop.table(table_fbs, 1) * 100
##
## 0 1
## 0 45.13619 54.86381
## 1 48.88889 51.11111
data$fbs <- factor(data$fbs, labels = c("<= 120", "> 120"))
ggplot(data, aes(x=fbs, fill=factor(target))) +
geom_bar(position="fill", color="black") +
scale_y_continuous(labels=scales::percent) +
labs(title="Heart Disease by Fasting Blood Sugar", y="Proportion", fill="Heart Disease")
Interpretasi 1c:
Hasil visualisasi menunjukkan bahwa penderita dengan kadar gula darah
lebih dari 120 mg/dL memiliki proporsi penyakit jantung yang lebih
tinggi dibandingkan dengan kelompok kadar gula darah normal. Meskipun
perbedaannya tidak terlalu mencolok, temuan ini tetap menguatkan bahwa
kadar gula darah merupakan salah satu indikator yang perlu diperhatikan
dalam mengidentifikasi risiko penyakit jantung.
ggplot(data[data$target == 1, ], aes(x=factor(cp))) +
geom_bar(fill="steelblue", color="black") +
labs(title="Chest Pain Type among Heart Disease Patients", x="Chest Pain Type")
Interpretasi 1d:
Grafik menunjukkan distribusi jenis nyeri dada (chest pain type) pada
pasien yang menderita penyakit jantung (target == 1). Dari hasil
visualisasi, tipe nyeri dada yang paling sering dialami oleh penderita
penyakit jantung adalah tipe 0 dan tipe 2. Ini menunjukkan bahwa tipe
nyeri dada tertentu (terutama tipe 0 = typical angina dan tipe 2 =
non-anginal pain) dapat menjadi gejala umum atau indikator awal penyakit
jantung.
cat_vars <- c("cp", "ca", "thal")
for (var in cat_vars) {
print(
ggplot(data, aes_string(x=var, fill="factor(target)")) +
geom_bar(position="fill", color="black") +
scale_y_continuous(labels=scales::percent) +
labs(title=paste("Heart Disease Proportion by", var), fill="Heart Disease") +
theme_minimal()
)
}
## 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.
Interpretasi 1e:
Variabel cp, ca, dan thal
menunjukkan perbedaan proporsi signifikan antara penderita dan
non-penderita. Ini menunjukkan bahwa ketiganya penting dalam prediksi
penyakit jantung.
# Ubah label target jadi faktor dengan nama yang jelas
data$target <- factor(data$target, labels = c("Sehat", "Sakit"))
# Plot hubungan antara age dan thalach berdasarkan status penyakit
ggplot(data, aes(x = age, y = thalach, color = target)) +
geom_point(shape = 21, fill = "white", color = "black") +
geom_smooth(method = "loess", se = FALSE) +
labs(
title = "Hubungan Usia dan Detak Jantung Maksimum",
x = "Usia",
y = "Thalach (Detak Jantung Maksimum)",
color = "Status"
)
## `geom_smooth()` using formula = 'y ~ x'
Interpretasi 1f:
Plot menunjukkan hubungan antara usia dan detak jantung maksimum
(thalach) berdasarkan status kesehatan (target). Secara umum, terlihat
bahwa detak jantung maksimum cenderung menurun seiring bertambahnya
usia, baik pada penderita penyakit jantung maupun individu yang sehat.
Namun, penderita penyakit jantung cenderung memiliki nilai thalach yang
lebih rendah dibandingkan kelompok sehat pada rentang usia yang sama.
Pola ini menunjukkan bahwa detak jantung maksimum yang lebih rendah bisa
menjadi indikasi adanya penyakit jantung, terutama pada usia lanjut.
num_df <- data %>% select_if(is.numeric)
corr <- round(cor(num_df), 2)
ggcorrplot(corr,
hc.order = TRUE,
type = "lower",
lab = TRUE,
lab_size = 3, # Ukuran label diperkecil
colors = c("blue", "white", "red"))
Interpretasi 1g:
Plot korelasi menunjukkan hubungan antar variabel numerik dalam data.
Warna merah mengindikasikan korelasi positif, sedangkan biru menunjukkan
korelasi negatif,semakin kuat warnanya, semakin kuat hubungannya. Dari
plot terlihat bahwa beberapa variabel memiliki hubungan yang cukup kuat,
baik positif maupun negatif. Contohnya, thalach cenderung berkorelasi
negatif dengan age, artinya semakin tua usia, detak jantung maksimum
biasanya semakin rendah. Korelasi semacam ini bisa membantu dalam
memahami pola data dan memilih variabel penting untuk analisis lebih
lanjut.
# 1h. Summary Analisis
Insight:
Pencegahan:
### **2. Melakukan Visualisasi menggunakan data**
# 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(…): Membuat tabel data dengan tiga kolom: Konsumsi, Biaya,
dan Jenis Konsumen.
- rep(…): Mengulang nama jenis konsumen sesuai banyaknya data
masing-masing kategori.
- library(ggplot2): Memanggil package ggplot2 untuk visualisasi.
- ggplot(data, aes(…)): Membuat objek grafik dari data dengan estetika
dasar: x = Konsumsi_GWh: sumbu x adalah konsumsi energi. y =
Biaya_per_kWh: sumbu y adalah biaya.
- color = Konsumen: membedakan warna berdasarkan jenis konsumen.
- geom_point(size = 3): Membuat titik-titik berukuran 3.
- labs(…): Menambahkan judul dan label sumbu.
- theme_minimal(): Menggunakan tema bersih dan minimal.
- geom_smooth(method = “lm”, se = FALSE): Menambahkan garis regresi
linear tanpa area standar deviasi.
Interpretasi
-Grafik hubungan antara konsumsi listrik (GWh) dan biaya per kWh pada
berbagai kelompok konsumen menunjukkan pola yang konsisten, di mana
peningkatan konsumsi listrik umumnya diikuti oleh penurunan tarif per
kWh.
-Pada segmen rumah tangga, konsumen dengan tingkat pemakaian listrik yang lebih tinggi cenderung mendapatkan tarif per kWh yang lebih rendah dibandingkan mereka yang konsumsi listriknya lebih sedikit.
-Pola serupa juga tampak pada sektor industri, di mana perusahaan dengan konsumsi listrik besar biasanya menikmati tarif yang lebih rendah. Kondisi ini bisa menjadi indikasi adanya kebijakan tarif khusus atau insentif yang ditujukan untuk mendukung kegiatan produksi dan efisiensi di sektor industri.
-Segmen kantor pemerintahan memperlihatkan kecenderungan yang sejalan, walaupun jumlah data pada kelompok ini relatif lebih sedikit, sehingga interpretasi hasilnya perlu dilakukan dengan hati-hati.
-Di sisi lain, UMKM juga menunjukkan pola bahwa semakin besar konsumsi listrik, semakin rendah biaya per kWh yang dikeluarkan. Hal ini bisa mencerminkan adanya kebijakan dukungan tarif bagi pelaku usaha skala kecil.
-Secara keseluruhan, visualisasi ini menunjukkan hubungan negatif antara konsumsi listrik dan tarif per kWh di seluruh segmen konsumen, yang merefleksikan penerapan skema tarif berbasis volume pemakaian. Meski sistem ini memberikan keuntungan bagi konsumen dengan penggunaan besar, dampak terhadap efisiensi energi dan keadilan antar kelompok pengguna tetap menjadi pertimbangan penting. ```