Package
library(tidyverse) # ggplot and dplyr
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.0 ✔ purrr 0.3.5
## ✔ tibble 3.1.8 ✔ dplyr 1.0.10
## ✔ tidyr 1.2.1 ✔ stringr 1.4.1
## ✔ readr 2.1.3 ✔ forcats 0.5.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(mlbench) # data pima Indian Dataset
library(cowplot) # menampilkan plot dalam bentuk Grid
library(caret) # features scaling
## Loading required package: lattice
##
## Attaching package: 'caret'
##
## The following object is masked from 'package:purrr':
##
## lift
Pemeriksaan Data
data(PimaIndiansDiabetes)
diabetes <- PimaIndiansDiabetes
str(diabetes)
## 'data.frame': 768 obs. of 9 variables:
## $ pregnant: num 6 1 8 1 0 5 3 10 2 8 ...
## $ glucose : num 148 85 183 89 137 116 78 115 197 125 ...
## $ pressure: num 72 66 64 66 40 74 50 0 70 96 ...
## $ triceps : num 35 29 0 23 35 0 32 0 45 0 ...
## $ insulin : num 0 0 0 94 168 0 88 0 543 0 ...
## $ mass : num 33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 0 ...
## $ pedigree: num 0.627 0.351 0.672 0.167 2.288 ...
## $ age : num 50 31 32 21 33 30 26 29 53 54 ...
## $ diabetes: Factor w/ 2 levels "neg","pos": 2 1 2 1 2 1 2 1 2 2 ...
head(diabetes)
Ringkasan dan Sebaran Data
summary(diabetes)
## pregnant glucose pressure triceps
## Min. : 0.000 Min. : 0.0 Min. : 0.00 Min. : 0.00
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 62.00 1st Qu.: 0.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :23.00
## Mean : 3.845 Mean :120.9 Mean : 69.11 Mean :20.54
## 3rd Qu.: 6.000 3rd Qu.:140.2 3rd Qu.: 80.00 3rd Qu.:32.00
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.00
## insulin mass pedigree age diabetes
## Min. : 0.0 Min. : 0.00 Min. :0.0780 Min. :21.00 neg:500
## 1st Qu.: 0.0 1st Qu.:27.30 1st Qu.:0.2437 1st Qu.:24.00 pos:268
## Median : 30.5 Median :32.00 Median :0.3725 Median :29.00
## Mean : 79.8 Mean :31.99 Mean :0.4719 Mean :33.24
## 3rd Qu.:127.2 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.0 Max. :67.10 Max. :2.4200 Max. :81.00
Jumlah NA
colSums(is.na(diabetes))
## pregnant glucose pressure triceps insulin mass pedigree age
## 0 0 0 0 0 0 0 0
## diabetes
## 0
Jumlah Nilai 0
colSums(diabetes==0)
## pregnant glucose pressure triceps insulin mass pedigree age
## 111 5 35 227 374 11 0 0
## diabetes
## 0
Persentase Nilai 0
round(colSums(diabetes==0)/length(diabetes$diabetes), 4)*100
## pregnant glucose pressure triceps insulin mass pedigree age
## 14.45 0.65 4.56 29.56 48.70 1.43 0.00 0.00
## diabetes
## 0.00
Dari Summary di atas, terlihat tidak terdapat data NA, namun terlihat banyak kolom memiliki nilai 0 yang seharusnya tidak mungkin 0. Seperti glucose yang menunjukkan kadar gula atau pressure yang menunjukkan tekanan darah, serta kolom lainnya.
Kondisi ini perlu ditangani karena merupakan informasi yang keliru.
plots <- lapply(names(diabetes), function(var_x){
p <-
ggplot(diabetes) +
aes_string(var_x)
if(is.numeric(diabetes[[var_x]])) {
p <- p + geom_density(lwd=1, color="darkgreen")
} else {
p <- p + geom_bar(fill="darkred")
}
})
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation ideoms with `aes()`
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
plot_grid(plotlist = plots)
Masing-masing kolom memiliki sebaran yang bervariasi ada yang relatif simetris ada pula yang menjulur. Secara umum dalam konteks prediksi hal ini tidak terlalu menjadi masalah. Pengecekan penting untuk penanganan data hilang atau outlier.
Kolom pregnant
# Histogram Data Kolom Pregnant
pl1 <- ggplot(diabetes, aes(x=pregnant))
pl1 <- pl1 +
geom_bar(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pregnant
pl2 <- ggplot(diabetes, aes(y=pregnant))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=pregnant))
# Boxplot Kolom Pregnant menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## Warning: The dot-dot notation (`..count..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(count)` instead.
summary(diabetes$pregnant)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 1.000 3.000 3.845 6.000 17.000
Sebaran nilai pregnant cenderung menjulur jauh ke kanan.
Menurut visualisasi boxplot, terdapat beberapa data outlier namun secara umum masih dalam batas yang wajar. Apalagi jika melihat boxplot antara pregnant dan diabetes sebaran data relatif cukup baik.
Namun jika ingin dilakukan penanganan maka terdapat beberapa alternatif:
- Menghapus data Outlier
- Mengganti data dengan mean/ median data yang tidak outlier
- Flooring & Capping Mengganti data dengan nilai max teoritis (Misal Q1 - 1.5xIQR dan Q3 + 1.5xIQR)
Menghapus Data Outlier
Melihat dari boxplot tunggal, terdapat 3 titik data outlier, sedangkan jika melihat berdasarkan kelompok diabetes atau tidakmaka terdapat dua outlier pada kelompok tidak diabetes. Misalkan kita menggunakan indikator dari boxplot tunggal, maka untuk menghapus data tersebut:
# Cari batas nilai maksimum (Q3 + 1.5*IQR)
q1 <- quantile(diabetes$pregnant, probs=0.25, names=F)
q3 <- quantile(diabetes$pregnant, probs=0.75, names=F)
IQR <- q3 - q1
max <- q3 + 1.5*IQR
# Hapus data yang lebih besar dari max
# R base
# diabetes <- diabetes[diabetes$pregnant <= max]
# dplyr
#diabetes <- diabetes %>% filter(pregnant <= max)
Mengganti dengan mean/median dari data yang tidak outlier
non.outlier <- diabetes[diabetes$pregnant <= max, "pregnant"]
mean.non <- mean(non.outlier)
med.non <- median(non.outlier)
# Update outlier data menggunakan mean atau median
# R base
diabetes$pregnant <- ifelse(diabetes$pregnant > max, med.non, diabetes$pregnant)
# dplyr
# diabetes <- diabetes %>% mutate(pregnant = ifelse(pregnant > max, med.non, pregnant))
Mengganti dengan nilai max
Sama seperti sebelumnya, cukup mengganti nilai outlier dengan nilai minimum/maksimum
# Update outlier data menggunakan nilai max
# R base
#diabetes$pregnant <- ifelse(diabetes$pregnant > max, max, diabetes$pregnant)
# dplyr
# diabetes <- diabetes %>% mutate(pregnant = ifelse(pregnant > max, max, pregnant))
Plot Setelah Modifikasi
pl2 <- ggplot(diabetes, aes(y=pregnant))
pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
Kolom glucose
summary(diabetes$glucose)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0 99.0 117.0 120.9 140.2 199.0
# Histogram Data Kolom glucose
pl1 <- ggplot(diabetes, aes(x=glucose))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom glucose
pl2 <- ggplot(diabetes, aes(y=glucose))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=glucose))
# Boxplot Kolom glucose menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Pada kolom ini sebaran data relatif simetris, dan secara umum tidak terdapat data outlier kecuali pada data bernilai 0.
Nilai Glucose menunjukkan kadar gula dalam darah, sehingga tidak mungkin bernilai 0. Perlu dicek juga apakah terdapat nilai-nilai lainnya yang tidak masuk akal (misalkan menurut Dokter).Namun pada contoh ini kita hanya akan fokus pada nilai 0 saja, kita anggap nilai lainnya masih masuk dalam rentang nilai yang memungkinkan.
Cek jumlah data bernilai 0:
length(which(diabetes$glucose == 0))
## [1] 5
Terdapat 5 data yang memiliki nilai glucose = 0 yang perlu ditangani. Jumlah ini relatif sedikit jadi dapat saja kita hapus 5 baris ini atau alternatif lain kita imputasi misal dengan mean atau median.
Menghapus Data
# Hapus data dengan nilai glucose = 0
# R base
# diabetes <- diabetes[diabetes$glucose > 0]
# dplyr
#diabetes <- diabetes %>% filter(glucose > 0)
Mengganti dengan Nilai Mean atau Median
Perlu diperhatikan, karena data bernilai 0 (bulan NA) maka perlu berhati-hati khususnya dalam menghitung mean.
Jika data bernilai NA, penghitungan mean dapat langsung dilakukan pada seluruh data, karena nilai NA akan diabaikan. Namun jika data bernilai 0 maka nilai tersebut akan dimasukkan dalam perhitungan rata-rata. Oleh karena itu perlu difilter terlebih dahulu data yang tidak bernilai 0.
Pemilihan mean biasanya untuk data yang memiliki sebaran relatif simetris, sementara untuk data dengan sebaran yang menjulur dapat menggunakan nilai median.
Melihat dari boxplot, tampak terdapat perbedaan sebaran nilai glucose antara yang terkena diabetes dan yang tidak. Penderita Diabetes cenderung memiliki nilai glucose yang lebih tinggi dibandingkan yang bukan penderita diabetes.
Opsi yang cocok adalah menggunakan mean atau median per kelompok. Data glucose 0 pada kelompok diabetes diganti dengan mean atau median pada kelompok tersebut begitu pula sebaliknya.
# Mengambil data glucose yang tidak bernilai 0
glucose.pos <- diabetes[(diabetes$glucose != 0) & (diabetes$diabetes == "pos"), "glucose"]
glucose.neg <- diabetes[(diabetes$glucose != 0) & (diabetes$diabetes == "neg"), "glucose"]
# Menghitung mean glucose masing-masing kelompok
med.gluc.pos <- median(glucose.pos)
med.gluc.neg <- median(glucose.neg)
# Mengganti nilai 0 dengan mean
# R base
diabetes$glucose <- ifelse(diabetes$glucose == 0,
ifelse(diabetes$diabetes == "pos", med.gluc.pos, med.gluc.neg),
diabetes$glucose)
# dplyr
# diabetes <- diabetes %>% mutate(glucose = ifelse(glucose == 0,
# ifelse(diabetes=="pos", med.gluc.pos, med.gluc.neg),
# glucose))
Plot Setelah Imputasi
# Histogram Data Kolom glucose
pl1 <- ggplot(diabetes, aes(x=glucose))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom glucose
pl2 <- ggplot(diabetes, aes(y=glucose))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=glucose))
# Boxplot Kolom glucose menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
summary(diabetes$glucose)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 44.00 99.75 117.00 121.68 140.25 199.00
Kolom pressure
Kolom pressure berisi data tekanan darah juga terdapat nilai 0 yang seharusnya tidak mungkin.
Selain itu juga terdapat nilai-nilai outlier baik di kedua sisi.
summary(diabetes$pressure)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 62.00 72.00 69.11 80.00 122.00
# Histogram Data Kolom Pressure
pl1 <- ggplot(diabetes, aes(x=pressure))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pressure
pl2 <- ggplot(diabetes, aes(y=pressure))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=pressure))
# Boxplot Kolom Pressure menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Cek jumlah data bernilai 0:
length(which(diabetes$pressure == 0))
## [1] 35
zero.pressure <- diabetes %>%
filter(pressure == 0) %>%
group_by(diabetes) %>%
summarise(count = length(pressure))
zero.pressure
Terdapat 35 data dengan nilai pressure = 0. Untuk kelompok Penderita diabetes terdapat 16 data bernilai 0 sedangkan untuk kelompok bukan penderita diabetes terdapat 19 data bernilai 0. Melihat dari boxplot kelompok, tampaknya tidak terdapat perbedaan yang berarti antara sebaran nilai pressure pada kelompok diabetes maupun tidak. Oleh karena itu kita mungkin cukup menggunakan mean data keseluruhan (yang tidak bernilai 0) untuk imputasi data 0.
Pada data pressure terindikasi terdapat beberapa amatan outlier, dapat pula dilakukan penanganan seperti pada bagian sebelumnya (pregnant). Namun di sini tidak akan kita lakukan penanganan. (Silahkan yang ingin mencoba)
Mengganti Nilai 0 dengan nilai Mean
# Mengambil data pressure yang tidak bernilai 0
pressure <- diabetes[diabetes$glucose != 0, "pressure"]
# Menghitung mean pressure
mean.pressure <- mean(pressure)
# Mengganti nilai 0 dengan mean
# R base
diabetes$pressure <- ifelse(diabetes$pressure == 0, mean.pressure, diabetes$pressure)
# dplyr
# diabetes <- diabetes %>% mutate(pressure = ifelse(pressure == 0, mean.pressure, pressure))
Plot Setelah Imputasi
# Histogram Data Kolom Pressure
pl1 <- ggplot(diabetes, aes(x=pressure))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pressure
pl2 <- ggplot(diabetes, aes(y=pressure))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=pressure))
# Boxplot Kolom Pressure menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Kolom tricepts
Kolom tricepts menunjukkan ketebalan lipatan kulit tricepts (mm). Data ini juga seharusnya tidak dapat bernilai 0.
summary(diabetes$triceps)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 0.00 23.00 20.54 32.00 99.00
# Histogram Data Kolom Pressure
pl1 <- ggplot(diabetes, aes(x=triceps))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pressure
pl2 <- ggplot(diabetes, aes(y=triceps))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=triceps))
# Boxplot Kolom Pressure menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
length(which(diabetes$triceps == 0))
## [1] 227
length(which(diabetes$triceps == 0))/length(diabetes$triceps)
## [1] 0.2955729
Jumlah data bernilai 0 untuk kolom tricepts cukup besar yaitu Sekitar 30%. Kita dapat saja melakukan imputasi seperti kolom sebelumnya. Namun jika dirasa terlalu banyak data yang diimputasi mungkin sebaiknya kolom ini dapat dibuang dari model.
# Menghapus kolom triceps
diabetes$triceps <- NULL
Kolom insulin
Sama seperti kolom tricepts, kolom insulin juga tidak mungkin bernilai 0. Namun pada data terdapat nilai 0 yang sangat banyak bahkan hampir 50%. Oleh karena itu penanganan yang paling tepat adalah membuang kolom tersebut dari model.
length(which(diabetes$insulin == 0))
## [1] 374
length(which(diabetes$insulin == 0))/length(diabetes$insulin)
## [1] 0.4869792
# Menghapus kolom insulin
diabetes$insulin <- NULL
Kolom mass
Kolom mass menunjukkan nilai BMI
summary(diabetes$mass)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 27.30 32.00 31.99 36.60 67.10
# Histogram Data Kolom Pressure
pl1 <- ggplot(diabetes, aes(x=mass))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pressure
pl2 <- ggplot(diabetes, aes(y=mass))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=mass))
# Boxplot Kolom Pressure menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
length(which(diabetes$mass == 0))
## [1] 11
length(which(diabetes$mass == 0))/length(diabetes$mass)
## [1] 0.01432292
Mengganti Nilai 0 dengan nilai Mean
# Mengambil data mass yang tidak bernilai 0
mass <- diabetes[diabetes$mass != 0, "mass"]
# Menghitung mean mass
mean.mass <- mean(mass)
# Mengganti nilai 0 dengan mean
# R base
diabetes$mass <- ifelse(diabetes$mass == 0, mean.mass, diabetes$mass)
# dplyr
# diabetes <- diabetes %>% mutate(mass = ifelse(mass == 0, mean.mass, mass))
Mengganti Nilai Data Outlier
Dalam contoh ini, anggap saja nilai BMI di atas (Q3 + 1.5 IQR) merupakan nilai yang tidak masuk akal. Maka kita dapat menghapus amatan dengan mass > 50 atau mengganti dengan nilai (Q3 + 1.5 IQR)
q1 <- quantile(diabetes$mass, probs=0.25, names=F)
q3 <- quantile(diabetes$mass, probs=0.75, names=F)
IQR <- q3 - q1
max <- q3 + 1.5*IQR
# R base
diabetes$mass <- ifelse(diabetes$mass > max, max, diabetes$mass)
# dplyr
# diabetes <- diabetes %>% mutate(mass = ifelse(mass > max, max, mass))
Kolom pedigree
summary(diabetes$pedigree)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0780 0.2437 0.3725 0.4719 0.6262 2.4200
# Histogram Data Kolom Pressure
pl1 <- ggplot(diabetes, aes(x=pedigree))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pressure
pl2 <- ggplot(diabetes, aes(y=pedigree))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=pedigree))
# Boxplot Kolom Pressure menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
length(which(diabetes$pedigree == 0))
## [1] 0
Untuk melakukan penanganan outlier dapat menggunakan cara seperti sebelumnya. Namun pada contoh ini akan kita biarkan, karena nilai-nilai nya masih masuk dalam rentang nilai yang memungkinkan.
Kolom age
summary(diabetes$age)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 21.00 24.00 29.00 33.24 41.00 81.00
# Histogram Data Kolom Pressure
pl1 <- ggplot(diabetes, aes(x=age))
pl1 <- pl1 +
geom_histogram(fill="red", alpha = 0.6, aes(fill=..count..))
# Boxplot Kolom Pressure
pl2 <- ggplot(diabetes, aes(y=age))
pl2 <- pl2 +
geom_boxplot(fill="red", alpha=0.6) + coord_flip() + theme_classic()
pl3 <- ggplot(diabetes, aes(x=diabetes, y=age))
# Boxplot Kolom Pressure menurut kondisi diabetes
pl3 <- pl3 +
geom_boxplot(aes(fill=diabetes)) + coord_flip() + theme_classic()
plot_grid(plotlist = list(pl1, pl2, pl3))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Tidak terdapat data yang aneh pada kolom age sehingga dapat kita biarkan apa adanya.
Features Scaling
Features Scaling adalah proses pengubahan skala pada peubah-peubah sehingga memiliki skala yang sama. Banyak algoritma machine learning, terutama yang berbasis jarak ataupun Neural Network akan bekerja lebih optimal jika skala setiap fitur sama.
Selain itu, dalam kasus model regresi, pada skala data yang sama, semakin besar nilai koefisiennya (mutlak) maka semakin besar pengaruhnya terhadap model.
feaures Scaling tidak merubah pola hubungan antara peubah tersebut dengan peubah respon.
Contoh features scaling: 1. Standardize : mengubah setiap fitur menjadi distribusi dengan mean 0 dan varians 1 dengan formula \[x_{i \;scaled}=\frac{x_i-\bar{x}}{s}\]
- Normalize : mengubah setiap fitur sehinggga memiliki nilai pada rentang [0 - 1] dengan formula \[x_{i\;scaled}=\frac{x_i - min(x)}{max(x)-min(x)}\]
Contoh menggunakan library caret:
Standardize
summary(diabetes[,1:6])
## pregnant glucose pressure mass
## Min. : 0.000 Min. : 44.00 Min. : 24.00 Min. :18.20
## 1st Qu.: 1.000 1st Qu.: 99.75 1st Qu.: 64.00 1st Qu.:27.50
## Median : 3.000 Median :117.00 Median : 72.00 Median :32.40
## Mean : 3.783 Mean :121.68 Mean : 72.25 Mean :32.40
## 3rd Qu.: 6.000 3rd Qu.:140.25 3rd Qu.: 80.00 3rd Qu.:36.60
## Max. :13.000 Max. :199.00 Max. :122.00 Max. :50.25
## pedigree age
## Min. :0.0780 Min. :21.00
## 1st Qu.:0.2437 1st Qu.:24.00
## Median :0.3725 Median :29.00
## Mean :0.4719 Mean :33.24
## 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :2.4200 Max. :81.00
sapply(diabetes[,1:6], sd)
## pregnant glucose pressure mass pedigree age
## 3.2706442 30.4641606 12.1159316 6.6674658 0.3313286 11.7602315
# Standardisasi Fitur
preprocessParams <- preProcess(diabetes[,1:6], method=c("center", "scale"))
standardized <- predict(preprocessParams, diabetes[,1:6])
summary(standardized)
## pregnant glucose pressure mass
## Min. :-1.1565 Min. :-2.5498 Min. :-3.98276 Min. :-2.1290870
## 1st Qu.:-0.8508 1st Qu.:-0.7198 1st Qu.:-0.68132 1st Qu.:-0.7342542
## Median :-0.2393 Median :-0.1535 Median :-0.02103 Median : 0.0006577
## Mean : 0.0000 Mean : 0.0000 Mean : 0.00000 Mean : 0.0000000
## 3rd Qu.: 0.6780 3rd Qu.: 0.6097 3rd Qu.: 0.63926 3rd Qu.: 0.6305822
## Max. : 2.8182 Max. : 2.5382 Max. : 4.10577 Max. : 2.6778368
## pedigree age
## Min. :-1.1888 Min. :-1.0409
## 1st Qu.:-0.6885 1st Qu.:-0.7858
## Median :-0.2999 Median :-0.3606
## Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.4659 3rd Qu.: 0.6598
## Max. : 5.8797 Max. : 4.0611
sapply(standardized, sd)
## pregnant glucose pressure mass pedigree age
## 1 1 1 1 1 1
Normalize
# Normalisasi Fitur
preprocessParams <- preProcess(diabetes[,1:6], method=c("range"))
normalized <- predict(preprocessParams, diabetes[,1:6])
summary(normalized)
## pregnant glucose pressure mass
## Min. :0.00000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.07692 1st Qu.:0.3597 1st Qu.:0.4082 1st Qu.:0.2902
## Median :0.23077 Median :0.4710 Median :0.4898 Median :0.4431
## Mean :0.29097 Mean :0.5011 Mean :0.4924 Mean :0.4429
## 3rd Qu.:0.46154 3rd Qu.:0.6210 3rd Qu.:0.5714 3rd Qu.:0.5741
## Max. :1.00000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## pedigree age
## Min. :0.00000 Min. :0.0000
## 1st Qu.:0.07077 1st Qu.:0.0500
## Median :0.12575 Median :0.1333
## Mean :0.16818 Mean :0.2040
## 3rd Qu.:0.23409 3rd Qu.:0.3333
## Max. :1.00000 Max. :1.0000
Plot Sebaran Asal
plots <- lapply(names(diabetes[,1:6]), function(var_x){
p <-
ggplot(diabetes) +
aes_string(var_x)
if(is.numeric(diabetes[[var_x]])) {
p <- p + geom_density(lwd=1, color="darkgreen")
} else {
p <- p + geom_bar(fill="darkred")
}
})
plot_grid(plotlist = plots)
Plot Sebaran Hasil Standardisasi
plots <- lapply(names(standardized), function(var_x){
p <-
ggplot(standardized) +
aes_string(var_x) +
geom_density(lwd=1, color="darkgreen")
})
plot_grid(plotlist = plots)
Plot Sebaran Hasil Normalisasi
plots <- lapply(names(normalized), function(var_x){
p <-
ggplot(normalized) +
aes_string(var_x) +
geom_density(lwd=1, color="darkgreen")
})
plot_grid(plotlist = plots)
Transformation (Box-Cox)
Transformasi umumnya digunakan untuk merubah sebaran suatu feature ketika feature tersebut tidak normal sehingga menjadi mendekati sebaran normal.
Box-Cox Transformation biasanya dilakukan pada variabel dependen (Y) dalam analisis regresi atau analisis varian (ANOVA). Ini dilakukan untuk memastikan bahwa variabel dependen memiliki distribusi yang lebih dekat dengan normal sehingga asumsi distribusi normal dalam model regresi atau ANOVA terpenuhi.
Transformasi ini juga dapat digunakan pada variabel independen (X) jika diperlukan, tergantung pada distribusi data dan tujuan analisis. Namun, transformasi pada variabel independen lebih jarang dilakukan karena memiliki implikasi terhadap interpretasi model akhir.
preprocessParams <- preProcess(diabetes[,1:6], method=c("BoxCox"))
print(preprocessParams)
## Created from 768 samples and 5 variables
##
## Pre-processing:
## - Box-Cox transformation (5)
## - ignored (0)
##
## Lambda estimates for Box-Cox transformation:
## 0.1, 0.9, 0.3, -0.1, -1.1
transformed <- predict(preprocessParams, diabetes[,1:6])
summary(transformed)
## pregnant glucose pressure mass
## Min. : 0.000 Min. :3.784 Min. : 24.00 Min. :4.626
## 1st Qu.: 1.000 1st Qu.:4.603 1st Qu.: 64.00 1st Qu.:5.676
## Median : 3.000 Median :4.762 Median : 72.00 Median :6.130
## Mean : 3.783 Mean :4.770 Mean : 72.25 Mean :6.087
## 3rd Qu.: 6.000 3rd Qu.:4.943 3rd Qu.: 80.00 3rd Qu.:6.482
## Max. :13.000 Max. :5.293 Max. :122.00 Max. :7.462
## pedigree age
## Min. :-2.5510 Min. :0.8772
## 1st Qu.:-1.4116 1st Qu.:0.8815
## Median :-0.9875 Median :0.8867
## Mean :-0.9599 Mean :0.8874
## 3rd Qu.:-0.4680 3rd Qu.:0.8938
## Max. : 0.8838 Max. :0.9019
plots <- lapply(names(transformed), function(var_x){
p <-
ggplot(transformed) +
aes_string(var_x) +
geom_density(lwd=1, color="darkgreen")
})
plot_grid(plotlist = plots)
=====================================================================================================================