Lennon Wall Praha
Lundi 14 , Emmanuel Macron a tenu son second discours. Long de 28 mn et débutant à 8h02, juste après les applaudissements, il a réunis une part importante de la population. Quel effet sur le sentiment ?
C’est à cette question que notre étude va répondre par une méthode de contrefactuel. Celle-ci consiste à comparer les sensiments observés après l’intervention, à ceux qu’un modèle de prédiction simple (autorégression) permet d’obtenir et qui sont supposer mesure l’opinion s’il n’y avait pas eu cette évènement. L’écart entre les deux ensembles de valeur mesurerait l’effet des discour, même s’il faut garder à l’esprit que dans les heures suivant le discours, d’autres événements se succèdent.
Comme le discours était annoncé depuis plusieurs jours que des indiscretions filtraient, il est bien possible que l’intervention aie une action avant même l’allocution. On sera donc attentif au choix des dates seuils. Et on testera deux modèles, l’un qui prend toute l’information jusqu’à 1h avant l’intervention, un autre qui s’arrête la veille. Mais on peut moduler l’approche.
A cette fin on utilise les packages suivants.
Quelques recodages de date pour obtenir les unités J+1, J+2…
knitr::opts_chunk$set(echo = TRUE,include=TRUE, cache=TRUE, message=FALSE,warning=FALSE, fig.width = 8)
library(tidyverse) #l'environnement de base : données et visus
library(reshape2)
library(gridExtra) #associer des ggplot
library(scales) #pour les échelles de temps et de date
library(lubridate)
library(zoo)
df<- readRDS(file = "df_nrcliwclsd.rds")
#construire des dates jour/heures
df$day<-as.numeric(format(df$created_at, "%d")) # jour
df$month<-as.numeric(format(df$created_at, "%m")) # mois
df$hour<-as.numeric(format(df$created_at, "%H")) # heure
df$year<-2020 # année
df<- df %>% mutate(Jour=ifelse(month == 3,day-16 ,ifelse(month==4,day+15,0) ))
https://www.statmethods.net/advstats/timeseries.html
le courbe du sentiment est place qu’il soit positif ou négatif. Elle semble le fruit d’un sysmographe, ce qui varie n’est pas le niveau, mais la variance. Des chocs d’information introduisent de la perturbation? (modèle garch? ). La barre verticale marque l’heure du début de discours de macron qui manifestement agite le sentiment.
sentevol<-df %>% group_by(month,day,hour) %>% mutate(n=1) %>%summarise(positive=mean(positive, na.rm=TRUE),negative=mean(negative, na.rm=TRUE), n=sum(n))
sentevol$date<-paste0("2020","-",sentevol$month,"-",sentevol$day," ",sentevol$hour,":00:00")
sentevol$date2 <- as.POSIXct(strptime(sentevol$date, "%Y-%m-%d %H:%M:%S"))
sentevol<- sentevol %>% mutate(Jour=ifelse(month == 3,day-16 ,ifelse(month==4,day+15,0) ))
foo<-sentevol %>% ungroup %>% filter(Jour>0 & Jour<31) %>% select(date2,negative,positive)%>%mutate(negative=-negative)
date_macron <-ymd_h("2020-04-13 19")
foo<-melt(foo, id=c("date2"))
ggplot(foo, aes(x=date2,y=value,group=variable))+
geom_line(size=1,aes(color=variable))+
theme(axis.text.x=element_text(angle = 60, vjust = 0.5))+
theme_minimal()+ stat_smooth( aes(color =variable, fill = variable), method = "loess")+
labs(x = NULL, y = NULL,
title = "Evolution des valences du sentiment #ConfinementJour", y="Valence (+/-)",x="dates (par heure)",
subtitle = "Par heure - zone en gris: le discours du Président",
caption = "\nSource: Data collected by Benavent C. from Twitter's REST API via rtweet"
)+ scale_x_datetime(date_breaks = "2 day", labels = scales::label_date_short()) + geom_vline(xintercept = date_macron, color = "lightgrey", size=4)
Le traitement de la série demande à ce qu’on la transforme en objet ts pour r. L’idée c’est d’utiliser l’histoire passée ( jusqu’avant le discours) pour prédire le niveau de sentiment après le discours.
On se concentre sur le sentiment positif, on fera de même en un bloc pour le négatif.
foo<-sentevol %>% ungroup %>%
filter(date2<date_macron) %>%
select(date2,negative,positive) %>%
mutate(negative=-1*negative, sentiment=positive+negative)
foo2<- sentevol %>% ungroup %>% filter(date2<date_macron) %>% select(date2)
# creation sous forme d'objet ts via zoo
#library(zoo)
ts<- zoo(foo$positive, order.by=foo$date2)
from https://rstudio-pubs-static.s3.amazonaws.com/9428_1197bd003ebd43c49b429f22ea4f36e5.html
https://rpubs.com/sinhrks/plot_tsstats
acf(coredata(ts),lag.max = 240, main="de l'autocorrélation et de la saisonnalité!")
pacf(coredata(ts),lag.max = 240, main="de l'autocorrélation et de la saisonnalité!")
mspect <- spec.pgram(coredata(ts))
plot(mspect, log = "no")
#avec lissage
#k = kernel("daniell", c(5,5))
#smooth.spec <- spec.pgram(coredata(ts), kernel = k, taper = 0)
spec.df <- data.frame(freq = mspect$freq, spec = mspect$spec)
day.period <- rev(c(1/24,1/12, 1/6,1, 2, 3, 4, 6, 12, 24))
day.labels <- rev(c("1/24","1/12", "1/6","1", "2", "3","4", "6", "12", "24"))
yrs.freqs <- 1/day.period #Convert annual period to annual freq, and then to monthly freq
mspect$period <- 1/spec.df$freq
ggplot(data = spec.df)+ geom_line(aes(x = freq, y = spec),color="firebrick") + scale_x_continuous("Period (heure)",
breaks = yrs.freqs, labels = day.labels) + scale_y_continuous()+theme_minimal()
On utilise la fonction auto.arima de forecast qui choisit le meilleur modèle au sens de l’AIC.
La figure donne une idée de l’ajustement du modèle.
library(forecast)
d.arima <- auto.arima(coredata(ts))
d.arima
## Series: coredata(ts)
## ARIMA(1,0,2) with non-zero mean
##
## Coefficients:
## ar1 ma1 ma2 mean
## 0.5621 -0.2213 0.1654 0.7859
## s.e. 0.0794 0.0820 0.0511 0.0109
##
## sigma^2 estimated as 0.01659: log likelihood=409.87
## AIC=-809.73 AICc=-809.64 BIC=-787.37
matplot(cbind(coredata(ts),fitted(d.arima)),type='l')
La prédiction se fait aussi simplement que l’estimation du modèle avec forecast. On prédit autant de périodes que de périodes observées après le discours du Président Macron.
d.forecast <- forecast(d.arima, level = c(95), h = 102)
autoplot(d.forecast)+theme_minimal()
On en représente le résultat en comparant les données observées à la prédiction et en examinant les écarts. On utilise une somme cumulative pour mieux marquer l’effet.
Elle doit être interprêté avec prudence.
foo2<-sentevol %>% ungroup %>% filter(date2>date_macron) %>% select(date2,negative,positive) %>% mutate(negative=-1*negative, sentiment=positive+negative)
foop<-d.forecast[4]
foo2<-cbind(foo2, foop)%>% select(date2,positive, mean) %>% mutate(ecart=positive-mean, ecart_cumul=cumsum(ecart))%>%rename(prediction=mean, observed=positive)
col_macron<-c("darkblue","gold3","firebrick","coral2")
foo2<-melt(foo2, id="date2")
ggplot(foo2, aes(x=date2,y=value,group=variable))+
geom_line(size=1,aes(color=variable))+
theme(axis.text.x=element_text(angle = 60, vjust = 0.5))+
theme_minimal()+# stat_smooth( aes(color =variable, fill = variable), method = "loess")+
labs(x = NULL, y = NULL,
title = "Impact du discours macron sur la positivité des tweets", y="Valence (+/-)",x="dates (par heures)",
subtitle = "Valence par heure",
caption = "\nSource: Data collected by Labo du confinement from Twitter's REST API via rtweet"
)+ scale_x_datetime(date_breaks = "4 hour", labels = scales::label_date_short()) + geom_vline(xintercept = date_macron, color = "brown4", size=2)+
scale_colour_manual(values=col_macron)
library(zoo)
ts<- zoo(foo$negative, order.by=foo$date2)
plot(ts, xlab="Date", ylab="Cases")
acf(coredata(ts),lag.max = 240, main="Temperature is Highly Autocorrelated!")
pacf(coredata(ts),lag.max = 240, main="Temperature is Highly Autocorrelated!")
mspect <- spec.pgram(coredata(ts))
#plot(mspect, log = "no")
#k = kernel("daniell", c(5,5))
#smooth.spec <- spec.pgram(coredata(ts), kernel = k, taper = 0)
spec.df <- data.frame(freq = mspect$freq, spec = mspect$spec)
day.period <- rev(c(1/24,1/12, 1/6,1, 2, 3, 4, 6, 12, 24))
day.labels <- rev(c("1/24","1/12", "1/6","1", "2", "3","4", "6", "12", "24"))
yrs.freqs <- 1/day.period #Convert annual period to annual freq, and then to monthly freq
mspect$period <- 1/spec.df$freq
ggplot(data = spec.df)+ geom_line(aes(x = freq, y = spec)) + scale_x_continuous("Period (heure)",
breaks = yrs.freqs, labels = day.labels) + scale_y_continuous() +theme_minimal()
# from https://rstudio-pubs-static.s3.amazonaws.com/9428_1197bd003ebd43c49b429f22ea4f36e5.html
library(forecast)
d.arima <- auto.arima(coredata(ts))
d.forecast <- forecast(d.arima, level = c(95), h = 102) #reajuster à chauqe maj des données
matplot(cbind(coredata(ts),fitted(d.arima)),type='l')
autoplot(d.forecast)+theme_minimal()
foo2<-sentevol %>% ungroup %>% filter(date2>date_macron) %>% select(date2,negative,positive) %>% mutate(negative=-1*negative, sentiment=positive+negative)
foop<-d.forecast[4]
foo2<-cbind(foo2, foop)%>% select(date2,negative, mean) %>% mutate(ecart=negative-mean, ecart_cumul=cumsum(ecart))%>%rename(prediction=mean, observed=negative)
foo2<-melt(foo2, id="date2")
col_macron<-c("darkblue","gold3","firebrick","coral2")
ggplot(foo2, aes(x=date2,y=value,group=variable))+
geom_line(size=1,aes(color=variable))+
theme(axis.text.x=element_text(angle = 60, vjust = 0.5))+
theme_minimal()+# stat_smooth( aes(color =variable, fill = variable), method = "loess")+
labs(x = NULL, y = NULL,
title = "Impact du discours macron sur la négativité des tweets", y="Valence (+/-)",x="dates (par heures)",
subtitle = "Valence par heure",
caption = "\nSource: Data collected by Benavent C. from Twitter's REST API via rtweet"
)+ scale_x_datetime(date_breaks = "4 hour", labels = scales::label_date_short()) + geom_vline(xintercept = date_macron, color = "brown4", size=2)+scale_color_manual(values=col_macron)
La production de flux n’est pas l’agrégation de productions individuelles similiaires, elle dépend de groupes d’individus qui se distinguent par la fréquence de leur post et très probablement par les motifs de leur activité : des réactions spontanées et ponctuelles, un engagement plus net qui conduit à récidiver pendant quelques tweets ou une conversation, un engagement plus soutenu et une sorte de fidélité aux #. Une determination dont il faut vérifier la motivation ( bot, troll, pathologe…) qui conduit à une production effrenée.
Des questions se posent et doivent être résolues: