blob: 82516a300d1214e66c079abd60fae3b11f10057b [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
9setwd(dirname(rstudioapi::getSourceEditorContext()$path))
10stopwords <- readLines(con = "../data/stopwords.txt",encoding="UTF-8")
11oringramme <- read.csv("../data/gold03_anno_ml_synfeat_nstopw.csv", header = TRUE, sep = "\t", dec=".", quote="", encoding="UTF-8",stringsAsFactors=FALSE)
12syfeaturenames <- read.csv("../data/syfeatures.tsv", header = TRUE, sep = "\t", dec=".", quote="", encoding="UTF-8",stringsAsFactors=FALSE)
13# syfeaturenames$navalue<-sapply(syfeaturenames$navalue,as.numeric)
14
15deleteStopwords = function(wl, stopwords = NULL) {
16 wl[!(wl %in% stopwords)]
17}
18
Marc Kupietz631800f2021-02-19 17:27:26 +010019oringramme <- oringramme %>%
20 filter(CO_IDIOM < 2) # just two classes: 0 no idiom, 1 idiom
21
Marc Kupietzc3bf3502021-02-19 17:18:57 +010022ngramme <- oringramme %>%
23 add_column(NSTOPW = sapply(oringramme$tokens,function(x) length(deleteStopwords(tolower(unlist(strsplit(x," "))),stopwords)))) %>%
24 # select(-matches("CO_TOKEN.*"), -tokens) %>%
25 select(-matches("CO_TOKEN.*")) %>% # keep tokens for interpretability
26 mutate(across(matches(".rank.*"), ~ replace_na(.x, 1000))) %>%
27 mutate(across(c("dice", "lfmd", "llr", "ld", "pmi"), ~ replace_na(.x, min(.x) - 1))) %>%
28 rename_at(syfeatures$innames, ~ syfeatures[syfeatures$innames==.x,]$synames ) %>%
29 mutate(across(everything(), ~ replace_na(.x, 0))) %>%
Marc Kupietz631800f2021-02-19 17:27:26 +010030 mutate(CO_IDIOM = as.factor(if_else(CO_IDIOM !=1, "0", "1")))
Marc Kupietzc3bf3502021-02-19 17:18:57 +010031
32covars <- 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")
33syvars <- c(syfeaturenames$synames,"NSTOPW")
34vars <- c(covars,syvars)
35
36fmla <- as.formula(paste("CO_IDIOM ~ ", paste(vars, collapse= "+")))
37fmlaco <- as.formula(paste("CO_IDIOM ~ ", paste(covars, collapse= "+")))
38fmlasy <- as.formula(paste("CO_IDIOM ~ ", paste(syvars, collapse= "+")))
39
40# Simple train/test split
41
42trainRows <- sample(nrow(ngramme), nrow(ngramme)*0.8, replace = FALSE)
43train <- ngramme[trainRows,]
44test <- ngramme[setdiff(1:nrow(ngramme),trainRows),]
45
46rf_classifier = randomForest(fmla, train, ntree=100, mtry=10, importance=TRUE)
47
48# only SY features
49# rf_classifier = randomForest(fmlasy, train, ntree=100, mtry=10, importance=TRUE)
50
51prediction_for_table <- predict(rf_classifier, test %>% select(-CO_IDIOM))
52
53# different cutoff for prediction
54# prediction_for_table <- predict(rf_classifier, test %>% select(-CO_IDIOM), cutoff = c(0.8, 0.2))
55
Marc Kupietz0932a782021-02-19 17:39:47 +010056confusion <- table(predicted=prediction_for_table, observed=test$CO_IDIOM)
57conf <- confusionMatrix(confusion, positive = "1")
Marc Kupietzc3bf3502021-02-19 17:18:57 +010058print(conf)
59varImpPlot(rf_classifier)
60
61# optional resampling with smote
62
63smoted.data <- SMOTE(fmla, subset(train, select = c("CO_IDIOM", vars)), perc.over = 1200, perc.under = 100)
Marc Kupietz7049c742021-02-19 17:42:06 +010064rf_classifier = randomForest(fmla, smoted.data, ntree=200, importance=TRUE)
65prediction_for_table <- predict(rf_classifier,test %>% select(-CO_IDIOM), cutoff=c(0.8,0.2))
Marc Kupietz0932a782021-02-19 17:39:47 +010066confusion <- table(predicted=prediction_for_table, observed=test$CO_IDIOM)
67conf <- confusionMatrix(confusion, positive = "1")
68print(conf)
Marc Kupietzc3bf3502021-02-19 17:18:57 +010069# Using estimates by random forest on entire dataset
Marc Kupietzc3bf3502021-02-19 17:18:57 +010070library(randomForest)
71rf_classifier_full = randomForest(fmla, data=ngramme, ntree=100, mtry=2, importance=TRUE, cutoff=c(0.8,0.2))
72rf_classifier_full
73varImpPlot(rf_classifier_full)
74
75# Feature ranking
76
77# rf features as table
78
79# correlated features seem to split their rankings
80
81rfranks<-importance(rf_classifier_full)[,3:4]
82
83# ttest
84
85idioms<-ngramme %>% filter(CO_IDIOM==1)
86nonidioms<-ngramme %>% filter(CO_IDIOM!=1)
87
88ttestPvalues<-sapply(vars,
89 function(sel) t.test(idioms[sel],nonidioms[sel])$p.value)
90
91# information gain
92# multiply by 1000 to avoid undersized bins
93# features are ranked individually not matter their correlation
94igain<-information.gain(fmla, data=ngramme%>%mutate_at(vars, ~ . * 1000),unit="log2")
95
96featureRanks<-cbind(rfranks,igain,ttestPvalues)
97
98#randomForestExplainer::explain_forest(rf_classifier )
99
100# averate estimates and feature ranks over 10 runs
101errrate<-0
102conf<-matrix(0,2,3)
103featureRanks<-matrix(0,4,length(vars))
104for (i in 1:10) {
105 # rfc =randomForest(fmla, data=ngramme, ntree=100, importance=TRUE)
106 rfc =randomForest(fmla, data=ngramme, ntree=100, importance=TRUE, cutoff=c(0.8,0.2))
107 errrate<-errrate+rfc$err.rate[100,1]
108 conf<-conf+rfc$confusion
109 featureRanks<-featureRanks+
110 cbind(importance(rfc)[,3:4],
111 sapply(vars,
112 function(sel) t.test(idioms[sel],nonidioms[sel])$p.value),
113 information.gain(fmla, data=ngramme%>%mutate_at(vars, ~ . * 1000),unit="log2"))
114 print(errrate/i)
115 conf1<-round(
116 rbind(
117 cbind(conf[,1:2]/i,(1-conf[,3]/i)*100),
118 c(100*diag(conf[,1:2])/colSums(conf[,1:2]),NA),
119 c(rowSums(conf[,1:2]/i),NA)),digits=2)
120 colnames(conf1)<-c("0","1","rec")
121 rownames(conf1)<-c("0","1","prec","sum")
122 print(conf1)
123}
124featureRanks<-featureRanks/10
125
126
127
128