Prediksi Pelanggan dari Distributor Grosir
Pendahuluan
Dalam portofolio Learning by Building untuk
Machine Learning: Classification 1, saya akan menganalisis
data wholesale tentang jenis pelanggan dari distributor
grosir berdasarkan variabel-variabel pengeluaran tahunan dari beberapa
jenis produknya. Dalam proses pembuatan model prediksi, saya menggunakan
logistik regression dan k-nearest neighbor yang termasuk dalam
supervised learning.
Data Preparation
Library
Langkah pertama yang harus dilakukan adalah
install.package() dan / atau mengaktifkan
library() yang dibutuhkan dalam proses analisis dan
pembuatan model prediksi.
library(dplyr)##
## 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
library(gtools)
library(gmodels)
library(ggplot2)
library(class)
library(tidyr)
library(caret)## Loading required package: lattice
library(rsample)##
## Attaching package: 'rsample'
## The following object is masked from 'package:gtools':
##
## permutations
Load Dataset
Dataset yang akan digunakan adalah data tentang pelanggan dari distributor grosir yang mencakup besaran pengeluaran tahunan berdasarkan produk yang ada.
wholesale <- read.csv("wholesale.csv")
head(wholesale)## Channel Region Fresh Milk Grocery Frozen Detergents_Paper Delicassen
## 1 2 3 12669 9656 7561 214 2674 1338
## 2 2 3 7057 9810 9568 1762 3293 1776
## 3 2 3 6353 8808 7684 2405 3516 7844
## 4 1 3 13265 1196 4221 6404 507 1788
## 5 2 3 22615 5410 7198 3915 1777 5185
## 6 2 3 9413 8259 5126 666 1795 1451
Channel: Pelanggan dari Distributor Grosir, 1: Horeca (Hotel, Restoran, Cafe) dan 2: Ritel.Region: Wilayah pelanggan, 1: Lisbon, 2: Porto dan 3: lainnya.Fresh: Pengeluaran tahunan untuk produk segar (Fresh).Milk: Pengeluaran tahunan untuk produk susu (Milk).Grocery: Pengeluaran tahunan untuk produk kelontong (Grocery).Frozen: Pengeluaran tahunan untuk produk beku (Frozen).Detergents_Paper: Pengeluaran tahunan untuk produk deterjen dan produk kertas (Detergents & Paper).Delicassen: Pengeluaran tahunan untuk produk delicatessen.
Cek Tipe Data
Dari data yang ada, cek apakah semua tipe data yang ada telah sesuai.
glimpse(wholesale)## Rows: 440
## Columns: 8
## $ Channel <int> 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1,…
## $ Region <int> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,…
## $ Fresh <int> 12669, 7057, 6353, 13265, 22615, 9413, 12126, 7579, 5…
## $ Milk <int> 9656, 9810, 8808, 1196, 5410, 8259, 3199, 4956, 3648,…
## $ Grocery <int> 7561, 9568, 7684, 4221, 7198, 5126, 6975, 9426, 6192,…
## $ Frozen <int> 214, 1762, 2405, 6404, 3915, 666, 480, 1669, 425, 115…
## $ Detergents_Paper <int> 2674, 3293, 3516, 507, 1777, 1795, 3140, 3321, 1716, …
## $ Delicassen <int> 1338, 1776, 7844, 1788, 5185, 1451, 545, 2566, 750, 2…
Menghapus Kolom
Dari data yang sudah ada, kolom Region bisa dihapus.
wholesale <- wholesale %>%
select(-Region)Mengubah Tipe Data
Terdapat 2 kolom yang tipe datanya belum sesuai, sehingga perlu mengubah tipe data dari 2 kolom tersebut.
wholesale <- wholesale %>%
mutate(Channel = as.factor(Channel))
glimpse(wholesale)## Rows: 440
## Columns: 7
## $ Channel <fct> 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1,…
## $ Fresh <int> 12669, 7057, 6353, 13265, 22615, 9413, 12126, 7579, 5…
## $ Milk <int> 9656, 9810, 8808, 1196, 5410, 8259, 3199, 4956, 3648,…
## $ Grocery <int> 7561, 9568, 7684, 4221, 7198, 5126, 6975, 9426, 6192,…
## $ Frozen <int> 214, 1762, 2405, 6404, 3915, 666, 480, 1669, 425, 115…
## $ Detergents_Paper <int> 2674, 3293, 3516, 507, 1777, 1795, 3140, 3321, 1716, …
## $ Delicassen <int> 1338, 1776, 7844, 1788, 5185, 1451, 545, 2566, 750, 2…
Cek Missing Value
Selanjutnya perlu mengetahui apakah ada missing value
pada dataset wholesale.
colSums(is.na(wholesale))## Channel Fresh Milk Grocery
## 0 0 0 0
## Frozen Detergents_Paper Delicassen
## 0 0 0
Cek Proporsi dari Variabel Target
wholesale$Channel
prop.table(table(wholesale$Channel))##
## 1 2
## 0.6772727 0.3227273
Membagi Data Train & Test
Data yang sudah ada, dibagi menjadi 2, yaitu data train yang digunakan untuk membuat modal dan data test untuk mengevaluasi model.
set.seed(193)
intrain <- sample(nrow(wholesale), size = 0.8*nrow(wholesale))
wholesale_train <- wholesale[intrain,]
wholesale_test <- wholesale[-intrain,]
wholesale$Channel %>%
levels()## [1] "1" "2"
Logistic Regression
Dengan permodelan Logistic Regression, akan dibuat 2
model, model pertama dengan menggunakan semua variabel pada data dan
model kedua menggunakan stepwise.
Model dengan Semua Variabel
Pertama, dibuat model menggunakan semua variabel prediktor.
Model
Untuk pembuatan model, fungsi yang digunakan adalah fungsi
glm.
model1 <- glm(formula = Channel~., family = "binomial",
data = wholesale)## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(model1)##
## Call:
## glm(formula = Channel ~ ., family = "binomial", data = wholesale)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.8094 -0.3163 -0.2285 0.0395 3.1918
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -3.700e+00 4.375e-01 -8.457 < 2e-16 ***
## Fresh 6.453e-06 1.700e-05 0.380 0.7043
## Milk 7.372e-05 5.389e-05 1.368 0.1713
## Grocery 1.177e-04 5.906e-05 1.993 0.0463 *
## Frozen -1.671e-04 9.207e-05 -1.815 0.0695 .
## Detergents_Paper 8.436e-04 1.334e-04 6.324 2.54e-10 ***
## Delicassen -6.766e-05 1.086e-04 -0.623 0.5333
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 553.44 on 439 degrees of freedom
## Residual deviance: 203.91 on 433 degrees of freedom
## AIC: 217.91
##
## Number of Fisher Scoring iterations: 7
Prediksi
Dari model yang telah dibuat, selanjutnya membuat prediksi dengan data test yang telah dibagi sebelumnya.
pred1 <- predict(model1, type = "response", newdata = wholesale_test)pred1_Label <- ifelse(test = pred1 > 0.5,
yes = 2,
no = 1)Evaluasi
Dengan data prediksi yang telah dibuat, bisa dilakukan evaluasi
dengan data aktual dari data test dengan
confusionMatrix.
pred_model1_conf <- confusionMatrix(data = as.factor(pred1_Label), #hasil prediksi dari model yg sudah dibuat
reference = wholesale_test$Channel, #data aktual dari data test
positive = "2")
pred_model1_conf## Confusion Matrix and Statistics
##
## Reference
## Prediction 1 2
## 1 56 6
## 2 1 25
##
## Accuracy : 0.9205
## 95% CI : (0.843, 0.9674)
## No Information Rate : 0.6477
## P-Value [Acc > NIR] : 2.664e-09
##
## Kappa : 0.819
##
## Mcnemar's Test P-Value : 0.1306
##
## Sensitivity : 0.8065
## Specificity : 0.9825
## Pos Pred Value : 0.9615
## Neg Pred Value : 0.9032
## Prevalence : 0.3523
## Detection Rate : 0.2841
## Detection Prevalence : 0.2955
## Balanced Accuracy : 0.8945
##
## 'Positive' Class : 2
##
Model dengan Fitting Stepwise
Kedua, model yang dibuat menggunakan stepwise dari model
pertama yang menggunakan semua variabel prediktor.
Model
Untuk pembuatan model, fungsi yang digunakan adalah fungsi
glm.
model2 <- step(object = model1,
direction = "backward",
trace = 0)## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(model2)##
## Call:
## glm(formula = Channel ~ Grocery + Frozen + Detergents_Paper,
## family = "binomial", data = wholesale)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.87319 -0.31394 -0.23700 0.04548 3.01358
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -3.622e+00 4.018e-01 -9.015 < 2e-16 ***
## Grocery 1.499e-04 4.989e-05 3.004 0.00267 **
## Frozen -1.383e-04 7.283e-05 -1.899 0.05751 .
## Detergents_Paper 8.441e-04 1.296e-04 6.513 7.39e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 553.44 on 439 degrees of freedom
## Residual deviance: 206.03 on 436 degrees of freedom
## AIC: 214.03
##
## Number of Fisher Scoring iterations: 7
Prediksi
Dari model stepwise yang telah dibuat, selanjutnya
membuat prediksi dengan data test yang telah dibagi sebelumnya.
pred2 <- predict(model2, type = "response", newdata = wholesale_test)pred2_Label <- ifelse(test = pred2 > 0.5,
yes = 2,
no = 1)Evaluasi
Dengan data prediksi yang telah dibuat, bisa dilakukan evaluasi
dengan data aktual dari data test dengan
confusionMatrix.
pred_model2_conf <- confusionMatrix(data = as.factor(pred2_Label), #hasil prediksi dari model yg sudah dibuat
reference = wholesale_test$Channel, #data aktual dari data test
positive = "2")
pred_model2_conf## Confusion Matrix and Statistics
##
## Reference
## Prediction 1 2
## 1 56 5
## 2 1 26
##
## Accuracy : 0.9318
## 95% CI : (0.8575, 0.9746)
## No Information Rate : 0.6477
## P-Value [Acc > NIR] : 4.07e-10
##
## Kappa : 0.8461
##
## Mcnemar's Test P-Value : 0.2207
##
## Sensitivity : 0.8387
## Specificity : 0.9825
## Pos Pred Value : 0.9630
## Neg Pred Value : 0.9180
## Prevalence : 0.3523
## Detection Rate : 0.2955
## Detection Prevalence : 0.3068
## Balanced Accuracy : 0.9106
##
## 'Positive' Class : 2
##
K-Nearest Neighbour
Untuk model yang ketiga, menggunakan K-Nearest Neighbour.
Data Pre-processing
Pada model KNN ini, tidak perlu membuat model, sehingga diperlukan persiapan data.
Memisahkan Prediktor dan Target
Pada model KNN, variabel prediktor dan variabel target harus dipisahkan.
wholesale_train_x <- wholesale_train %>%
select(-Channel)
wholesale_test_x <- wholesale_test %>%
select(-Channel)
wholesale_train_y <- wholesale_train$Channel
wholesale_test_y <- wholesale_test$ChannelScaling Data
summary(wholesale)## Channel Fresh Milk Grocery Frozen
## 1:298 Min. : 3 Min. : 55 Min. : 3 Min. : 25.0
## 2:142 1st Qu.: 3128 1st Qu.: 1533 1st Qu.: 2153 1st Qu.: 742.2
## Median : 8504 Median : 3627 Median : 4756 Median : 1526.0
## Mean : 12000 Mean : 5796 Mean : 7951 Mean : 3071.9
## 3rd Qu.: 16934 3rd Qu.: 7190 3rd Qu.:10656 3rd Qu.: 3554.2
## Max. :112151 Max. :73498 Max. :92780 Max. :60869.0
## Detergents_Paper Delicassen
## Min. : 3.0 Min. : 3.0
## 1st Qu.: 256.8 1st Qu.: 408.2
## Median : 816.5 Median : 965.5
## Mean : 2881.5 Mean : 1524.9
## 3rd Qu.: 3922.0 3rd Qu.: 1820.2
## Max. :40827.0 Max. :47943.0
Dari range data wholesale, range dari masing-masing
variabel memiliki skala yang berbeda-beda. Karena range harus sama
karena knn mengklasifikasikan berdasarkan jarak
#tidak menggunakan argumen center dan scale karena data train
wholesale_train_x_scale <- scale(x = wholesale_train_x)
#menggunakan center dan scale dari data train
wholesale_test_x_scale <- scale(x = wholesale_test_x,
center = attr(wholesale_train_x_scale, "scaled:center"),
scale =attr(wholesale_train_x_scale, "scaled:scale"))Prediksi
Sebelum membuat prediksi, dicari nilai k menggunakan
akar dari jumlah data.
sqrt(nrow(wholesale_train))## [1] 18.76166
Karena pada KNN tidak membuat model, maka langsung
dibuat prediksi.
pred_knn <- knn(train = wholesale_train_x_scale,
test = wholesale_test_x_scale,
cl = wholesale_train_y, #menggunakan dataframe harus dipanggil nama kolomnya/variabelnya
k = 19)
head(pred_knn)## [1] 1 1 2 1 1 1
## Levels: 1 2
Evaluasi
Dengan data prediksi yang telah dibuat, bisa dilakukan evaluasi
dengan data aktual dari data test dengan
confusionMatrix.
pred_knn_conf <- confusionMatrix(data = as.factor(pred_knn), #hasil prediksi dari model yg sudah dibuat
reference = wholesale_test$Channel, #data aktual dari data test
positive = "2")
pred_knn_conf## Confusion Matrix and Statistics
##
## Reference
## Prediction 1 2
## 1 55 7
## 2 2 24
##
## Accuracy : 0.8977
## 95% CI : (0.8147, 0.9522)
## No Information Rate : 0.6477
## P-Value [Acc > NIR] : 7.518e-08
##
## Kappa : 0.7673
##
## Mcnemar's Test P-Value : 0.1824
##
## Sensitivity : 0.7742
## Specificity : 0.9649
## Pos Pred Value : 0.9231
## Neg Pred Value : 0.8871
## Prevalence : 0.3523
## Detection Rate : 0.2727
## Detection Prevalence : 0.2955
## Balanced Accuracy : 0.8696
##
## 'Positive' Class : 2
##
Model Evaluation
Dari semua model dan prediksi yang telah dibuat, dibandingkan hasil
evaluasi dari masing-masing confusionMatrix setiap
model.
model_eval <- data.frame(Model_prediksi = c("Model Logit Semua Prediktor", "Model Logit Step", "Model KNN"),
Accuracy = c(pred_model1_conf$overall[1],pred_model2_conf$overall[1],pred_knn_conf$overall[1]),
Recall = c(pred_model1_conf$byClass[1],pred_model2_conf$byClass[1],pred_knn_conf$byClass[1]),
Specificity = c(pred_model1_conf$byClass[2],pred_model2_conf$byClass[2],pred_knn_conf$byClass[2]),
Precision = c(pred_model1_conf$byClass[3],pred_model2_conf$byClass[3],pred_knn_conf$byClass[3]))
model_eval## Model_prediksi Accuracy Recall Specificity Precision
## 1 Model Logit Semua Prediktor 0.9204545 0.8064516 0.9824561 0.9615385
## 2 Model Logit Step 0.9318182 0.8387097 0.9824561 0.9629630
## 3 Model KNN 0.8977273 0.7741935 0.9649123 0.9230769
Conclusion
Dari data wholesale, telah dibuat model dengan algoritma
logistic regression dan K-Nearest Neighbour.
Hasil evaluasi dari prediksi pada semua model, menunjukkan prediksi
dengan K-Nearest Neighbour menghasilkan model yang lebih
baik dibanding model dengan logistic regression.