Klasifikasi dengan Model Regresi Logistik dan K-NN

Dedy Gusnadi Sianipar

4/24/2021

Pendahuluan

Apa yang akan kita lakukan?

Kita akan mencoba melakukan prediksi terhadap data wholesale dengan model klasifikasi. Saya sebagai seorang distributor ingin melakukan penghabisan stok bahan yang memiliki kadarluarsa dalam jangka waktu dekat, dengan memberikan promo/diskon terhadap jenis perusahaan yang konsumsi barang tersbut dengan cepat , seperti horeca

Data

Package & Import Data

library(tidyverse) # feature engineering
library(rsample) # split data
library(caret) # untuk confusion matrix
library(car) # untuk uji VIF
options(scipen = 99999)
ws <- read.csv("wholesale.csv")
summary(ws)
##     Channel          Region          Fresh             Milk      
##  Min.   :1.000   Min.   :1.000   Min.   :     3   Min.   :   55  
##  1st Qu.:1.000   1st Qu.:2.000   1st Qu.:  3128   1st Qu.: 1533  
##  Median :1.000   Median :3.000   Median :  8504   Median : 3627  
##  Mean   :1.323   Mean   :2.543   Mean   : 12000   Mean   : 5796  
##  3rd Qu.:2.000   3rd Qu.:3.000   3rd Qu.: 16934   3rd Qu.: 7190  
##  Max.   :2.000   Max.   :3.000   Max.   :112151   Max.   :73498  
##     Grocery          Frozen        Detergents_Paper    Delicassen     
##  Min.   :    3   Min.   :   25.0   Min.   :    3.0   Min.   :    3.0  
##  1st Qu.: 2153   1st Qu.:  742.2   1st Qu.:  256.8   1st Qu.:  408.2  
##  Median : 4756   Median : 1526.0   Median :  816.5   Median :  965.5  
##  Mean   : 7951   Mean   : 3071.9   Mean   : 2881.5   Mean   : 1524.9  
##  3rd Qu.:10656   3rd Qu.: 3554.2   3rd Qu.: 3922.0   3rd Qu.: 1820.2  
##  Max.   :92780   Max.   :60869.0   Max.   :40827.0   Max.   :47943.0

kita bisa simpulkan dari sumarry terdapat : 1. terdapat outlier pada hampir keseluruhan data( kecuali channel region ), dilihat dari nilai max dan perbedaan nilai antara mean dan median, outlier ini dapat mempengaruhi model yang akan kita buat

Data Check

glimpse(ws)
## 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~

) . FRESH: pengeluaran tahunan (m.u.) untuk produk segar (Berkelanjutan) . MILK: pengeluaran tahunan (m.u.) untuk produk susu (Berkelanjutan) . GROCERY: pengeluaran tahunan (m.u.) untuk produk grosir (Berkelanjutan) . FROZEN: pengeluaran tahunan (m.u.) untuk produk beku (Berkelanjutan) . DETERGENTS_PAPER: pengeluaran tahunan (m.u.) untuk deterjen dan produk kertas (Berkelanjutan) . DELICATESSEN: pengeluaran tahunan (m.u.) dan produk makanan jadi (Berkelanjutan) . CHANNEL: saluran pelanggan - Horeca (Hotel / Restoran / Kafe) (1) atau saluran Ritel (Nominal) (2) . REGION: Wilayah pelanggan - Lisnon (1), Oporto(2) atau Lainnya (3)

Check Unique

unique(ws$Channel)
## [1] 2 1
unique(ws$Region)
## [1] 3 1 2

Variabel Channel dengan Region dapat kita ubah menjadi tipe data faktor

Check Missing Value

anyNA(ws)
## [1] FALSE

Tidak ada NA pada data

Change Type Data Set

tws <- ws %>% 
  mutate(Region = as.factor(Region))
tws$Channel <- factor(tws$Channel, levels = c(1,2), labels = c("1","0"))
datas_new <- tws

kita mengubah data channel kategori 2 menjadi 0 , untuk menjadikannya lebih umum dan tipe data sudah berhasil diganti menjadi kategori/faktor

Check Persebaran data

tws %>% ggplot(aes(x=Fresh,y=Milk,col= Channel))+
  geom_point()

dari grafik yang didapat dapat disimpulkan bahwa sebenarnya data yang digunakan tidak baik untuk dilakukan model klasifikasi, dikarenakan data cenderung berada di sisi sebelah kiri, sehingga ketika dilakukan siqmoid model tidak akn mendapatkan klasifikasi yang baik

