alcuni codici di esempio per generare la matrice di predittori a partire dai tweets
# scaricato da http://46.51.205.81/dump_tweets/any_ita/
train=read.csv("dataset/train.csv",numerals="no.loss")
str(train)
## 'data.frame': 4513 obs. of 6 variables:
## $ id : Factor w/ 4499 levels "125485104863780865",..: 3137 940 3216 1167 2416 2173 3496 1693 3947 3856 ...
## $ tweet : Factor w/ 4494 levels ":') ❤ ❤ ❤ :')",..: 1579 914 157 2328 94 3090 1503 784 3173 2514 ...
## $ soggettivo: logi TRUE TRUE FALSE FALSE TRUE FALSE ...
## $ positivo : logi FALSE FALSE FALSE FALSE TRUE FALSE ...
## $ negativo : logi TRUE TRUE FALSE FALSE FALSE FALSE ...
## $ ironico : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
test=read.csv("dataset/test.csv",numerals="no.loss")
str(test)
## 'data.frame': 1935 obs. of 2 variables:
## $ id : Factor w/ 1930 levels "122449983151669248",..: 862 1240 1506 460 1464 1823 602 1288 1750 185 ...
## $ tweet: Factor w/ 1929 levels "08 aprile 2011 - 08 aprile 2012. La mia vita è cambiata completamente. #unannodiFreaks <3",..: 610 512 685 507 679 1782 1133 1423 918 1178 ...
names(train)
## [1] "id" "tweet" "soggettivo" "positivo" "negativo"
## [6] "ironico"
test=data.frame(test,soggettivo=NA,positivo=NA,negativo=NA,ironico=NA)
tweets=rbind(train,test)
names(tweets)[2]="TEXT"
rm(train,test)
nchars= sapply(as.vector(tweets$TEXT),nchar)
nchars=as.vector(nchars)
boxplot(nchars~tweets$soggettivo,col=2:3)
t.test(nchars~tweets$soggettivo)
##
## Welch Two Sample t-test
##
## data: nchars by tweets$soggettivo
## t = -0.67863, df = 2440.6, p-value = 0.4974
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -2.866498 1.392550
## sample estimates:
## mean in group FALSE mean in group TRUE
## 100.6152 101.3522
boxplot(nchars~tweets$positivo,col=2:3)
t.test(nchars~tweets$positivo)
##
## Welch Two Sample t-test
##
## data: nchars by tweets$positivo
## t = 4.8761, df = 2141.3, p-value = 1.162e-06
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 3.385346 7.940279
## sample estimates:
## mean in group FALSE mean in group TRUE
## 102.76498 97.10217
boxplot(nchars~tweets$negativo,col=2:3)
t.test(nchars~tweets$negativo)
##
## Welch Two Sample t-test
##
## data: nchars by tweets$negativo
## t = -10.925, df = 4457.9, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -12.619791 -8.779747
## sample estimates:
## mean in group FALSE mean in group TRUE
## 96.39968 107.09945
pare essere interessante, lo teniamo come predittore
Si possono seguire molte strade, ovviamente.
Trovate una accurata review qui (chi vuole approfondire poi condifida anche): http://sentiment.christopherpotts.net/
library(TextWiller)
## Loading required package: stringr
## Loading required package: twitteR
## Loading required package: RCurl
## Loading required package: bitops
## Loading required package: SnowballC
tweets$TEXT=iconv(tweets$TEXT,to="UTF-8")
tweets$TEXTorig=tweets$TEXT
tweets$TEXT=normalizzaemote(tweets$TEXT)
length(grep("EMOTE",tweets$TEXT))
## [1] 414
tweets$TEXT=gsub("…","",tweets$TEXT)
tweets$TEXT=normalizzaTesti(tweets$TEXT,contaStringhe = c("\\?","\\!","@","#","(\u20AC|euro)","(\\$|dollar)"))
Salvo i conteggi delle parole specificate come matrice a parte
conteggi_caratteri=as.data.frame(attributes(tweets$TEXT)$ counts)
faccio a mano alcuni preprocessamenti che possono essereq sfuggiti, elimino a questo punto i # degli hastag (questo sono già stati contati sopra). Mi aiuto anche con l’anali degli n-grammi (vedi codice commentato)
############ ricerca n-grammi più frequenti
# install.packages("tau")
# require(tau)
#
# bigrams <- textcnt(tweets$TEXT,method="string",n=2L,split="[[:blank:]]")
# sort(bigrams,decreasing=TRUE)[1:10]
# sort(bigrams[grep("^stadio",names(bigrams))],decreasing=TRUE)[1:10]
# trigrams <- textcnt(tweets$TEXT,method="string",n=3L,split="[[:blank:]]")
# sort(trigrams,decreasing=TRUE)[1:10]
tweets$TEXT <- gsub("#", "", tweets$TEXT)
tweets$TEXT=removeStopwords(tweets$TEXT, stopwords = c(itastopwords,"…"))
tweets$TEXT <- gsub("( |^)piu( |$)", " più ", tweets$TEXT)
tweets$TEXT <- gsub("perch쎩", "perché", tweets$TEXT)
# tweets$TEXT <- gsub("tweet not available", "tweet_not_available", tweets$TEXT)
tweets$TEXT <- gsub("mario monti", "mario_monti", tweets$TEXT)
tweets$TEXT <- gsub("governo monti", "governo_monti", tweets$TEXT)
tweets$TEXT <- gsub("professor monti", "professor_monti", tweets$TEXT)
(= una riga per tweet, una colonna per ogni parola)
library(tm)
## Loading required package: NLP
corpus <- Corpus(VectorSource(tweets$TEXT))
data(itastopwords)
#Elenco di parole aggiuntive caricate con TextWiller
dtm <- as.matrix(DocumentTermMatrix(corpus
, control = list( stemming = FALSE, stopwords = itastopwords,
minWordLength = 2, removeNumbers = TRUE,
removePunctuation = FALSE, bounds=list(local = c(1,Inf)) ))
) #dictionary=
# tweets=tweets[ids,]
Aggiungo alla dtm i conteggi della parole generale in fare di normalizzazione
dtm=cbind(dtm,conteggi_caratteri)
controllo che non ci siano colonne costantemente 0.
which(colSums(dtm)==0)
## named integer(0)
ok.
Dimensione della dtm
dim(dtm)
## [1] 6448 15283
lo useremo come predittore in futuro
sent=sentiment(tweets$TEXT)
tweets$sent=sent
prop.table(table(tweets$sent,exclude = NULL))
##
## -1 0 1 <NA>
## 0.3070720 0.3334367 0.3594913 0.0000000
barplot(table(tweets$sent),col=2:4)
tab=table(tweets$sent,tweets$soggettivo)
prop.table(tab,1)
##
## FALSE TRUE
## -1 0.2226225 0.7773775
## 0 0.3811075 0.6188925
## 1 0.2402516 0.7597484
mosaicplot(tab,col=1:2)
chisq.test(tab)
##
## Pearson's Chi-squared test
##
## data: tab
## X-squared = 112.13, df = 2, p-value < 2.2e-16
tab=table(tweets$sent,tweets$positivo)
prop.table(tab,1)
##
## FALSE TRUE
## -1 0.8602305 0.1397695
## 0 0.7706840 0.2293160
## 1 0.5308176 0.4691824
mosaicplot(tab,col=1:2)
chisq.test(tab)
##
## Pearson's Chi-squared test
##
## data: tab
## X-squared = 430.52, df = 2, p-value < 2.2e-16
tab=table(tweets$sent,tweets$negativo)
prop.table(tab,1)
##
## FALSE TRUE
## -1 0.3609510 0.6390490
## 0 0.6071661 0.3928339
## 1 0.6786164 0.3213836
mosaicplot(tab,col=1:2)
chisq.test(tab)
##
## Pearson's Chi-squared test
##
## data: tab
## X-squared = 327.1, df = 2, p-value < 2.2e-16
tab=table(tweets$sent,tweets$ironico)
prop.table(tab,1)
##
## FALSE TRUE
## -1 0.8674352 0.1325648
## 0 0.8794788 0.1205212
## 1 0.8748428 0.1251572
mosaicplot(tab,col=1:2)
chisq.test(tab)
##
## Pearson's Chi-squared test
##
## data: tab
## X-squared = 0.97197, df = 2, p-value = 0.6151
X=cbind(sentPOS=tweets$sent==1,sentNEG=tweets$sent==-1,nchars=nchars,dtm)
faremo sempre riferiemnto al regolamento ufficiale:
http://clic.humnet.unipi.it/proceedings/Proceedings-EVALITA-2014.pdf (vedi “Overview of the Evalita 2014 SENTIment POLarity Classification Task” a pg 50)
è utile definire le funzioni che calcolano i punteggi finali:
precision <- function(true,predicted){
sum(true[predicted==1]==1)/sum(predicted==1)
}
recall <- function(true,predicted){
sum(predicted[true==1]==1)/sum(true==1)
}
F_class <- function(true,predicted,verbatim=TRUE){
rec=recall(true,predicted)
pre=precision(true,predicted)
Fsc = 2*(pre*rec)/(pre+rec)
if(verbatim) print(c(recall=rec,precision=pre,F=Fsc))
Fsc
}
Punteggio finale task 1: (F_obj+F_soggettivo)/2
(F_class( true==1,predetto==1) +F_class( true==0,predetto==0))/2
Punteggio finale task 2: ((F_neg_0+F_neg_1)/2+(F_pos_0+F_pos_1)/2)/2
per il modello che prevede i positivo
F_pos_1=F_class( true==1,predetto==1)
F_pos_0=F_class( true==0,predetto==0)
Uguale per il modello che prevede i negativo
F_neg_1=F_class( true==1,predetto==1)
F_neg_0=F_class( true==0,predetto==0)
come task 1
salvo due data.frame
e le funzioni per calcolare i punteggi finali:
tweets
che contiene i testi originali ed anche le classificazioni dei task 1, 2 e 3.X
la matrice dei predittori: dtm + sentiment + nchar
save(file="dati_FunScore.Rdata", tweets,X, precision, recall, F_class)
buon lavoro!!