Material explicativo: Machine Learning sob a ótica estatística: Uma abordagem preditivista para estatística com exemplos em R (http://www.rizbicki.ufscar.br/sml)
set.seed(1)
library(data.table)
library(tm)
library(glmnet)
library(tidyverse)
dados <- fread("../../../../mineracaoDeDados/2016_01/notasDeAula/data/Reviews.csv",
header = TRUE,
nrows = 8000)
corp = VCorpus(VectorSource(dados$Text))
dtm = DocumentTermMatrix(corp,
control = list(tolower
= TRUE,
stemming
= FALSE,
removeNumbers
= TRUE,
removePunctuation
= TRUE,
removeStripwhitespace = TRUE,
weighting
= weightTf,
bounds=list(global=c(50, Inf))))
dtm
## <<DocumentTermMatrix (documents: 8000, terms: 1045)>>
## Non-/sparse entries: 279916/8080084
## Sparsity : 97%
## Maximal term length: 13
## Weighting : term frequency (tf)
dtm.matrix <- dtm %>% as.matrix # perdemos esparsidade :(
split <- sample(c("Treinamento",
"Validacao",
"Teste"),prob=c(0.6,0.2,0.2),size = nrow(dados),
replace = TRUE)
riscos <- list()
vc_lasso <- cv.glmnet(dtm.matrix[split=="Treinamento",], dados$Score[split=="Treinamento"],
alpha = 1)
predito_MMQ <- predict(vc_lasso, s = 0,
newx = dtm.matrix[split=="Teste",])
Risco estimado:
riscos$minimos.quadrados <- (predito_MMQ-dados$Score[split=="Teste"])^2 %>% mean
riscos$minimos.quadrados
## [1] 1.607447
plot(vc_lasso)
predito_lasso <- predict(vc_lasso, s = vc_lasso$lambda.min,
newx = dtm.matrix[split=="Teste",])
Risco estimado:
riscos$lasso <- (predito_lasso-dados$Score[split=="Teste"])^2 %>% mean
riscos$lasso
## [1] 1.286448
Quais variáveis foram escolhidas?
table(coef(vc_lasso,s=vc_lasso$lambda.min)[,1]!=0)
##
## FALSE TRUE
## 598 448
coefs_estimates <- coef(vc_lasso,s=vc_lasso$lambda.min)
coefs <- coefs_estimates %>% as.matrix %>% as_tibble
names(coefs)="Estimativa"
coefs %>% mutate(variavel=rownames(coefs_estimates)) %>% arrange(desc(abs(Estimativa)))
## # A tibble: 1,046 x 2
## Estimativa variavel
## <dbl> <chr>
## 1 4.07 (Intercept)
## 2 -1.18 worst
## 3 -1.10 terrible
## 4 -0.906 awful
## 5 -0.763 waste
## 6 -0.711 disappointed
## 7 -0.606 weak
## 8 -0.526 avoid
## 9 -0.516 return
## 10 -0.507 worse
## # ... with 1,036 more rows
library(ggpubr)
theme_set(theme_gray(base_size = 18))
coefs_estimates <- coef(vc_lasso,s=vc_lasso$lambda.min)
coefs_estimates = data.frame(Palavra = rownames(coefs_estimates), Coeficientes = coefs_estimates[,1])
coef_pos = coefs_estimates %>% arrange(desc(Coeficientes))
coef_neg = coefs_estimates %>% arrange(Coeficientes)
graf_pos = ggplot(data = coef_pos[2:30,],
aes(x = reorder(Palavra, Coeficientes), y = Coeficientes)) +
geom_bar(stat="identity", col = "white", fill = "dodgerblue1") + coord_flip() +
xlab("") + ylab("Estimativa") + ggtitle("Coeficientes Positivos")
graf_neg = ggplot(data = coef_neg[2:30,], aes(x = reorder(Palavra, -Coeficientes), y = Coeficientes)) +
geom_bar(stat="identity", col = "white", fill = "firebrick4") + coord_flip() +
xlab("Termo") + ylab("Estimativa") + ggtitle("Coeficientes Negativos")
ggarrange(graf_neg, graf_pos, ncol = 2, nrow = 1)
library(FNN)
k.grid <- round(seq(1,50,length.out = 10))
erro <- rep(NA,length(k.grid))
for(ii in seq_along(k.grid))
{
predito <- knn.reg(train=dtm.matrix[split=="Treinamento",],
y=dados$Score[split=="Treinamento"],
k=k.grid[ii])$pred
erro[ii] <- mean((predito-dados$Score[split=="Treinamento"])^2)
}
plot(k.grid,erro)
best.k <- k.grid[which.min(erro)]
predito <- knn.reg(train=dtm.matrix[split=="Treinamento",],
test = dtm.matrix[split=="Teste",],
y=dados$Score[split=="Treinamento"],
k=best.k)$pred
riscos$knn <- (predito-dados$Score[split=="Teste"])^2 %>% mean
riscos$knn
## [1] 1.564783
library(rpart)
library(rpart.plot)
dados.tudo <- dtm.matrix %>% as.data.frame %>% mutate(Score=dados$Score)
# ajuste da arvore
arvore = rpart(Score ~.,
data = dados.tudo[split=="Treinamento",])
# poda
melhorCp = arvore$cptable[which.min(arvore$cptable[,"xerror"]),
"CP"]
poda = prune(arvore, cp = melhorCp)
# arvore
rpart.plot(poda, type = 4)
# predito árvore
predito_arvore = predict(poda,
dados.tudo[split=="Teste", ])
riscos$arvores <- (predito_arvore-dados$Score[split=="Teste"])^2 %>% mean
riscos$arvores
## [1] 1.580799
library(randomForest)
names(dados.tudo) <- make.names(names(dados.tudo))
# floresta aleatória
floresta = randomForest(Score ~.,
data = dados.tudo[split=="Treinamento",],
ntree = 100)
# predito floresta
predito_floresta = predict(floresta,
dados.tudo[split=="Teste", ])
varImpPlot(floresta)
riscos$florestas <- (predito_floresta-dados$Score[split=="Teste"])^2 %>% mean
riscos$florestas
## [1] 1.322329
library(knitr)
kable(as.matrix(unlist(riscos)),row.names = TRUE,digits=3)
minimos.quadrados | 1.607 |
lasso | 1.286 |
knn | 1.565 |
arvores | 1.581 |
florestas | 1.322 |
riscos <- list()
Definindo a variável resposta
dados$Bom <- ifelse(dados$Score>=4,"Bom",
"Ruim")
vc_glm.lasso <- cv.glmnet(dtm.matrix[split=="Treinamento",], dados$Bom[split=="Treinamento"], alpha=1,family="binomial")
predito_logistica <- predict(vc_glm.lasso, s = 0,
newx = dtm.matrix[split=="Teste",],type="response")
hist(predito_logistica)
Avaliando o risco
classe_log <- ifelse(predito_logistica<1/2,"Bom","Ruim")
riscos$logistica <-mean(classe_log!=dados$Bom[split=="Teste"])
riscos$logistica
## [1] 0.2292909
table(classe_log,dados$Bom[split=="Teste"])
##
## classe_log Bom Ruim
## Bom 959 172
## Ruim 174 204
vc_lm.lasso <- cv.glmnet(dtm.matrix[split=="Treinamento",], dados$Bom[split=="Treinamento"]=="Bom", alpha=1)
predito_linear <- predict(vc_lm.lasso, s = 0,
newx = dtm.matrix[split=="Teste",],type="response")
hist(predito_linear)
Avaliando o risco
classe_lin <- ifelse(predito_linear>1/2,"Bom","Ruim")
riscos$linear <-mean(classe_lin!=dados$Bom[split=="Teste"])
riscos$linear
## [1] 0.1868787
table(classe_lin,dados$Bom[split=="Teste"])
##
## classe_lin Bom Ruim
## Bom 1038 187
## Ruim 95 189
predito_logistica.p <- predict(vc_glm.lasso, s = vc_glm.lasso$lambda.min,
newx = dtm.matrix[split=="Teste",],type="response")
classe_log.p <- ifelse(predito_logistica.p<1/2,"Bom","Ruim")
riscos$logisitica.penalizada <-mean(classe_log.p!=dados$Bom[split=="Teste"])
riscos$logisitica.penalizada
## [1] 0.1802518
table(classe_log.p,dados$Bom[split=="Teste"])
##
## classe_log.p Bom Ruim
## Bom 1072 211
## Ruim 61 165
predito_linear.p <- predict(vc_lm.lasso, s = vc_lm.lasso$lambda.min,
newx = dtm.matrix[split=="Teste",],type="response")
classe_lin.p <- ifelse(predito_linear.p>1/2,"Bom","Ruim")
riscos$linear.penalizado <-mean(classe_lin.p!=dados$Bom[split=="Teste"])
riscos$linear.penalizado
## [1] 0.1935056
table(classe_lin.p,dados$Bom[split=="Teste"])
##
## classe_lin.p Bom Ruim
## Bom 1092 251
## Ruim 41 125
library(e1071)
n.b <- naiveBayes(x=dtm.matrix[split=="Treinamento",],y=as.factor(dados$Bom[split=="Treinamento"]))
predito_n.b <- predict(n.b,dtm.matrix[split=="Teste",])
riscos$naive.bayes <-mean(predito_n.b!=dados$Bom[split=="Teste"])
riscos$naive.bayes
## [1] 0.2485089
table(predito_n.b,dados$Bom[split=="Teste"])
##
## predito_n.b Bom Ruim
## Bom 919 161
## Ruim 214 215
dados.tudo <- as.data.frame(dtm.matrix %>% as.data.frame %>% mutate(Bom=as.factor(dados$Bom)))
# ajuste da arvore
arvore = rpart(Bom ~., method = "class",
data = dados.tudo[split=="Treinamento",])
predito_arvore = predict(arvore, dados.tudo[split=="Teste",],type="class")
riscos$arvore <-mean(predito_arvore!=dados$Bom[split=="Teste"])
riscos$arvore
## [1] 0.2491716
table(predito_arvore,dados$Bom[split=="Teste"])
##
## predito_arvore Bom Ruim
## Bom 1133 376
## Ruim 0 0
Problema: classe muito desbalanceada!
mean(dados$Bom[split=="Teste"]=="Ruim")
## [1] 0.2491716
Alternativa: usar floresta de regressão para estimar \(P(\mbox{Bom}|x)\).
names(dados.tudo) <- make.names(names(dados.tudo))
# floresta aleatória
floresta = randomForest(Bom ~., method = "class",data = dados.tudo[split=="Treinamento",])
varImpPlot(floresta)
# predito floresta
predito_floresta = predict(floresta, dados.tudo[split=="Teste",])
table(predito_floresta)
## predito_floresta
## Bom Ruim
## 1426 83
riscos$floresta <-mean(predito_floresta!=dados$Bom[split=="Teste"])
riscos$floresta
## [1] 0.2113983
table(predito_floresta,dados$Bom[split=="Teste"])
##
## predito_floresta Bom Ruim
## Bom 1120 306
## Ruim 13 70
k.grid <- round(seq(1,50,length.out = 10))
erro <- rep(NA,length(k.grid))
for(ii in seq_along(k.grid))
{
predito <- knn.cv(train=dtm.matrix[split=="Treinamento",], cl=dados$Bom[split=="Treinamento"],k=k.grid[ii])[1:sum(split=="Treinamento")]
erro[ii] <- mean((predito!=dados$Bom[split=="Treinamento"]))
}
plot(k.grid,erro)
best.k <- k.grid[which.min(erro)]
predito <- knn(train=dtm.matrix[split=="Treinamento",],cl=dados$Bom[split=="Treinamento"],
test = dtm.matrix[split=="Teste",],
k=best.k)
riscos$knn <- mean(predito!=dados$Bom[split=="Teste"])
riscos$knn
## [1] 0.2432074
table(predito,dados$Bom[split=="Teste"])
##
## predito Bom Ruim
## Bom 1115 349
## Ruim 18 27
set.seed(1)
dados <- fread("../../../../mineracaoDeDados/2016_01/notasDeAula/data/Reviews.csv",
header = TRUE,
nrows = 100000)
corp = VCorpus(VectorSource(dados$Text))
dtm = DocumentTermMatrix(corp,
control = list(tolower
= TRUE,
stemming
= FALSE,
removeNumbers
= TRUE,
removePunctuation
= TRUE,
removeStripwhitespace = TRUE,
weighting
= weightTf,
bounds=list(global=c(50, Inf))))
dtm
## <<DocumentTermMatrix (documents: 100000, terms: 5640)>>
## Non-/sparse entries: 4392634/559607366
## Sparsity : 99%
## Maximal term length: 15
## Weighting : term frequency (tf)
Proporção do teste menor!
split <- sample(c("Treinamento",
"Validacao",
"Teste"),prob=c(0.9,0.05,0.05),size = nrow(dados),
replace = TRUE)
table(split)
## split
## Teste Treinamento Validacao
## 4997 89973 5030
Converter para formato esparso aceito pelo xgboost.
library(Matrix)
nomes.variaveis=colnames(dtm)
dtm <- sparseMatrix(i=dtm$i, j=dtm$j, x=dtm$v, dims=c(dtm$nrow, dtm$ncol))
dados$Bom <- as.numeric(dados$Score>=4)
library(xgboost)
bstCV = xgb.cv(data = dtm[split=="Treinamento",],
label = dados$Bom[split=="Treinamento"],
nthread
= 7, nround
= 2000,
nfold
= 4, metrics = "error",
objective = "binary:logistic",
lambda
= .01, verbose = FALSE)
bst = xgboost(data = dtm[split=="Treinamento",],
label = dados$Bom[split=="Treinamento"], nthread = 7,
nround = which.min(bstCV$evaluation_log$test_error_mean),
objective = "binary:logistic", verbose = FALSE,
lambda = 0.01)
#saveRDS(bst,file = "bst.RDS")
#bst=loadRDS(file = "bst.RDS")
importance_matrix=xgb.importance(nomes.variaveis, model = bst)[1:20,]
xgb.plot.importance(importance_matrix)
predicoes= predict(bst, dtm[split=="Teste",])
predito_bst = as.numeric(predicoes >1/2)
riscos$xgboost <- mean(predito_bst!=dados$Bom[split=="Teste"])
table(predito_bst,dados$Bom[split=="Teste"])
##
## predito_bst 0 1
## 0 836 184
## 1 321 3656
riscos$xgboost
## [1] 0.1010606
Aumentar \(n\) para a logística não é tão importante, mas para um método não paramétrico sim!
library(knitr)
kable(as.matrix(unlist(riscos)),row.names = TRUE,digits=3)
logistica | 0.229 |
linear | 0.187 |
logisitica.penalizada | 0.180 |
linear.penalizado | 0.194 |
naive.bayes | 0.249 |
arvore | 0.249 |
floresta | 0.211 |
knn | 0.243 |
xgboost | 0.101 |