Regresi Logistik

Pre-Processing Data

prop.table(table(datas_new$Channel))
## 
##         1         0 
## 0.6772727 0.3227273

terlihat proporsi data antara horeca dan ritel cukup seimbang

table(datas_new$Channel)
## 
##   1   0 
## 298 142

terdapat 298 data horeca dan 142 data ritel

Splitting Train-Test

set.seed(26)
init <- initial_split(data = datas_new,prop = 0.8, strata = Channel)
train <- training(init)
test <-  testing(init)

Dilakukan penetapan set.seed agar hasil random ketika digunakan oleh orang lain tidak berubah ubah , pemilihan angka 26 merupakan berdasarkan angka kelahiran saya, untuk penentuan angka ini bebas.

Data di Split menjadi dua bagian dengan proporsi data yaitu 80% (train) dan 20%(test)

prop.table(table(train$Channel))
## 
##         1         0 
## 0.6770538 0.3229462
prop.table(table(test$Channel))
## 
##         1         0 
## 0.6781609 0.3218391

Nice!. Setelah dilakukan split data dan dilakukan pengecekan hasil split data terhadap proporsi target kita didapatkan hasil yang sama dengan proprosi sebelumnya.

Model Fitting

Pertama, Mari kita membuat model dengan menggunakan seluruh varibel yang ada dengan target yaitu Channel

model_1 <- glm(formula = Channel~., data = train, family = "binomial")
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(model_1)
## 
## Call:
## glm(formula = Channel ~ ., family = "binomial", data = train)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -2.57291  -0.33610  -0.22455   0.02574   2.95986  
## 
## Coefficients:
##                      Estimate   Std. Error z value       Pr(>|z|)    
## (Intercept)      -5.201388782  0.823090856  -6.319 0.000000000263 ***
## Region2           2.221140908  0.898295934   2.473         0.0134 *  
## Region3           1.631890428  0.682836580   2.390         0.0169 *  
## Fresh            -0.000003681  0.000020226  -0.182         0.8556    
## Milk              0.000068299  0.000062680   1.090         0.2759    
## Grocery           0.000120770  0.000066113   1.827         0.0677 .  
## Frozen           -0.000099478  0.000092176  -1.079         0.2805    
## Detergents_Paper  0.001006858  0.000172580   5.834 0.000000005407 ***
## Delicassen       -0.000146850  0.000117632  -1.248         0.2119    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 444.12  on 352  degrees of freedom
## Residual deviance: 159.22  on 344  degrees of freedom
## AIC: 177.22
## 
## Number of Fisher Scoring iterations: 7

glm.fit: fitted probabilities numerically 0 or 1 occurredList of 30 Terdapat warning yang menyatakan bahwa model yang digunakan terdapat Perfect Separator. Berdasarkan hasil Sumaary sebelumnya dapat dilihat bahwa terdapat banyak data outlier pada beberapa Variabel contohnya Grocery Dan Region. Mari kita liat visualisasinya

plot(train$Channel, train$Grocery)

#dont use grocery
# GGally::ggcorr(train %>% 
#                  select_if(is.numeric),label = TRUE)

dari hasil visualisasi dapat disimpulkan bahwa outlier pada data 1 atau Horeca masih dalam range data 0 atau retail sehingga kita putuskan untuk tidak menggunakan variabel grocery.

model_2 <- glm(formula = Channel~Frozen+Milk+Fresh+Region+Delicassen, data = train, family = "binomial")
summary(model_2)
## 
## Call:
## glm(formula = Channel ~ Frozen + Milk + Fresh + Region + Delicassen, 
##     family = "binomial", data = train)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -3.0375  -0.6407  -0.3098   0.4187   3.1345  
## 
## Coefficients:
##                Estimate  Std. Error z value            Pr(>|z|)    
## (Intercept) -2.62141434  0.48490721  -5.406 0.00000006444338666 ***
## Frozen      -0.00032007  0.00008168  -3.918 0.00008916896821818 ***
## Milk         0.00036731  0.00004640   7.916 0.00000000000000245 ***
## Fresh       -0.00002734  0.00001488  -1.838             0.06606 .  
## Region2      1.76834867  0.60529418   2.921             0.00348 ** 
## Region3      0.99462677  0.45005581   2.210             0.02710 *  
## Delicassen  -0.00006697  0.00007483  -0.895             0.37080    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 444.12  on 352  degrees of freedom
## Residual deviance: 277.26  on 346  degrees of freedom
## AIC: 291.26
## 
## Number of Fisher Scoring iterations: 6

