Contexto

O twitter de Jair Bolsonaro é praticamente um “Diário Não-Oficial” do governo federal, um fórum utilizado pelo mandatário para anúncios relacionados ao governo federal, funcionando quase como um “diário oficial” informal, cheio de intrigas e reviravoltas.

Dessa forma, é válido analisar a potencial influência que seu filho Carlos Bolsonaro tem sobre essa conta do país. Twitteiro contumaz, próximo do pai, especula-se que Carlos seja um dos administradores da conta do pai na rede social.

Fiz esse estudo a pedido do Intercept Brasil, resultando em um texto do jornalista Alexandre Santi.

Dados

Os dados são a partir de 1º de janeiro de 2018, obtidos diretamente das contas oficiais de Twitter do presidente jairbolsonaro e de seu filho CarlosBolsonaro.

Foi utilizada a API da ferramenta Workbench para extrair e armazenar esses dados.

A fim de mostrar interação entre contas, a análise inclui retuítes.

Às vezes, o Workbench desabilita o retorno dos dados até que alguém acesse a tabela diretamente no aplicativo, retornando o resultado {} nos dados. Caso isso aconteça, basta acessar o link a seguir para carregar os dados, e a URL com o csv voltará a funcionar sem precisar fazer mais nada.

Link para reativar dados

# Carrega os dados estruturados direto da API do Workbench
d <- read.csv("https://app.workbenchdata.com/public/moduledata/live/45112.csv", header = T)

# estrutura dos dados (exceto texto de tuítes, que quebravam a estética da tabela)
names(d)
##  [1] "screen_name"                  "created_at"                  
##  [3] "text"                         "retweet_count"               
##  [5] "favorite_count"               "in_reply_to_screen_name"     
##  [7] "retweeted_status_screen_name" "user_description"            
##  [9] "source"                       "id"

Após o carregamento dos dados e a criação de uma coluna nova para separar apenas as horas, fazemos alguma limpeza nos dados e forçamos a configuração do tipo certo de dado para cada coluna, especialmente forçando a formatação de data e hora.

É possível, para uma segunda análise, excluir os retuítes das contas fazendo um comment out no fim desse bloco de código.

# força formatação pra date-time na coluna created_at
d$created_at <- ymd_hms(d$created_at)

#ordena por data
d <- d[order(d$created_at),]

# separa colunas
d <- separate(d, created_at, c("dia", "hora"), sep = " ", remove = F)
d$hora <- gsub("\\:.*","",d$hora)

# limpa a coluna para ter apenas a hora-relógio cheia numeral
d$hora <- gsub("\\:.*","",d$hora)
d$hora <- as.numeric(d$hora)

# remove retuítes
# d <- dplyr::filter(d, !str_detect(text, '(RT)'))

A partir dessa organização dos dados, vamos criar buckets de 3 em 3 horas a fim de definir os períodos do dia que serão referência de proximidade dos tweets. Isso acrescenta uma nova camada de informação que nos permite analisar os dados mais facilmente a partir de intervalos de tempo definidos.

Note que a única exceção para período de horas é o último da noite e o primeiro da manhã: as primeiras horas da madrugada tem quatro horas, enquanto as últimas da noite tem duas.

Essa diferença deve-se ao fato de os dados do Twitter estarem formatados como meia-noite sendo 00:00, em vez de 24:00. Como transformamos o horário em valor numeral, isso evita mais complexidade no código para identificar a meia noite como 00:00. São horários de menor movimentação, houve diferença mínima nos dados finais.

