Labai trumpai charakterizuoti duomenų rinkiniai, sprendžiamas klasifikavimo uždavinys abiems pasirinktiems duomenų rinkiniams. Pasirinktiems duomenims sudarykite LDA klasifikatorių pagal pavyzdį 128-131 psl. iš 5 skyriaus “Machine learning with R, tidyverse and mlr”. Padarykite vieną “hold-out” testą ir išveskite klasifikavimo lenteles “confusion matrix” mokymo ir testavimo duomenims.
Užduočiai pasiekti pasirenkami du skirtingi duomenų rinkiniai, patalpinti “UCI Machine Learning Repository” duomenų bazėje. Vienas iš jų – klasikinis rinkodaros banko duomenų rinkinys (“BANK”), kuriame yra turima informacija apie 45 000 asmenis. Kitame duomenų rinkinyje (“ADULT”) rasime informacijos apie maždaug 30 000 asmenų pajamas, kurių metines pajamas lemia įvairūs veiksniai: iššilavinimo lygis, amžius, lytis ir kita.
Reikalingos bibliotekos:
rm(list = ls())
library(caret)
library(mlr)
library(dplyr)
library(tidyr)
library(readxl)
Nuskaitykime pirmą duomenų rinkinį ir jį pavadinkime “bankclient”. Duomenų rinkinį sudaro daugiau nei 45 000 eilučių ir 17 atributų. Ištrinamos nežinomos reikšmės, sudaroma duomenų lentelė ir “dplyr” paketo pagalba parenkamos klasifikavimo uždaviniui reikalingos reikšmės: amžius (age), paskutinė susisiekimo diena (day), sąskaitos likutis (balance), paskutinio skambučio trukmė (duration), kompanijos kontaktų skaičius (campaign), dienų skaičius kurios praėjo nuo paskutinio susisiekimo su klientu iš ankstesnės kompanijos (pdays), ankstesnis kliento kontaktų skaičius (previous), ar klientas sutartį pasirašo ar ne (y). Būtent šis uždavinys ir yra skirtas prognozuoti, ar klientas banke pasirašys terminuotą sutartį ar ne.
bankclient <- read.csv(file = 'C:/Users/Tautvydas/Desktop/DUOMENŲ GAVYBA/bank/bank-full.csv',
stringsAsFactors = FALSE,
strip.white = TRUE,
sep = ';')
data <- bankclient[complete.cases(bankclient), ] #Deleting NA values
str(data)
## 'data.frame': 45211 obs. of 17 variables:
## $ age : int 58 44 33 47 33 35 28 42 58 43 ...
## $ job : chr "management" "technician" "entrepreneur" "blue-collar" ...
## $ marital : chr "married" "single" "married" "married" ...
## $ education: chr "tertiary" "secondary" "secondary" "unknown" ...
## $ default : chr "no" "no" "no" "no" ...
## $ balance : int 2143 29 2 1506 1 231 447 2 121 593 ...
## $ housing : chr "yes" "yes" "yes" "yes" ...
## $ loan : chr "no" "no" "yes" "no" ...
## $ contact : chr "unknown" "unknown" "unknown" "unknown" ...
## $ day : int 5 5 5 5 5 5 5 5 5 5 ...
## $ month : chr "may" "may" "may" "may" ...
## $ duration : int 261 151 76 92 198 139 217 380 50 55 ...
## $ campaign : int 1 1 1 1 1 1 1 1 1 1 ...
## $ pdays : int -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
## $ previous : int 0 0 0 0 0 0 0 0 0 0 ...
## $ poutcome : chr "unknown" "unknown" "unknown" "unknown" ...
## $ y : chr "no" "no" "no" "no" ...
bankdata <- bankclient %>% dplyr::select(age, day, balance, duration, campaign, pdays, previous, y)
bankdata<- as_tibble(bankdata)
bankdata$y<- as.factor(bankdata$y)
str(bankdata)
## tibble [45,211 x 8] (S3: tbl_df/tbl/data.frame)
## $ age : int [1:45211] 58 44 33 47 33 35 28 42 58 43 ...
## $ day : int [1:45211] 5 5 5 5 5 5 5 5 5 5 ...
## $ balance : int [1:45211] 2143 29 2 1506 1 231 447 2 121 593 ...
## $ duration: int [1:45211] 261 151 76 92 198 139 217 380 50 55 ...
## $ campaign: int [1:45211] 1 1 1 1 1 1 1 1 1 1 ...
## $ pdays : int [1:45211] -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
## $ previous: int [1:45211] 0 0 0 0 0 0 0 0 0 0 ...
## $ y : Factor w/ 2 levels "yes","no": 2 2 2 2 2 2 2 2 2 2 ...
Šiek tiek panagrinėkime turimą duomenų rinkinį. Matome, kiekvieno atributo minimalias, makslimalias reikšmes, kvartilius bei mediana. Kaip faktorius klasifikavimo uždaviniui pasirenkamas sutarties pasirašymo kintamasis, kuris gali įgyti taip (yes) – 1, ne (no) – 2.
summary(bankdata)
## age day balance duration
## Min. :18.00 Min. : 1.00 Min. : -8019 Min. : 0.0
## 1st Qu.:33.00 1st Qu.: 8.00 1st Qu.: 72 1st Qu.: 103.0
## Median :39.00 Median :16.00 Median : 448 Median : 180.0
## Mean :40.94 Mean :15.81 Mean : 1362 Mean : 258.2
## 3rd Qu.:48.00 3rd Qu.:21.00 3rd Qu.: 1428 3rd Qu.: 319.0
## Max. :95.00 Max. :31.00 Max. :102127 Max. :4918.0
## campaign pdays previous y
## Min. : 1.000 Min. : -1.0 Min. : 0.0000 yes: 5289
## 1st Qu.: 1.000 1st Qu.: -1.0 1st Qu.: 0.0000 no :39922
## Median : 2.000 Median : -1.0 Median : 0.0000
## Mean : 2.764 Mean : 40.2 Mean : 0.5803
## 3rd Qu.: 3.000 3rd Qu.: -1.0 3rd Qu.: 0.0000
## Max. :63.000 Max. :871.0 Max. :275.0000
bankUntidy <- gather(bankdata, "Variable", "Value", -y)
ggplot(bankUntidy, aes(y, Value)) +
facet_wrap(~ Variable, scales = "free_y") +
geom_boxplot() +
theme_bw()
Vadinamieji box plot grafikai, rodo grafinį skaitinių imties charakteristikų išsidėstymą, kurias galima palyginti. Stačiakampis brėžiamas nuo pirmojo iki trečiojo kvartilio. Stačiakampį į dvi dalis dalija brūkšnys, žymintis medianą. Nuo stačiakampio į viršų ir į apačią brėžiamos dvi tiesių atkarpos: apatinė – iki mažiausios imties reikšmės, o viršutinė – iki didžiausios imties reikšmės. Taip pat galima pastebėti išskirtis.
Sukurkime reikalingą modelį apsibrėždami klasifikatorių ir nurodykime mokymosi imtį. Šį kartą padarykime tai naudodami LDA (Linear Discriminant Analysis)
bankTask <- makeClassifTask(data = bankdata, target = "y")
lda <- makeLearner("classif.lda")
ldaModel <- train(lda, bankTask)
Iš modelio išskaičiuokime reikalingą informaciją pasinaudodami funkcija getLearnerModel() ir gaukime duomenų lentelės reikšmes kiekvienu atveju naudojant prognozavimo funkciją. Matome, kad modelis išmoko vieną diskriminantinę funkciją (DF) – LD1. Prognozės funkcija grąžina šios funkcijos reikšmes kiekvienu atveju mūsų turimo “bankdata” duomenų rinkinio.
ldaModelData <- getLearnerModel(ldaModel)
ldaPreds <- predict(ldaModelData)$x
head(ldaPreds)
## LD1
## 1 -0.0756109
## 2 0.5275920
## 3 0.8983154
## 4 0.6943838
## 5 0.4078993
## 6 0.6246096
Sudarykime QDA (Quadratic Discriminant Analysis) modelį.
qda <- makeLearner("classif.qda")
qdaModel <- train(qda, bankTask)
Patikrinkime, kaip sudaryti modeliai veikia k-fold metodu.
kFold <- makeResampleDesc(method = "RepCV", folds = 10, reps = 50,
stratify = TRUE)
ldaCV <- resample(learner = lda, task = bankTask, resampling = kFold,
measures = list(mmce, acc))
qdaCV <- resample(learner = qda, task = bankTask, resampling = kFold,
measures = list(mmce, acc))
ldaCV$aggr
## mmce.test.mean acc.test.mean
## 0.1117954 0.8882046
qdaCV$aggr
## mmce.test.mean acc.test.mean
## 0.1273663 0.8726337
LDA modelis teisingai klasifikavo vidutiniškai 89% sutarties pasirašymo prognozės, o QDA modeliui, pavyko teisingai klasifikuoti 87%. Išvada, kad LDA klasifikuoja geriau. Patikrinkime, kaip atrodys klasifikavimo lentelės (confusion matrix) ir įvertinkime kaip jie veiks turint naujus duomenis.
calculateConfusionMatrix(ldaCV$pred, relative = TRUE)
## Relative confusion matrix (normalized by row/column):
## predicted
## true yes no -err.-
## yes 0.25/0.55 0.75/0.09 0.75
## no 0.03/0.45 0.97/0.91 0.03
## -err.- 0.45 0.09 0.11
##
##
## Absolute confusion matrix:
## predicted
## true yes no -err.-
## yes 66814 197636 197636
## no 55083 1941017 55083
## -err.- 55083 197636 252719
newclient <- tibble(age = 40, day = 2, balance = 1000, duration = 10, campaign = 3, pdays = -1, previous = 0)
predict(ldaModel, newdata = newclient)
## Prediction: 1 observations
## predict.type: response
## threshold:
## time: 0.00
## response
## 1 no
Modelis prognozuoja, kad naujas klientas terminuotos sutarties nepasirašys!
Papildomai atliekamas hold-out testas.
holdout <- makeResampleDesc(method = "Holdout", split = 2/3,
stratify = TRUE)
lda_holdoutCV <- resample(learner = lda, task = bankTask,
resampling = holdout, measures = list(mmce, acc))
qda_holdoutCV <- resample(learner = qda, task = bankTask,
resampling = holdout, measures = list(mmce, acc))
lda_holdoutCV$aggr
## mmce.test.mean acc.test.mean
## 0.1092827 0.8907173
qda_holdoutCV$aggr
## mmce.test.mean acc.test.mean
## 0.1246765 0.8753235
calculateConfusionMatrix(lda_holdoutCV$pred, relative = TRUE)
## Relative confusion matrix (normalized by row/column):
## predicted
## true yes no -err.-
## yes 0.26/0.57 0.74/0.09 0.74
## no 0.03/0.43 0.97/0.91 0.03
## -err.- 0.43 0.09 0.11
##
##
## Absolute confusion matrix:
## predicted
## true yes no -err.-
## yes 467 1296 1296
## no 351 12957 351
## -err.- 351 1296 1647
Matome, kad atlikus holdout testą LDA klasifikuoja geriau (89%).
Šis duomenų rinkinys yra skirtas prognozuoti, ar asmens pajamos per metus yra didesnės už 50 000 dolerių ar mažesnės. Tai klasifikuoti padeda įvairūs faktoriai apie žmogų. Rinkinyje yra viso 14 atributų ir daugiau nei 32 000 duomenų eilučių (vartotojų). Šiam klasifikavimui naudojami duomenys nuskaitomi R kodu, ištrinamos nežinomos NA reikšmės, sudaroma duomenų lentelė.
adult <- read_excel("DUOMENŲ GAVYBA/adult.xlsx")
str(adult)
## tibble [32,561 x 15] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:32561] 39 50 38 53 28 37 49 52 31 42 ...
## $ workclass : chr [1:32561] "State-gov" "Self-emp-not-inc" "Private" "Private" ...
## $ fnlwgt : num [1:32561] 77516 83311 215646 234721 338409 ...
## $ education : chr [1:32561] "Bachelors" "Bachelors" "HS-grad" "11th" ...
## $ educationnum : num [1:32561] 13 13 9 7 13 14 5 9 14 13 ...
## $ maritalstatus: chr [1:32561] "Never-married" "Married-civ-spouse" "Divorced" "Married-civ-spouse" ...
## $ occupation : chr [1:32561] "Adm-clerical" "Exec-managerial" "Handlers-cleaners" "Handlers-cleaners" ...
## $ relationship : chr [1:32561] "Not-in-family" "Husband" "Not-in-family" "Husband" ...
## $ race : chr [1:32561] "White" "White" "White" "Black" ...
## $ sex : chr [1:32561] "Male" "Male" "Male" "Male" ...
## $ capitalgain : num [1:32561] 2174 0 0 0 0 ...
## $ capitalloss : num [1:32561] 0 0 0 0 0 0 0 0 0 0 ...
## $ hoursperweek : num [1:32561] 40 13 40 40 40 40 16 45 50 40 ...
## $ nativecountry: chr [1:32561] "United-States" "United-States" "United-States" "United-States" ...
## $ income : chr [1:32561] "<=50K" "<=50K" "<=50K" "<=50K" ...
data1 <- adult[complete.cases(adult), ] #Deleting NA values
adultdata <- data1 %>% dplyr::select(age, fnlwgt, educationnum, capitalgain, capitalloss, hoursperweek, income)
adultdata<- as_tibble(adultdata)
adultdata$income<- as.factor(adultdata$income)
str(adultdata)
## tibble [32,561 x 7] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:32561] 39 50 38 53 28 37 49 52 31 42 ...
## $ fnlwgt : num [1:32561] 77516 83311 215646 234721 338409 ...
## $ educationnum: num [1:32561] 13 13 9 7 13 14 5 9 14 13 ...
## $ capitalgain : num [1:32561] 2174 0 0 0 0 ...
## $ capitalloss : num [1:32561] 0 0 0 0 0 0 0 0 0 0 ...
## $ hoursperweek: num [1:32561] 40 13 40 40 40 40 16 45 50 40 ...
## $ income : Factor w/ 2 levels "<=50K",">50K": 1 1 1 1 1 1 1 2 2 2 ...
summary(adultdata)
## age fnlwgt educationnum capitalgain
## Min. :17.00 Min. : 12285 Min. : 1.00 Min. : 0
## 1st Qu.:28.00 1st Qu.: 117827 1st Qu.: 9.00 1st Qu.: 0
## Median :37.00 Median : 178356 Median :10.00 Median : 0
## Mean :38.58 Mean : 189778 Mean :10.08 Mean : 1078
## 3rd Qu.:48.00 3rd Qu.: 237051 3rd Qu.:12.00 3rd Qu.: 0
## Max. :90.00 Max. :1484705 Max. :16.00 Max. :99999
## capitalloss hoursperweek income
## Min. : 0.0 Min. : 1.00 <=50K:24720
## 1st Qu.: 0.0 1st Qu.:40.00 >50K : 7841
## Median : 0.0 Median :40.00
## Mean : 87.3 Mean :40.44
## 3rd Qu.: 0.0 3rd Qu.:45.00
## Max. :4356.0 Max. :99.00
Naudojami atributai: vartotojo amžius (age), pajamų svoris (fnlwgt), mokymosi metai (educationnum), kapitalo prieaugis (capitalgain), kapitalo nuostolis (capitalloss), darbo valandos per savaitę (hoursperweek), pajamos (income). Visi kintamieji kiekybiniai, išskyrus pajamas, kurios gali įgauti dvi reikšmes: arba >50K arba <50K.
Atvaizduojami boxplot grafikai, kad grafiškai būtų matomos įvairios duomenų matematinės charakteristikos.
adultUntidy <- gather(adultdata, "Variable", "Value", -income)
ggplot(adultUntidy, aes(income, Value)) +
facet_wrap(~ Variable, scales = "free_y") +
geom_boxplot() +
theme_bw()
Apibrėžiame pajamų klasifikavimo uždavinį ir sukuriami LDA ir QDA klasifikatoriai. Sukurti klasifikatoriai yra apmokomi.
adultTask <- makeClassifTask(data = adultdata, target = "income")
## Warning in makeTask(type = type, data = data, weights = weights, blocking =
## blocking, : Provided data is not a pure data.frame but from class tbl_df, hence
## it will be converted.
lda <- makeLearner("classif.lda")
ldaModel <- train(lda, adultTask)
ldaModelData <- getLearnerModel(ldaModel)
ldaPreds <- predict(ldaModelData)$x
head(ldaPreds)
## LD1
## 1 0.6933577
## 2 0.1397711
## 3 -0.4135499
## 4 -0.4042299
## 5 0.3283618
## 6 0.8652966
qda <- makeLearner("classif.qda")
qdaModel <- train(qda, adultTask)
Sudaryto modelio validavimas pasinaudojant k-fold metodu.
kFold <- makeResampleDesc(method = "RepCV", folds = 10, reps = 50,
stratify = TRUE)
ldaCV <- resample(learner = lda, task = adultTask, resampling = kFold,
measures = list(mmce, acc))
qdaCV <- resample(learner = qda, task = adultTask, resampling = kFold,
measures = list(mmce, acc))
ldaCV$aggr
## mmce.test.mean acc.test.mean
## 0.1975633 0.8024367
qdaCV$aggr
## mmce.test.mean acc.test.mean
## 0.2036669 0.7963331
LDA modelis teisingai klasifikavo vidutiniškai 80.2% pajamų prognozės, o QDA modeliui, pavyko teisingai klasifikuoti 79.6%. Išvada, kad LDA klasifikuoja geriau.
Patikrinkime, kaip atrodys klasifikavimo lentelės (confusion matrix) ir įvertinkime kaip jie veiks turint naujus duomenis.
calculateConfusionMatrix(ldaCV$pred, relative = TRUE)
## Relative confusion matrix (normalized by row/column):
## predicted
## true <=50K >50K -err.-
## <=50K 0.95/0.82 0.05/0.31 0.05
## >50K 0.67/0.18 0.33/0.69 0.67
## -err.- 0.18 0.31 0.20
##
##
## Absolute confusion matrix:
## predicted
## true <=50K >50K -err.-
## <=50K 1177649 58351 58351
## >50K 263292 128758 263292
## -err.- 263292 58351 321643
newadult <- tibble(age = 40, fnlwgt = 0, educationnum = 1, capitalgain = 0, capitalloss = 1000, hoursperweek = 10)
predict(qdaModel, newdata = newadult)
## Prediction: 1 observations
## predict.type: response
## threshold:
## time: 0.00
## response
## 1 <=50K
Gauname, kad naujo kliento pajamos bus mažesnės arba lygios 50 000 dolerių.
Papildomai atlikime hold-out testą:
holdout <- makeResampleDesc(method = "Holdout", split = 2/3,
stratify = TRUE)
lda_holdoutCV <- resample(learner = lda, task = adultTask,
resampling = holdout, measures = list(mmce, acc))
qda_holdoutCV <- resample(learner = qda, task = adultTask,
resampling = holdout, measures = list(mmce, acc))
lda_holdoutCV$aggr
## mmce.test.mean acc.test.mean
## 0.2013083 0.7986917
qda_holdoutCV$aggr
## mmce.test.mean acc.test.mean
## 0.2057306 0.7942694
calculateConfusionMatrix(lda_holdoutCV$pred, relative = TRUE)
## Relative confusion matrix (normalized by row/column):
## predicted
## true <=50K >50K -err.-
## <=50K 0.95/0.81 0.05/0.33 0.05
## >50K 0.68/0.19 0.32/0.67 0.68
## -err.- 0.19 0.33 0.20
##
##
## Absolute confusion matrix:
## predicted
## true <=50K >50K -err.-
## <=50K 7836 404 404
## >50K 1781 833 1781
## -err.- 1781 404 2185
Matome, kad atlikus holdout testą geriau klasifikuoja LDA (80.4%).