Nice! Perfect Separator berhasil kita keluarkan, sekarang mari kita coba membuat model dengan stepwise

summary(step(model_2, direction = "both", trace = 0))
## 
## Call:
## glm(formula = Channel ~ Frozen + Milk + Fresh + Region, family = "binomial", 
##     data = train)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -3.0102  -0.6435  -0.2944   0.4226   3.2176  
## 
## Coefficients:
##                Estimate  Std. Error z value             Pr(>|z|)    
## (Intercept) -2.55817787  0.47575830  -5.377 0.000000075714664444 ***
## Frozen      -0.00036765  0.00006623  -5.551 0.000000028462078989 ***
## Milk         0.00035340  0.00004326   8.169 0.000000000000000312 ***
## Fresh       -0.00002527  0.00001449  -1.745              0.08106 .  
## Region2      1.73424777  0.60113357   2.885              0.00391 ** 
## Region3      0.95970991  0.44418240   2.161              0.03072 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 444.12  on 352  degrees of freedom
## Residual deviance: 278.08  on 347  degrees of freedom
## AIC: 290.08
## 
## Number of Fisher Scoring iterations: 6

Dari Sumarry yang didapatkan bisa disimpulkan bahwa: 1. hampir semua variabel yang digunakan signifikan kecuali variabel Fresh 2. Nilai Estimate Intercept(log off odds) Sebesar -2.5581 3. Nilai Estimate Milk sebesar 0.00035340 dan bernilai positif maka disimpulkan setiap peningkatan 1 pada Variabel milk akan meningkatkan nilai prediksi channel sebesar 0.00035340 3. Nilai Estimate Frozen sebesar -0.00036765 dan bernilai negatif maka disimpulkan setiap peningkatan 1 pada Variabel Frozen akan menurunkan nilai prediksi channel sebesar 0.00035340 4. Nilai Estimate Pada Region2 sebesar 1.73424777 dan bernilai positif maka disimpulkan setiap peningkatan 1 pada variabel Region 2 maka akan meningkatkan nilai prediksi sebesar 1.73424777 4. Nilai Estimate Pada Region3 sebesar 0.95970991 dan bernilai positif maka disimpulkan setiap peningkatan 1 pada variabel Region 3 maka akan meningkatkan nilai prediksi sebesar 0.95970991

Uji Multicolinearitas

vif(step(model_2, direction = "both", trace = 0))
##            GVIF Df GVIF^(1/(2*Df))
## Frozen 2.054515  1        1.433358
## Milk   1.933221  1        1.390403
## Fresh  1.278249  1        1.130597
## Region 1.086509  2        1.020959

Berdasarkan Uji asumsi terlihat tidak adanya nilai VIF yang lebih dari 10 artinya tidak adanya hubungan yang kuat antar variabel prediktornya

Prediction

kita lakukan pengujian model dengan data test

test$pred.channel <- predict(object = model_2, newdata = test, type = "response")
test$pred.label <- ifelse(test$pred.channel<0.5,0,1)
test$pred.label <- as.factor(test$pred.label)
test[1:10, c("Channel", "pred.label")]
##    Channel pred.label
## 1        0          1
## 10       0          1
## 11       0          0
## 13       0          1
## 14       0          0
## 15       0          1
## 16       1          0
## 22       1          0
## 30       1          0
## 40       1          0

Dalam syntax diatas, ketika probabilitas data test lebih dari 0.5, artinya dia Horeca atau Retail. setelah model dilakukan pengujian terhadap data test maka kita melihat bagaimana hasil prediksi dengan aktual

Model Evaluation

Confusion Matrix

library(caret)
confusionMatrix(data = test$pred.label, reference = test$Channel, positive = "1")
## Warning in confusionMatrix.default(data = test$pred.label, reference =
## test$Channel, : Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  0
##          1  6 20
##          0 53  8
##                                           
##                Accuracy : 0.1609          
##                  95% CI : (0.0909, 0.2552)
##     No Information Rate : 0.6782          
##     P-Value [Acc > NIR] : 1.0000000       
##                                           
##                   Kappa : -0.4678         
##                                           
##  Mcnemar's Test P-Value : 0.0001802       
##                                           
##             Sensitivity : 0.10169         
##             Specificity : 0.28571         
##          Pos Pred Value : 0.23077         
##          Neg Pred Value : 0.13115         
##              Prevalence : 0.67816         
##          Detection Rate : 0.06897         
##    Detection Prevalence : 0.29885         
##       Balanced Accuracy : 0.19370         
##                                           
##        'Positive' Class : 1               
## 

Re-call/Sensitivity = dari semua data aktual yang positif, seberapa mampu proporsi model saya menebak benar. Specificity = dari semua data aktual yang negatif, seberapa mampu proporsi model saya menebak yang benar. Accuracy = seberapa mampu model saya menebak dengan benar target Y. Precision = dari semua hasil prediksi, seberapa mampu model saya dapat menebak benar kelas positif

Berdasarkan hasil confusionMatrix diatas, dapat kita ambil informasi bahwa kemampuan model dalam menebak target Y (1horeca atau 0retail) sebesar 16%. Sedangkan dari keluruhan data aktual channel tipe Horeca, model dapat mampu menebak benar sebesar 10,2%. Dari keseluruhan data aktual channel tipe retail, model mampu menebak dengan benar sebesar 23%. Dari keseluruhan hasil prediksi yang mampu ditebak oleh model, model mampu menebak benar kelas positif sebesar 6%.

Hasil model yang kurang baik sebenarnya bukan dikarenakan pemilihan prediktor yang kurang baik melaikan persebaran daata yang ada pada prediktor cukup tidak bagus, terdapat banayak outlier sehingga tidak menampilkan kurva sigmoid

K-NN

Pre-Processing & Splitting Train-Test

#predictor
ws_train_x <- train %>% 
  select(-Channel)
ws_test_x <- test %>% 
  select(-c("Channel","pred.channel","pred.label"))

#target
ws_train_y <- train %>% 
  select(Channel)
ws_test_y <- test %>% 
  select(Channel)

Scale & K Value

#scale
ws_train_xs <- scale(ws_train_x %>% select(-Region))
ws_test_xs <- scale(ws_test_x %>% select(-Region))
dim(ws_train_xs)
## [1] 353   6
dim(ws_test_xs)
## [1] 87  6
#K Value
sqrt(nrow(ws_train_xs))
## [1] 18.78829

Model Fitting

library(class)
ws_pred <- knn(ws_train_xs,ws_test_xs,cl = ws_train_y$Channel,k=19)
head(ws_pred)
## [1] 0 0 0 0 0 0
## Levels: 1 0

Model Evaluation

Confusion matrix

confusionMatrix(data = ws_pred,reference = as.factor(ws_test_y$Channel),positive = "1")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  0
##          1 55  2
##          0  4 26
##                                           
##                Accuracy : 0.931           
##                  95% CI : (0.8559, 0.9743)
##     No Information Rate : 0.6782          
##     P-Value [Acc > NIR] : 0.00000001437   
##                                           
##                   Kappa : 0.8449          
##                                           
##  Mcnemar's Test P-Value : 0.6831          
##                                           
##             Sensitivity : 0.9322          
##             Specificity : 0.9286          
##          Pos Pred Value : 0.9649          
##          Neg Pred Value : 0.8667          
##              Prevalence : 0.6782          
##          Detection Rate : 0.6322          
##    Detection Prevalence : 0.6552          
##       Balanced Accuracy : 0.9304          
##                                           
##        'Positive' Class : 1               
## 

Hasil penelitian menunjukkan bahwa K-NN kami dengan K = 19 memiliki akurasi 93,1% pada dataset uji, artinya 93,1% data kami diklasifikasikan dengan benar. Nilai sensitivitas dan spesifisitas 93.22% dan 92.86%. Ini menunjukkan bahwa sebagian besar hasil positif diklasifikasikan dengan benar tetapi hanya sejumlah kecil hasil negatif yang diklasifikasikan dengan benar. Nilai prediksi presisi / positif adalah 96.49%, artinya 96.49% prediksi positif kami benar.

Conclusion

Berdasarkan Evaluasi kedua model, dapat disimpulkan bahwa model klasifikasi memperlihatkan nilai akurasi , recall , maupun prediksi yang sangat kecil , sementara untuk model Knn memperlihatkan hasil yang sangat bagus. Berdasarkan hasil EDA dari awal sebenarnya dapat disimpulkan bahwa data yang digunakan tidak cocok untuk dilakukan model klasifikasi(logistik).