blob: 31edf3ac17859ac0d3a1a9abb53595eb36db9c66 [file] [log] [blame]
Marc Kupietzc3bf3502021-02-19 17:18:57 +01001library(caret)
2library(tidyverse)
3library(DMwR)
4library(randomForest)
5library(FSelector)
6# library(randomForestExplainer)
7# may need to: options(expressions = 5e5) to avoid stackoverflow for installing package
8
PeterFankhauserIDSed93d2e2021-02-20 14:51:13 +01009# Test
10
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010011ngramfile<-"gold03_anno_ml_synfeat_nstopw"
12
Marc Kupietzc3bf3502021-02-19 17:18:57 +010013setwd(dirname(rstudioapi::getSourceEditorContext()$path))
14stopwords <- readLines(con = "../data/stopwords.txt",encoding="UTF-8")
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010015oringramme <- read.csv(paste("../data/",ngramfile,".csv",sep=""), header = TRUE, sep = "\t", dec=".", quote="", encoding="UTF-8",stringsAsFactors=FALSE)
Marc Kupietzc3bf3502021-02-19 17:18:57 +010016syfeaturenames <- read.csv("../data/syfeatures.tsv", header = TRUE, sep = "\t", dec=".", quote="", encoding="UTF-8",stringsAsFactors=FALSE)
17# syfeaturenames$navalue<-sapply(syfeaturenames$navalue,as.numeric)
18
19deleteStopwords = function(wl, stopwords = NULL) {
20 wl[!(wl %in% stopwords)]
21}
22
Marc Kupietz631800f2021-02-19 17:27:26 +010023oringramme <- oringramme %>%
24 filter(CO_IDIOM < 2) # just two classes: 0 no idiom, 1 idiom
25
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010026# Reduce number of classes, treat null values, add NSTOPW, change names for SY features
27
Marc Kupietzc3bf3502021-02-19 17:18:57 +010028ngramme <- oringramme %>%
29 add_column(NSTOPW = sapply(oringramme$tokens,function(x) length(deleteStopwords(tolower(unlist(strsplit(x," "))),stopwords)))) %>%
30 # select(-matches("CO_TOKEN.*"), -tokens) %>%
31 select(-matches("CO_TOKEN.*")) %>% # keep tokens for interpretability
32 mutate(across(matches(".rank.*"), ~ replace_na(.x, 1000))) %>%
33 mutate(across(c("dice", "lfmd", "llr", "ld", "pmi"), ~ replace_na(.x, min(.x) - 1))) %>%
Marc Kupietzaced2702021-02-19 19:09:29 +010034 rename_at(syfeaturenames$innames, ~ syfeaturenames[syfeaturenames$innames==.x,]$synames ) %>%
Marc Kupietzc3bf3502021-02-19 17:18:57 +010035 mutate(across(everything(), ~ replace_na(.x, 0))) %>%
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010036 mutate(CO_IDIOM = as.factor(if_else(CO_IDIOM !=1, "0", "1"))) # just two classes: 0 no idiom, 1 idiom
37
38# Optional
39write.table(ngramme,file=paste("../data/",ngramfile,"_cosy.csv",sep=""), sep = "\t", quote=F)
40
41# featuresets
Marc Kupietzc3bf3502021-02-19 17:18:57 +010042
43covars <- c("CO_LL", "CO_Z", "CO_G", "CO_T", "CO_LOGDICE", "CO_PMI", "CO_MI3", "CO_DEREKO", "CO_SGT", "CO_WIN5_VEC","CO_WIN5_VEC_AUTOSEM")
44syvars <- c(syfeaturenames$synames,"NSTOPW")
45vars <- c(covars,syvars)
46
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010047# formulae for training and testing rf
48
Marc Kupietzc3bf3502021-02-19 17:18:57 +010049fmla <- as.formula(paste("CO_IDIOM ~ ", paste(vars, collapse= "+")))
50fmlaco <- as.formula(paste("CO_IDIOM ~ ", paste(covars, collapse= "+")))
51fmlasy <- as.formula(paste("CO_IDIOM ~ ", paste(syvars, collapse= "+")))
52
53# Simple train/test split
54
55trainRows <- sample(nrow(ngramme), nrow(ngramme)*0.8, replace = FALSE)
56train <- ngramme[trainRows,]
57test <- ngramme[setdiff(1:nrow(ngramme),trainRows),]
58
59rf_classifier = randomForest(fmla, train, ntree=100, mtry=10, importance=TRUE)
60
61# only SY features
62# rf_classifier = randomForest(fmlasy, train, ntree=100, mtry=10, importance=TRUE)
63
64prediction_for_table <- predict(rf_classifier, test %>% select(-CO_IDIOM))
65
66# different cutoff for prediction
67# prediction_for_table <- predict(rf_classifier, test %>% select(-CO_IDIOM), cutoff = c(0.8, 0.2))
68
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010069confusion <- table(observed=test$CO_IDIOM,predicted=prediction_for_table)
70conf <- confusionMatrix(confusion, positive= "1")
Marc Kupietzc3bf3502021-02-19 17:18:57 +010071print(conf)
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010072# Sensitivity is precision of class 1
73# Pos Pred Value is recall
Marc Kupietzc3bf3502021-02-19 17:18:57 +010074varImpPlot(rf_classifier)
75
76# optional resampling with smote
77
78smoted.data <- SMOTE(fmla, subset(train, select = c("CO_IDIOM", vars)), perc.over = 1200, perc.under = 100)
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010079rf_classifier = randomForest(fmla, smoted.data, ntree=100, mtry=10, importance=TRUE)
80prediction_for_table <- predict(rf_classifier,test %>% select(-CO_IDIOM))
81confusion <- table(observed=test$CO_IDIOM,predicted=prediction_for_table)
Marc Kupietz0932a782021-02-19 17:39:47 +010082conf <- confusionMatrix(confusion, positive = "1")
83print(conf)
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010084
Marc Kupietzc3bf3502021-02-19 17:18:57 +010085# Using estimates by random forest on entire dataset
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010086
Marc Kupietzc3bf3502021-02-19 17:18:57 +010087library(randomForest)
88rf_classifier_full = randomForest(fmla, data=ngramme, ntree=100, mtry=2, importance=TRUE, cutoff=c(0.8,0.2))
89rf_classifier_full
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +010090# class.error is 1 - recall
Marc Kupietzc3bf3502021-02-19 17:18:57 +010091varImpPlot(rf_classifier_full)
92
93# Feature ranking
94
95# rf features as table
96
97# correlated features seem to split their rankings
98
99rfranks<-importance(rf_classifier_full)[,3:4]
100
101# ttest
102
103idioms<-ngramme %>% filter(CO_IDIOM==1)
104nonidioms<-ngramme %>% filter(CO_IDIOM!=1)
105
106ttestPvalues<-sapply(vars,
107 function(sel) t.test(idioms[sel],nonidioms[sel])$p.value)
108
109# information gain
110# multiply by 1000 to avoid undersized bins
111# features are ranked individually not matter their correlation
112igain<-information.gain(fmla, data=ngramme%>%mutate_at(vars, ~ . * 1000),unit="log2")
113
114featureRanks<-cbind(rfranks,igain,ttestPvalues)
115
116#randomForestExplainer::explain_forest(rf_classifier )
117
118# averate estimates and feature ranks over 10 runs
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +0100119
Marc Kupietzc3bf3502021-02-19 17:18:57 +0100120errrate<-0
121conf<-matrix(0,2,3)
122featureRanks<-matrix(0,4,length(vars))
123for (i in 1:10) {
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +0100124 rfc =randomForest(fmla, data=ngramme, ntree=100, importance=TRUE)
125 #rfc =randomForest(fmla, data=ngramme, ntree=100, importance=TRUE, cutoff=c(0.8,0.2))
Marc Kupietzc3bf3502021-02-19 17:18:57 +0100126 errrate<-errrate+rfc$err.rate[100,1]
127 conf<-conf+rfc$confusion
128 featureRanks<-featureRanks+
129 cbind(importance(rfc)[,3:4],
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +0100130 information.gain(fmla, data=ngramme%>%mutate_at(vars, ~ . * 1000),unit="log2"),
Marc Kupietzc3bf3502021-02-19 17:18:57 +0100131 sapply(vars,
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +0100132 function(sel) t.test(idioms[sel],nonidioms[sel])$p.value))
Marc Kupietzc3bf3502021-02-19 17:18:57 +0100133 print(errrate/i)
134 conf1<-round(
135 rbind(
136 cbind(conf[,1:2]/i,(1-conf[,3]/i)*100),
137 c(100*diag(conf[,1:2])/colSums(conf[,1:2]),NA),
138 c(rowSums(conf[,1:2]/i),NA)),digits=2)
139 colnames(conf1)<-c("0","1","rec")
140 rownames(conf1)<-c("0","1","prec","sum")
141 print(conf1)
142}
143featureRanks<-featureRanks/10
PeterFankhauserIDSd1f3df82021-02-20 14:44:01 +0100144colnames(featureRanks)<-c("MeanDecreaseAccuracy","MeanDecreaseGini","InformationGain","Ttest")
Marc Kupietzc3bf3502021-02-19 17:18:57 +0100145
146
147
148