# cria variavel de periodos em buckets de 3 horas
d$periodo <- ifelse(d$hora > 12 & d$hora <= 15,"tarde 1", 
                    ifelse(d$hora > 15 & d$hora <= 18,"tarde 2", 
                           ifelse(d$hora > 18 & d$hora <= 21,"noite 1", 
                                  ifelse(d$hora > 21 & d$hora <= 23 ,"noite 2", 
                                         ifelse(d$hora >= 0 & d$hora <= 3,"madrugada 1", 
                                                ifelse(d$hora > 3 & d$hora <= 6,"madrugada 2", 
                                                       ifelse(d$hora > 6 & d$hora <= 9,"manha 1", 
                                                              ifelse(d$hora > 9 & d$hora <= 12,"manha 2", "n/a"))))))))

# retweets <- count(d, d$retweeted_status_screen_name)

# conta total de ocorrências de fonte de tweets (tipo de aparelho)
fonte <- count(d, d$source)

# conta o número de retweets
retweets <- d %>% 
  drop_na() %>%
  group_by(retweeted_status_screen_name) %>%
  filter(screen_name == "jairbolsonaro") %>%
  summarize(Count=n()) %>%
  arrange(desc(Count))

retweets <- head(retweets, n = 16, addrownums = TRUE)

#agrupa elementos
dl <- d %>%
  select(dia, periodo, screen_name, created_at) %>%
  group_by(dia, periodo, screen_name) %>% 
  mutate(rn = row_number()) %>% 
  arrange(created_at) %>% 
  spread(screen_name, created_at) %>% 
  select(-rn)

# soma as colunas, transformando em segundos
dl$jair_carlos <- dl$CarlosBolsonaro - dl$jairbolsonaro

# tira o sinal de menos, para que dados sejam comparáveis também em vice-versa e depois força diferença como número
dl$jair_carlos <- gsub("-", "", dl$jair_carlos)
dl$jair_carlos <- as.numeric(dl$jair_carlos)

# força dia como data 
dl$dia <- lubridate::ymd(dl$dia)

# cria dataframe com subset com filtro de datas
df <- subset(dl, dia > "2018-01-01" & dia < "2019-02-13")

# escreve o csv
# write.csv(df, "d.csv")

A seguir subtraímos as colunas para saber o spread entre um tweet e outro dentro de um mesmo período de três horas.

A principal análise a ser feita recai sobre a mediana de tempo entre os tweets. Considero que a mediana no caso seja muito mais adequada do que a média por conta da grande dispersão entre os dados (desvio padrão de 2281 segundos).

#summary(df$jair_carlos)[c(1,3,4,6)]
recorte <- subset(df, select=c(jair_carlos))

stats <- as.data.frame(summary(recorte))

stats <- separate(stats, Freq, c("medição", "valor (em segundos)"), sep = ":", remove = T)
stats$"valor (em segundos)" <- as.numeric(stats$valor)
stats$"valor (em minutos)" <- round(stats$valor / 60, digits = 1)


kable(stats[c(3,4,5)], caption = "Estatísticas básicas da análise em fev.2019")
Estatísticas básicas da análise em fev.2019
medição valor (em segundos) valor (em minutos)
Min. 11 0.2
1st Qu. 804 13.4
Median 1930 32.2
Mean 2634 43.9
3rd Qu. 3718 62.0
Max. 10944 182.4
NA’s 2989 49.8
kable(retweets, caption = "Top 15 retweets por usuário na conta de @jairbolsonaro")
Top 15 retweets por usuário na conta de @jairbolsonaro
retweeted_status_screen_name Count
2484
CarlosBolsonaro 152
BolsonaroSP 80
odiodobem 44
FlavioBolsonaro 25
conexaopolitica 21
RenovaMidia 21
planalto 15
BlogDoPim 12
jairbolsonaro 12
benebarbosa_mvb 11
republica_ctba 10
Clauwild1 8
filgmartin 7
foIha_sp 7
JoelAlexandreM 7
kable(fonte, caption = "Tweets de @jairbolsonaro por tipo de dispositivo celular")
Tweets de @jairbolsonaro por tipo de dispositivo celular
d$source n
Twitter for Android 21
Twitter for iPhone 6812
Twitter Web Client 2