Lennon Wall Praha

La collection de tweets constituée ( nous en sommes à 26 jours) est supposée reflétée le sentiment des populations. Mais cette production n’est pas que l’agrégation d’opinion individuelles comme c’est le cas dans une enquête d’opinion qui pratique les sondage par quotas. La production des tweets est le fait d’une population hétérogène, beaucoups lisent, très peu s’engagent et parmis ceux qui s’engagent certains le feront ponctuellement,d’autres occasionnellement, certains de manière plus périodiqu, et sans doute d’autres , peu nombreux, de manière acharnée.

La question principale : peut-on identifier des groupes de twittos qui sur le fil #confinementjour:

Construire une telle segmentation permettrait d’engager une opération de comparaison systématique sur les profils. C’est l’objectif de cette note d’étude.

Les outils de l’analyse

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)
library(tidyverse) #l'environnement de base : données et visus
library(rtweet) #extraction twitter
library(gridExtra) #associer des ggplot
library(scales) #pour les échelles de temps et de date
library(ineq)
library(gglorenz)
library(ggridges)


df<- readRDS(file = "df_lsd.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 # heure

df<- df %>% mutate(Jour=ifelse(month == 3,day-16 ,ifelse(month==4,day+15,0) ))

Et voici une représentation de la distribution journalière de la production des données, ainsi que sa distribution horaire, jour par jour. On observe des pics matinaux et le soir, mais avec une balance différente selon les jours.Parfois pls le midi, parfois plus le soir. L’enjeu bien sur, va être d’idenfier ceux qui produisent les tweets.

g001<-ggplot(df,aes(x=Jour))+
  geom_bar(aes(fill=(is_retweet)))+ 
  theme_minimal()+ 
  labs(title="# de tweets par jour")+
  facet_wrap(vars(is_retweet),ncol=1,scales="free")

#library(ggridges)

foo<-df %>% filter(Jour>1 & Jour<23)
foo$Jour<-as.factor(foo$Jour)

g002<-ggplot(foo,aes(x=hour, y=Jour))+theme_minimal() + 
  geom_density_ridges(scale=4, fill="pink") +
  labs(title = 'distribution du sentiment')

grid.arrange(g001, g002, ncol=2)

La popularité des tweets

Avant de nous intéresser à la population des individus, examinons encore les caractéristiques du flux et de la population des tweets et notamment à leur popularité.

On ne garde que des contenus avec du texte original. On passe de 1,3 millions de tweets et RT à un peu plus de 250 000 tweets. Donc un rapport de 1 tweet pour 5 retweets. Parmis les tweets primaires, 25000 d’entre eux sont des citations (quotes), donc en gros 10%.

Examinons la distribution des indicateurs d’engagement qui décrit la popularité des contenus et peut être appréciée par le nombre de retweetx dont ils ont fait l’objet, et le nombre de fois où ils ont été cliqués comme favori.

L’inégalité est de mise : moins de 5 tweets ont été relayés et aimés plus de mille fois. Ceux qui l’ont été dans l’ordre de la centaine de fois, sont une centaine d’individus. La représentation logarithmique efface la grande majorité de ceux qui n’ont jamais été apprécié ( 0 tweets ou retweet).

library(scales)
foo<-df %>% filter (is_quote==TRUE & is_retweet==FALSE)

g1<-ggplot(foo,aes(x=favorite_count+0.1))+geom_histogram(fill="firebrick")+theme_minimal()+ scale_x_log10()+ scale_y_log10()+labs(title="Popularité des tweets", subtitle = "Favoris", x="nombre de likes")     

g2<-ggplot(foo,aes(x=retweet_count+0.1))+geom_histogram(fill="firebrick")+theme_minimal()+ scale_x_log10() +scale_y_log10()+labs(title="", subtitle = "Retweet", x="nombre de retwteets")     

grid.arrange(g1,g2,ncol=2)

La concentration de la production

Une analyse en terme de concentration est indispensable.

Après agrégation sur le screen_name, le nom d’utilisateur, on peut representer la distribution des individus qui postent des messages en fonction du nombre des messages qu’ils ont postés. Globalement le volume des 250 000 tweets sont générés par 75407 comptes distincts. Soit à peu prêt un peu plus de 3 message par individu. Mais ces deux chiffres masquent une extrême hétérogénéité.

Si près de 50.000, les deux tiers n’ont posté qu’une fois, des milliers ont produits jusqu’à des dizaines de post, et une infime partie des centaines. La courbe de concentration est claire : un tiers des twittos qui postent de multiples fois , produisent les deux tiers du contenu, et les premiers 5% en produisent la moitié.

L’indice de gini est de .

#on calcule le nombre d'dc par logement
dc<-df %>% mutate(n=1) %>% group_by(screen_name) %>% summarise(nb_dc = sum(n))
mean<-round(mean(dc$nb_dc),1)
median<-median(dc$nb_dc)
max<- max(dc$nb_dc)
g05a<-ggplot(dc, aes(x=nb_dc))+
  geom_histogram(binwidth=.1,fill="firebrick")+
  theme_minimal()+xlim(-5,250)+scale_x_log10()

#  annotate("text", x=1000, y=20, size=3,label= paste0("moyenne=",mean,"- médiane=", median,"- max=",max))+labs(x = "nombre d'dc", y = "Fréquences (nb d'hôtels)", title = "Distribution du nombre d'dc par hôtel", caption = "Laboratoire du confinement")

#on analyse la concentration
#library(ineq)
#library(gglorenz)
gini<-round(ineq(dc$nb_dc,type = c("Gini")),2)

g05b<-dc %>%
    ggplot(aes(nb_dc)) +
    stat_lorenz(desc = TRUE,size=1.2,color="darkred") +
    coord_fixed() +
    geom_abline(linetype = "dashed") +
    theme_minimal() +labs(x = "Part cumulée des twittos",
         y = "Part cumulée des dc",
         title = "Concentration des tweets",
         caption = "")
#+  annotate("text", x=.35, y=.6, size=3,label= paste0("indice de Gini=",gini))

grid.arrange(g05a,g05b,ncol=2)

La segmentation des twittos

On segmente sur la base du nombre de posts

En terme de capacité de production, les fidèles qui émettent de 7 à 25 messages représentent la moitié de la production. La production des spammeur est importante mais ne représente que 15% du volume.

col =c("deepskyblue4","chartreuse3","gold2","firebrick2")

dc<-dc %>% mutate(Twittos=ifelse(nb_dc==1,"Ponctuels", ifelse(nb_dc>1 & nb_dc<7, "Récidivistes", ifelse(nb_dc>6 & nb_dc<26,"Fidèles","superposteurs"))))
dc$Twittos<- factor(dc$Twittos,ordered=TRUE,levels=c("Ponctuels","Récidivistes","Fidèles","superposteurs"))

g10<-ggplot(dc,aes(x=Twittos,y = ..count.. / sum(..count..),fill=Twittos))+
  geom_bar(position = "stack")+theme_minimal()+
  coord_flip()+
  scale_fill_manual(values =col)+ 
  theme(legend.position = "none")+  labs(title="Part des tweetos (n=75 407)",x="twittos",y="proportion")  


#dc$Twittos<- as.factor(dc$Twittos)


df_user <-df %>%left_join(dc,by="screen_name")%>%mutate(n_tweets=1)                                 


g11<-ggplot(df_user,aes(x=Twittos, y = ..count.. / sum(..count..),fill=Twittos))  +
  geom_bar() +theme_minimal()+coord_flip()+
  scale_fill_manual(values =col) + theme(legend.position = "none")+
  labs(title="Part des tweets ( n= 273 343)", y="proportion")  
grid.arrange(g10,g11,ncol=2)                                 

leurs discours sont-ils différents ?

En termes de sentiment?

Les superposteurs dramatisent la situations, le contenu n’est pas plus positifs que les fidèles, mais bien plus négatifs. Leurs petits nombre par un grand nombres de posts biaise donc vers le négatif le corpus.

Pour le reste on observe une belle corrélation entre la fréquence de post et l’expressivité, est-ce l’effet d’une expérience et d’une compétence entrainée? Les expressions ponctuelles seraient plus spontanée et réservée.

col_sent=c("green4","firebrick3")
df_user <-df %>%left_join(dc,by="screen_name")%>%mutate(n_tweets=1)      
foo<-df_user %>%group_by(Twittos)%>% summarise(positive=mean(positive,na.rm=TRUE),negative=mean(negative,na.rm=TRUE))
library(reshape2)
foo<-melt(foo)
g12<-ggplot(foo,aes(x=Twittos,y=value, group=variable))  +geom_line(aes(color=variable), size=2) +theme_minimal()+coord_flip()+scale_color_manual(values =col_sent) +labs(title="Comparaison des profils de twittos", subtitle = "par les sentiments", y="Densité")          
g12

df_user$Jour<-as.factor(df_user$Jour)
anova<-lm(negative~Jour+Twittos, data=df_user)
summary(anova)
## 
## Call:
## lm(formula = negative ~ Jour + Twittos, data = df_user)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.9629 -0.8408 -0.7566  0.2204 15.1420 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 0.7470091  0.0388174  19.244  < 2e-16 ***
## Jour2       0.0762899  0.0406946   1.875  0.06084 .  
## Jour3       0.0985369  0.0401510   2.454  0.01412 *  
## Jour4       0.1096480  0.0414444   2.646  0.00815 ** 
## Jour5       0.1231492  0.0406318   3.031  0.00244 ** 
## Jour6       0.0829477  0.0401851   2.064  0.03901 *  
## Jour7       0.0694562  0.0405142   1.714  0.08646 .  
## Jour8       0.0503261  0.0408544   1.232  0.21801    
## Jour9       0.0837232  0.0404224   2.071  0.03834 *  
## Jour10      0.0507639  0.0400329   1.268  0.20478    
## Jour11      0.0716864  0.0412584   1.737  0.08230 .  
## Jour12      0.1150019  0.0412964   2.785  0.00536 ** 
## Jour13      0.0895170  0.0414030   2.162  0.03061 *  
## Jour14      0.0317740  0.0405042   0.784  0.43277    
## Jour15      0.0150982  0.0415096   0.364  0.71606    
## Jour16      0.0734759  0.0416437   1.764  0.07767 .  
## Jour17      0.1246376  0.0418890   2.975  0.00293 ** 
## Jour18      0.0834032  0.0415587   2.007  0.04476 *  
## Jour19      0.0470276  0.0423085   1.112  0.26634    
## Jour20      0.1192073  0.0417679   2.854  0.00432 ** 
## Jour21      0.0674111  0.0418212   1.612  0.10699    
## Jour22      0.0723148  0.0417019   1.734  0.08290 .  
## Jour23      0.0428737  0.0414640   1.034  0.30114    
## Jour24      0.0553888  0.0425676   1.301  0.19319    
## Jour25      0.0794394  0.0697263   1.139  0.25458    
## Twittos.L   0.1316925  0.0060534  21.755  < 2e-16 ***
## Twittos.Q   0.0006682  0.0055985   0.119  0.90500    
## Twittos.C   0.0113694  0.0051990   2.187  0.02876 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.378 on 256767 degrees of freedom
## Multiple R-squared:  0.00225,    Adjusted R-squared:  0.002145 
## F-statistic: 21.45 on 27 and 256767 DF,  p-value: < 2.2e-16
anova(anova)
## Analysis of Variance Table
## 
## Response: negative
##               Df Sum Sq Mean Sq  F value    Pr(>F)    
## Jour          24    173   7.215   3.8003 9.138e-10 ***
## Twittos        3    926 308.761 162.6398 < 2.2e-16 ***
## Residuals 256767 487455   1.898                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
library(ggeffects)
mydf<-ggpredict(anova, terms = "Twittos")
ggplot(mydf, aes(x, predicted, group=1)) +
  geom_line() +
  geom_ribbon(aes(ymin = conf.low, ymax = conf.high), alpha = .1)+theme_minimal()

les émotions des segments

Plus on est actif et plus on est expressif. Mais pour les superposteurs, la tendance n’est pas poursuivie pour les sentiments positifs. Ils polarisent en effaçant les éléments positifs et en renforçant les éléments négatifs.

emocol<-c("red3","orangered1","purple3","royalblue3","chartreuse","olivedrab3","green4","gold") #ern respectant des codes mais il faudra adoucir.

df_user <-df %>%left_join(dc,by="screen_name")%>%mutate(n_tweets=1)      
foo<-df_user %>%group_by(Twittos)%>% summarise(anger=mean(anger,na.rm=TRUE),fear=mean(fear,na.rm=TRUE),disgust=mean(disgust,na.rm=TRUE),sadness=mean(sadness,na.rm=TRUE),surprise=mean(surprise,na.rm=TRUE),anticipation=mean(anticipation,na.rm=TRUE),joy=mean(joy,na.rm=TRUE),trust=mean(trust,na.rm=TRUE)) %>% ungroup()
library(reshape2)
foo<-melt(foo)
g12<-ggplot(foo,aes(x=Twittos,y=value, group=variable))  +
  geom_line(aes(color=variable),size=2) +
  theme_minimal()+coord_flip()+ 
  scale_color_manual(values =emocol)+labs(title="Comparaison des profils de twittos", subtitle = "par les émotions de leurs tweet", y="Densité")     
g12

Comment s’expriment -il?

Les tweetos ponctuels semblent avoir un discours situé : le je est fréquent et on parle au présent. Le “je” se réduit avec le nombre de tweets produit, devient-on plus impersonnel dans le ton avec l’expérience ? De même on s’exprime avec moins de temporalité, un discours décontextualisé?

col_sent=c("cadetblue2","cadetblue3","cadetblue4", "darkolivegreen1","darkolivegreen2","darkolivegreen3")
df_user <-df %>%left_join(dc,by="screen_name")%>%mutate(n_tweets=1)      
foo<-df_user %>%group_by(Twittos)%>% summarise(je=mean(je,na.rm=TRUE),nous=mean(nous,na.rm=TRUE),vous=mean(vous,na.rm=TRUE),verbepassé=mean(verbepassé,na.rm=TRUE),verbeprésent=mean(verbeprésent,na.rm=TRUE), verbefutur=mean(verbefutur,na.rm=TRUE))
library(reshape2)
foo<-melt(foo)
g12<-ggplot(foo,aes(x=Twittos,y=value, group=variable))  +geom_line(aes(color=variable), size=1.5) +theme_minimal()+coord_flip()+scale_color_manual(values =col_sent)+labs(title="Comparaison des profils de twittos", subtitle = "par la syntaxe", y="Densité")          
g12

De quoi parle-t-on?

Le Licw propose un certain nombre d’indicateurs topicaux. En voici le résultat pour un certain nombre d’entre eux pertinents au regard de la question du confinement : le corps, la santé, les proches.

Encore une fois, des différences systématiques sont observées, qui vont dans le sens de la dramatisation. La tendance générale est que ces thématiques sont évoquées moins fréquemment à mesure que l’on poste souvent et va dans le sens de l’impersonnel. Plus on s’expose et moins on parle de soit, mais plutôt de sujet tiers. Quant aux Les superposteurs il se distingue par une thématique centrée sur la santé. S’agit-il de contenus alarmistes ou inquétant dont ils se feraient une spécialité?

sont des “flippés”! Au regard des “fidèles”, ils postent du contenu moins positif mais du contenu plus positif.

col_sent=c("Orange1","Orange2","Orange3", "blue",  "coral1",  "coral3", "coral4")
df_user <-df %>%left_join(dc,by="screen_name")%>%mutate(n_tweets=1)      
foo<-df_user %>%group_by(Twittos)%>% summarise(famille=mean(famille,na.rm=TRUE),ami=mean(ami,na.rm=TRUE), humain=mean(humain,na.rm=TRUE),corps=mean(corps,na.rm=TRUE),alimentation=mean(alimentation,na.rm=TRUE),santé=mean(santé,na.rm=TRUE),sexualité=mean(sexualité,na.rm=TRUE))
library(reshape2)
foo<-melt(foo)
g12<-ggplot(foo,aes(x=Twittos,y=value, group=variable))  +geom_line(aes(color=variable), size=2) +theme_minimal()+coord_flip()+scale_color_manual(values =col_sent) +labs(title="Comparaison des profils de twittos", subtitle = "par les topics de leurs tweet", y="Densité")         
g12

Conclusion

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 pendants quelques twts 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:

#Références