A Network Analysis of the 2019 Bolivian Political Crisis.
In the wake of Bolivia’s 2019 general elections, the Organization of American States (OAS) claimed in its report that the socialist party of Evo Morales was rigging the election. As a result, protests from the opposing party erupted, eventually leading to a coup supported by the police and military. As a result, Jeanine Áñez of the opposition Democrat Social Movement, assumed the interim presidency of Bolivia. Evo Morales and other members of his party sought political asylum in Mexico citing concerns over their livelihood.
Months later, multiple studies analyzing the election results found no statistical evidence for fraud and also pointed out errors in the coding of OAS’s report. With concerns of the OAS’s history of being a US sponsored organization that was utilized to stop communism in Latin America during the cold war; many left-wing proponents believed that the US backed right-wing coup of Bolivia was a ploy to exploit the country’s lithium reserves — its deposits being the second largest in the world.
Earlier this year, Morales’s party won the re-election by a landslide and ousted Jeanine Áñez’s interim presidency that was marred by controversy and massacres. But concern over the US government’s and US media’s actions and influence still looms.
To analyze the network structure of this political crisis, 63,965 tweets were retrieved from the Academic Twitter API. Tweets were collected from the month of the 2019 crisis to the month before the 2020 election (09/10/2019 - 09/18/2020). The search query string only including tweets that matched two keywords from the following list: bolivia, coup, democracy, evo, morales, anez, jeanine.
The original data was in RDS format and converted into an edgelist representing the universe of cases. Data was transformed by only including tweets that mention another user in the dataframe column “mention_screen_name” with a minimum of 2 retweets. There are 5,539 nodes and what constitutes a node within this dataset is the original sender of a tweet. Ties are defined when a “sender” has a tweet mentioning another user. There are 6,986 ties and the ties are weighted by the count of retweets.
Many users are interconnected within this sparsely connected graph due to direct ties measuring mentions rather than retweets, meaning the authors had to mention the user within their tweet rather than simply retweeting. There are 966 total components with the main component having 3327 points whereas the minor component only contains 14. The network is fairly centralized (49%) with a small number of nodes representing the information flow, however the centralization score almost doubles when we focus on the main component. The low global transivity score showcases that there isn’t a shared attribute (ideology, opinions, etc.) clustering nodes together when they’re mentioning users in their tweets. This transitivity trend continues at the local level of the ego network (when users mention each other) even when the proportion of mutual connections is measured via reciprocity.
The average number of steps along the shortest paths of network nodes is 27.6, showing an extent of inefficiency in information. The distribution of degrees shows a lack of statistical dispersion, with the average user only having one link for both mentioning another twitter user or receiving a mention.
# DESCRIPTIVE STATS
vcount(mt)
[1] 5539
ecount(mt)
[1] 6986
graph.density(mt, loops = TRUE)
[1] 0.0002277015
igraph::components(mt)$no
[1] 966
head(igraph::components(mt)$csize)
[1] 2 2 3 3327 2 2
centr_degree(mt, mode = c("in"), loops = TRUE,normalized = TRUE)$centralization
[1] 0.4873129
maincomponent <- induced_subgraph(
mt, V(mt)[components(mt)$membership == which.max(components(mt)$csize)]
)
centr_degree(maincomponent, mode = c("in"), loops = TRUE,normalized = TRUE)$centralization
[1] 0.8112694
transitivity(mt, type = "global")
[1] 0.0006518992
transitivity(mt, type="average")
[1] 0.04946828
reciprocity(mt)
[1] 0.005725737
igraph::dyad.census(mt)
$mut
[1] 18
$asym
[1] 5116
$null
[1] 15332357
igraph::triad_census(mt)
[1] 28280145269 24949093 2125336 6977 665147
[6] 3462 116 335 128 0
[11] 7 6 7 4 2
[16] 0
[1] 27.597
DFalconeti joshua__frank goffmansmasker AleFerruzcaL
1 1 1 6
SabatoFan Maryest66760646
1 1
# Degrees Histogram
mt.nodes <- data.frame(name=V(mt)$name, degree=igraph::degree(mt)) %>%
arrange(desc(degree))
summary(mt.nodes)
name degree
Length:5539 Min. : 1.000
Class :character 1st Qu.: 1.000
Mode :character Median : 1.000
Mean : 2.522
3rd Qu.: 1.000
Max. :2700.000
hist(mt.nodes$degree, main="2019 Bolivian Political Crisis (Degrees)", xlab = "")
DFalconeti joshua__frank goffmansmasker AleFerruzcaL
0.5000000 0.5000000 0.5000000 0.0062500
SabatoFan Maryest66760646
0.5000000 0.1428571
mt.nodes <- mt.nodes %>%
mutate(indegree=igraph::degree(mt, mode="in", loops=TRUE),
outdegree=igraph::degree(mt, mode="out", loops=TRUE))
summary(mt.nodes) %>%
kbl() %>%
kable_material_dark(c("striped", "hover")) %>%
scroll_box(width = "100%", height = "auto")
name | degree | indegree | outdegree | |
---|---|---|---|---|
Length:5539 | Min. : 1.000 | Min. : 0.000 | Min. : 0.000 | |
Class :character | 1st Qu.: 1.000 | 1st Qu.: 0.000 | 1st Qu.: 0.000 | |
Mode :character | Median : 1.000 | Median : 0.000 | Median : 1.000 | |
NA | Mean : 2.522 | Mean : 1.261 | Mean : 1.261 | |
NA | 3rd Qu.: 1.000 | 3rd Qu.: 1.000 | 3rd Qu.: 1.000 | |
NA | Max. :2700.000 | Max. :2700.000 | Max. :464.000 |
#VIZ
kcore <- coreness(mt, mode="all")
twocore <- induced_subgraph(mt, kcore>=1)
graph1 <- visIgraph(twocore,idToLabel = TRUE,layout = "layout_nicely") %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE)
graph1
#VIZ 2
kcore4 <- coreness(mt, mode="all")
fourcore <- induced_subgraph(mt, kcore4>=4)
graph2 <- visIgraph(fourcore,idToLabel = TRUE,layout = "layout_nicely") %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE)
graph2
#comp viz
kcore1 <- coreness(maincomponent, mode="all")
onecore <- induced_subgraph(maincomponent, kcore1>=1)
graph3 <- visIgraph(onecore,idToLabel = TRUE,layout = "layout_nicely") %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE)
graph3
Measuring popularity/status with in/out degree centrality made the most sense for this dataset due to it being directed and is simply looking at mentions of usernames. The ousted president Evo Morales (evoespueblo) received the most mentions by twitter users followed by La Razón, one of the largest newspaper publications within Bolivia.
indegree_mt <- sort(degree(mt,mode = "in"),decreasing = TRUE)
indegree_mt[1:10] %>% #show the top 10 users ranked by in-degree
kbl() %>%
kable_material_dark(c("striped", "hover")) %>%
scroll_box(width = "100%", height = "auto")
x | |
---|---|
evoespueblo | 2700 |
LaRazon_Bolivia | 92 |
JeanineAnez | 74 |
entrammbasaguas | 65 |
Almagro_OEA2015 | 58 |
yeidckol | 54 |
CarmenEGonzale2 | 40 |
DiazCanelB | 38 |
JohnMAckerman | 34 |
CMonteroOficial | 29 |
outdegree_mt <- sort(degree(mt,mode = "out"),decreasing = TRUE)
outdegree_mt[1:10] %>% #show the top 10 users ranked by out-degree
kbl() %>%
kable_material_dark(c("striped", "hover")) %>%
scroll_box(width = "100%", height = "auto")
x | |
---|---|
GiovannaZeball4 | 464 |
rayleon1515 | 295 |
DAVlD51 | 157 |
MonicaAparicioA | 107 |
FranzRBarriosG | 96 |
BenjaminNorton | 72 |
Libverd | 46 |
t_taeki | 43 |
elinforman_t | 38 |
YaotlAltan | 33 |
# BETWEENESS
bt <- sort(betweenness(mt, directed=T), decreasing = TRUE)
bt[1:10] %>% #show the top 10 nodes by betweenness centrality
kbl() %>%
kable_material_dark(c("striped", "hover")) %>%
scroll_box(width = "100%", height = "auto")
x | |
---|---|
GiovannaZeball4 | 6259.0 |
CarmenEGonzale2 | 4953.5 |
MonicaAparicioA | 4845.0 |
alopezescarre | 3462.5 |
DAVlD51 | 3052.0 |
marcoci56595060 | 2717.0 |
Libverd | 2636.5 |
rayleon1515 | 2627.0 |
entrammbasaguas | 2320.0 |
Amp_Bald63 | 1166.0 |
pr <- page_rank(mt, algo = c("prpack"))
pr <- sort(pr$vector,decreasing = TRUE)
pr[1:10] %>% #show the top 10 users ranked by PageRank
kbl() %>%
kable_material_dark(c("striped", "hover")) %>%
scroll_box(width = "100%", height = "auto")
x | |
---|---|
evoespueblo | 0.1036595 |
LaRazon_Bolivia | 0.0057484 |
CarmenEGonzale2 | 0.0053971 |
yeidckol | 0.0044487 |
entrammbasaguas | 0.0038097 |
JeanineAnez | 0.0036367 |
Almagro_OEA2015 | 0.0033602 |
JohnMAckerman | 0.0023502 |
DiazCanelB | 0.0022066 |
ChalecosAmarill | 0.0020588 |
# NODES
degree.nodes<-data.frame(name=V(mt)$name,
totdegree=igraph::degree(mt, loops = TRUE),
indegree=igraph::degree(mt, loops = TRUE),
outdegree=igraph::degree(mt,loops = TRUE),
eigen <- centr_eigen(mt, directed=T),
bt)
arrange(degree.nodes, desc(indegree)) %>%
head() %>%
kbl() %>%
kable_material_dark(c("striped", "hover")) %>%
scroll_box(width = "100%", height = "auto")
name | totdegree | indegree | outdegree | vector | value | options.bmat | options.n | options.which | options.nev | options.tol | options.ncv | options.ldv | options.ishift | options.maxiter | options.nb | options.mode | options.start | options.sigma | options.sigmai | options.info | options.iter | options.nconv | options.numop | options.numopb | options.numreo | centralization | theoretical_max | bt | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
evoespueblo | evoespueblo | 2700 | 2700 | 2700 | 1.0000000 | 4.19761 | I | 5539 | LR | 1 | 0 | 0 | 0 | 1 | 1000 | 1 | 1 | 1 | 0 | 0 | 0 | 2 | 1 | 29 | 0 | 29 | 0.9998964 | 5538 | 0 |
GiovannaZeball4 | GiovannaZeball4 | 473 | 473 | 473 | 0.0063064 | 4.19761 | I | 5539 | LR | 1 | 0 | 0 | 0 | 1 | 1000 | 1 | 1 | 1 | 0 | 0 | 0 | 2 | 1 | 29 | 0 | 29 | 0.9998964 | 5538 | 0 |
rayleon1515 | rayleon1515 | 300 | 300 | 300 | 0.0015024 | 4.19761 | I | 5539 | LR | 1 | 0 | 0 | 0 | 1 | 1000 | 1 | 1 | 1 | 0 | 0 | 0 | 2 | 1 | 29 | 0 | 29 | 0.9998964 | 5538 | 86 |
DAVlD51 | DAVlD51 | 169 | 169 | 169 | 0.0005272 | 4.19761 | I | 5539 | LR | 1 | 0 | 0 | 0 | 1 | 1000 | 1 | 1 | 1 | 0 | 0 | 0 | 2 | 1 | 29 | 0 | 29 | 0.9998964 | 5538 | 0 |
MonicaAparicioA | MonicaAparicioA | 115 | 115 | 115 | 0.0005835 | 4.19761 | I | 5539 | LR | 1 | 0 | 0 | 0 | 1 | 1000 | 1 | 1 | 1 | 0 | 0 | 0 | 2 | 1 | 29 | 0 | 29 | 0.9998964 | 5538 | 113 |
FranzRBarriosG | FranzRBarriosG | 103 | 103 | 103 | 0.0002780 | 4.19761 | I | 5539 | LR | 1 | 0 | 0 | 0 | 1 | 1000 | 1 | 1 | 1 | 0 | 0 | 0 | 2 | 1 | 29 | 0 | 29 | 0.9998964 | 5538 | 0 |
To discover communities, the walktrap community detection method was used due to it handling weights, increasing the probability of it going towards its direction. Below is a visualization of the communities color coded by the walktrap method.
# COMMUNITY
#mt.eb <- cluster_edge_betweenness(mt)
mt.wt <- walktrap.community(mt, weights = TRUE)
membership(mt.wt)[1:20] #list only 10 nodes.
DFalconeti joshua__frank goffmansmasker AleFerruzcaL
1 2 3 4
SabatoFan Maryest66760646 yaciramendoza _KevFal_
5 6 7 8
JpFair mundodedesigual Nsnc2019 deborakr
9 10 11 12
GDAEman MarKaAbyaYala quimogrande Markbearz
13 14 15 16
Gaby_Joy97 descuajeringado Jckarlos521 Barry__Ale
17 18 19 20
rt <- mt
V(rt)$color <- membership(mt.wt)
kcorewt <- coreness(rt, mode="all")
twocorewt <- induced_subgraph(rt, kcorewt>=2)
graph4 <- visIgraph(twocorewt,idToLabel = TRUE,layout = "layout_nicely") %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE)
graph4
By conditioning the transitivity (clustering) of the network on size, density, and dyads. We find that in 1,000 random networks, the variable number of nodes is able to produce a greater value than the observed graph’s transitivity.
This network graph has a low centralization score. Below it will be evaluated on indegree and outdegree vertices and conditioned on the variables size, density, and dyads. We find that in 1,000 random networks, none of the variables above were able to produce a value higher than the observed centralization score when based on indegree. However, the variable number of nodes was able to produce a greater value when evaluating for outdegrees.