Project ini dilakukan untuk tugas Learning By Building sebagai
pendalaman dan pembelajaran mandiri atas materi Logistic Regression dan
KNN. Objektif dari project ini adalah melakukan eksplorasi target
variabel channel
untuk dapat dianalisis variabel-variabel
apa yang mempengaruhi untuk sebuah data dikelompokan sebagai channel
klien tertentu. Dataset yang digunakan mengacu kepada klien dari
wholesale distributor.
<-
Wholesale read.csv("wholesale.csv")
Mengubah sistem label nominal pada variabel target yang sebelumnya 1-2 menjadi 0-1 agar pembuatan model dan analisisnya dapat dilakukan dengan lebih mudah
$Channel <-
Wholesaleifelse(Wholesale$Channel=="1", yes = 0, no = 1)
glimpse(Wholesale)
## Rows: 440
## Columns: 8
## $ Channel <dbl> 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0,…
## $ 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…
Deskripsi dari variabel yang ada pada dataset adalah sebagai berikut:
CHANNEL : customers Channel - 1 Hotel (Hotel/Restaurant/Cafe) or 0 Retail channel (Nominal)
REGION : customers Region Lisnon, Oporto or Other (Nominal)
FRESH : annual spending (m.u.) on fresh products (Continuous)
MILK : annual spending (m.u.) on milk products (Continuous)
GROCERY : annual spending (m.u.)on grocery products (Continuous)
FROZEN : annual spending (m.u.)on frozen products (Continuous)
DETERGENTS_PAPER : annual spending (m.u.) on detergents and paper products (Continuous)
DELICATESSEN : annual spending (m.u.)on and delicatessen products (Continuous)
Pada data di atas terdapat 2 variabel yang harus diubah jenis datanya, yakni: Channel menjadi bentuk category. Selain itu juga ada data yang tidak dibutuhkan, yakni Region sehingga akan di-drop.
<-
Wholesale %>%
Wholesale select(!c(Region)) %>%
mutate(Channel = as.factor(Channel))
str(Wholesale)
## 'data.frame': 440 obs. of 7 variables:
## $ Channel : Factor w/ 2 levels "0","1": 2 2 2 1 2 2 2 2 1 2 ...
## $ Fresh : int 12669 7057 6353 13265 22615 9413 12126 7579 5963 6006 ...
## $ Milk : int 9656 9810 8808 1196 5410 8259 3199 4956 3648 11093 ...
## $ Grocery : int 7561 9568 7684 4221 7198 5126 6975 9426 6192 18881 ...
## $ Frozen : int 214 1762 2405 6404 3915 666 480 1669 425 1159 ...
## $ Detergents_Paper: int 2674 3293 3516 507 1777 1795 3140 3321 1716 7425 ...
## $ Delicassen : int 1338 1776 7844 1788 5185 1451 545 2566 750 2098 ...
colSums(is.na(Wholesale))
## Channel Fresh Milk Grocery
## 0 0 0 0
## Frozen Detergents_Paper Delicassen
## 0 0 0
Kolom yang akan digunakan semuanya memiliki data yang lengkap sehingga tidak ada baris yang perlu dihilangkan.
summary(Wholesale)
## Channel Fresh Milk Grocery Frozen
## 0:298 Min. : 3 Min. : 55 Min. : 3 Min. : 25.0
## 1: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
Kolom yang akan digunakan memiliki skala yang tidak jauh berbeda antara satu kolom dengan kolom lainnya sehingga tidak perlu dilakukan skala data.
library(rsample)
RNGkind(sample.kind = "Rounding")
## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(100)
<- initial_split(data = Wholesale, prop = 0.8,
intrain strata = "Channel")
<- training(intrain)
wholesale_train <- testing(intrain) wholesale_test
prop.table(table(wholesale_train$Channel))
##
## 0 1
## 0.6780627 0.3219373
Karena datanya tidak seimbang maka untuk kali ini akan dilakukan Downsample yakni mengurangi observasi mayoritas (kelas 0) hingga seimbang dengan yang minoritas (kelas 1). Proporsi yang seimbang penting agar model klasifikasi mempelajari karakteristik setiap kelas secara seimbang, tidak dominan hanya satu kelas saja. Hal ini mencegah model bias terhadap model dengan nilai yang lebih besar proporsinya sehingga hanya baik untuk memprediksi 1 kelas saja.
RNGkind(sample.kind = "Rounding")
## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(100)
<- downSample(x = wholesale_train %>% select(-c(Channel)),
wholesale_train_down y = wholesale_train$Channel,
yname = "Channel")
prop.table(table(wholesale_train_down$Channel))
##
## 0 1
## 0.5 0.5
Kolom target pada data train sudah memiliki data yang balance
<- glm(formula = Channel~.,
model_wholesale data = wholesale_train_down,
family = "binomial")
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(model_wholesale)
##
## Call:
## glm(formula = Channel ~ ., family = "binomial", data = wholesale_train_down)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.47918 -0.28178 -0.04021 0.09392 2.81240
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -4.115e+00 7.279e-01 -5.652 1.58e-08 ***
## Fresh 1.791e-05 2.452e-05 0.730 0.465
## Milk 7.045e-05 1.013e-04 0.696 0.487
## Grocery 1.017e-04 9.087e-05 1.120 0.263
## Frozen -6.306e-05 7.648e-05 -0.825 0.410
## Detergents_Paper 1.308e-03 2.315e-04 5.648 1.62e-08 ***
## Delicassen -4.929e-05 1.204e-04 -0.409 0.682
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 313.303 on 225 degrees of freedom
## Residual deviance: 90.404 on 219 degrees of freedom
## AIC: 104.4
##
## Number of Fisher Scoring iterations: 8
#table(wholesale_train_down$Channel, wholesale_train_down$Grocery)
#table(wholesale_train_down$Channel, wholesale_train_down$Detergents_Paper)
#table(wholesale_train_down$Channel, wholesale_train_down$Delicassen)
Variabel yang diduga mengalami Perfect Separation adalah Grocery, Detergent Papers, Delicassen. Hal ini terlihat dari datanya yang mengalami permisahaan skala 0-1 yang jelas sehingga predictor ini tidak akan digunakan pada persamaan yang baru.
Selanjutnya dibuat model baru hanya dengan prediktor yang bebas perfect separation.
<- glm(formula = Channel~Fresh+Milk+Frozen,
model_wholesale_new data = wholesale_train_down,
family = "binomial")
summary(model_wholesale_new)
##
## Call:
## glm(formula = Channel ~ Fresh + Milk + Frozen, family = "binomial",
## data = wholesale_train_down)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.3139 -0.6737 -0.0001 0.6747 3.3519
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -9.852e-01 3.208e-01 -3.071 0.00214 **
## Fresh -3.481e-05 2.186e-05 -1.592 0.11129
## Milk 3.763e-04 5.543e-05 6.789 1.13e-11 ***
## Frozen -3.800e-04 7.729e-05 -4.917 8.81e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 313.30 on 225 degrees of freedom
## Residual deviance: 190.51 on 222 degrees of freedom
## AIC: 198.51
##
## Number of Fisher Scoring iterations: 6
Selain dengan model glm, juga dilakukan percobaan untuk mencari predictor dengan metode Step-Wise (Backward) untuk mendapatkan nilai AIC yang optimum.
<- step(object = model_wholesale_new,
model_wholesale_step direction = "backward",
trace = 0)
summary(model_wholesale_step)
##
## Call:
## glm(formula = Channel ~ Fresh + Milk + Frozen, family = "binomial",
## data = wholesale_train_down)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.3139 -0.6737 -0.0001 0.6747 3.3519
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -9.852e-01 3.208e-01 -3.071 0.00214 **
## Fresh -3.481e-05 2.186e-05 -1.592 0.11129
## Milk 3.763e-04 5.543e-05 6.789 1.13e-11 ***
## Frozen -3.800e-04 7.729e-05 -4.917 8.81e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 313.30 on 225 degrees of freedom
## Residual deviance: 190.51 on 222 degrees of freedom
## AIC: 198.51
##
## Number of Fisher Scoring iterations: 6
Ternyata pilihan predictor tidak berbeda dibandingkan dengan model
yang dibuat sebelumnya.
exp(model_wholesale_new$coefficients)
## (Intercept) Fresh Milk Frozen
## 0.3733737 0.9999652 1.0003764 0.9996201
Setiap kenaikan 1 satuan pada nilai Milk/Fresh/Frozen maka
kemungkinan dia adalah Wholesale akan 1 kali lebih mungkin dibandingkan
nilai di bawahnya dengan catatan variabel lainnya konstan (nilainya
sama).
$pred_channel <- predict(object = model_wholesale_new,
wholesale_testnewdata = wholesale_test,
type = "link")
head(wholesale_test,3)
## Channel Fresh Milk Grocery Frozen Detergents_Paper Delicassen pred_channel
## 3 1 6353 8808 7684 2405 3516 7844 1.194235
## 4 0 13265 1196 4221 6404 507 1788 -3.430331
## 5 1 22615 5410 7198 3915 1777 5185 -1.224345
Klasifikasi data wholesale_test berdasarkan pred_wholesale_new dan disimpan pada kolom baru bernama pred_label menggunakan threshold 0.5
$pred_channel_label <- ifelse(test = wholesale_test$pred_channel > 0.5,
wholesale_testyes = 1,
no = 0)
head(wholesale_test,3)
## Channel Fresh Milk Grocery Frozen Detergents_Paper Delicassen pred_channel
## 3 1 6353 8808 7684 2405 3516 7844 1.194235
## 4 0 13265 1196 4221 6404 507 1788 -3.430331
## 5 1 22615 5410 7198 3915 1777 5185 -1.224345
## pred_channel_label
## 3 1
## 4 0
## 5 0
Melihat hasil prediksi dibandingkan dengan data aktual
head(wholesale_test %>%
select(pred_channel, pred_channel_label, Channel))
## pred_channel pred_channel_label Channel
## 3 1.1942348 1 1
## 4 -3.4303313 0 0
## 5 -1.2243446 0 1
## 6 1.5419042 1 1
## 9 0.0184746 0 0
## 10 2.5396148 1 1
confusionMatrix(data = as.factor(wholesale_test$pred_channel_label),
reference = wholesale_test$Channel,
positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 54 10
## 1 6 19
##
## Accuracy : 0.8202
## 95% CI : (0.7245, 0.8936)
## No Information Rate : 0.6742
## P-Value [Acc > NIR] : 0.001565
##
## Kappa : 0.5757
##
## Mcnemar's Test P-Value : 0.453255
##
## Sensitivity : 0.6552
## Specificity : 0.9000
## Pos Pred Value : 0.7600
## Neg Pred Value : 0.8438
## Prevalence : 0.3258
## Detection Rate : 0.2135
## Detection Prevalence : 0.2809
## Balanced Accuracy : 0.7776
##
## 'Positive' Class : 1
##
sqrt(nrow(wholesale_train_down))
## [1] 15.0333
# variabel prediktor (x)
<- select(wholesale_train_down, -Channel)
wholesale_train_x_KNN <- select(wholesale_test, -Channel, -pred_channel, -pred_channel_label)
wholesale_test_x_KNN
#variabel target (y: kategorikal)
<- select(wholesale_train_down, Channel)
wholesale_train_y_KNN <- select(wholesale_test, Channel) wholesale_test_y_KNN
<- knn(train = wholesale_train_x_KNN,
wholesale_KNN test = wholesale_test_x_KNN,
cl = wholesale_train_y_KNN$Channel,
k = 15)
head(wholesale_KNN)
## [1] 1 0 0 1 0 1
## Levels: 0 1
confusionMatrix(data = as.factor(wholesale_KNN),
reference = wholesale_test_y_KNN$Channel,
positive = "1")
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 53 3
## 1 7 26
##
## Accuracy : 0.8876
## 95% CI : (0.8031, 0.9448)
## No Information Rate : 0.6742
## P-Value [Acc > NIR] : 2.711e-06
##
## Kappa : 0.7531
##
## Mcnemar's Test P-Value : 0.3428
##
## Sensitivity : 0.8966
## Specificity : 0.8833
## Pos Pred Value : 0.7879
## Neg Pred Value : 0.9464
## Prevalence : 0.3258
## Detection Rate : 0.2921
## Detection Prevalence : 0.3708
## Balanced Accuracy : 0.8899
##
## 'Positive' Class : 1
##
Kesimpulan untuk menentukan metode terbaik dilakukan dengan
membandingkan nilai accuracy metode Logistic Regression vs KNN.
Alasan evaluasi akan didasarkan pada nilai Accuracy adalah:
Dengan tujuan ingin memprediksi kelompok customer tertentu untuk membuat strategi marketing untuk tiap kelompok membuat kedua kelas yang ada pada analisis menjadi sama pentingnya.
Data yang digunakan pada saat training sudah balance, dan data keseluruhan perbedaan antar kelas Channel tidak ekstrim.
Dari Confusion Matrix di kedua metode terlihat bahwa nilai accuracy dengan menggunakan metode KNN memiliki nilai yang lebih baik yakni 89% dibandingkan dengan model logistik regresi dengan nilai accuracy 82%. Hal ini menunjukkan bahwa pada kasus ini, KNN lebih mampu melakukan prediksi yang tepat pada setiap kelas dibandingkan jika menggunakan Logistik Regresi.