DIY Conflict Model

April 23, 2024

Step 1: Get Data

peacesciencer package

library(peacesciencer)

conflict_df <- create_stateyears(system = 'gw') |>
  filter(year %in% c(1946:1999)) |>
  add_ucdp_acd(type=c("intrastate"), only_wars = FALSE) |>
  add_democracy() |>
  add_creg_fractionalization() |>
  add_sdp_gdp() |>
  add_rugged_terrain()

glimpse(conflict_df)
Rows: 7,036
Columns: 20
$ gwcode         <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ statename      <chr> "United States of America", "United States of America",…
$ year           <dbl> 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1…
$ ucdpongoing    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ ucdponset      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ maxintensity   <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ conflict_ids   <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ v2x_polyarchy  <dbl> 0.605, 0.587, 0.599, 0.599, 0.587, 0.602, 0.601, 0.594,…
$ polity2        <dbl> 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,…
$ xm_qudsest     <dbl> 1.259180, 1.259180, 1.252190, 1.252190, 1.270106, 1.259…
$ ethfrac        <dbl> 0.2226323, 0.2248701, 0.2271561, 0.2294918, 0.2318781, …
$ ethpol         <dbl> 0.4152487, 0.4186156, 0.4220368, 0.4255134, 0.4290458, …
$ relfrac        <dbl> 0.4980802, 0.5009111, 0.5037278, 0.5065309, 0.5093204, …
$ relpol         <dbl> 0.7769888, 0.7770017, 0.7770303, 0.7770729, 0.7771274, …
$ wbgdp2011est   <dbl> 28.539, 28.519, 28.545, 28.534, 28.572, 28.635, 28.669,…
$ wbpopest       <dbl> 18.744, 18.756, 18.781, 18.804, 18.821, 18.832, 18.848,…
$ sdpest         <dbl> 28.478, 28.456, 28.483, 28.469, 28.510, 28.576, 28.611,…
$ wbgdppc2011est <dbl> 9.794, 9.762, 9.764, 9.730, 9.752, 9.803, 9.821, 9.857,…
$ rugged         <dbl> 1.073, 1.073, 1.073, 1.073, 1.073, 1.073, 1.073, 1.073,…
$ newlmtnest     <dbl> 3.214868, 3.214868, 3.214868, 3.214868, 3.214868, 3.214…

Your Turn!

  • Install/load the peacesciencer package
  • Visit the package website
  • Create a conflict dataset based on the Gleditsch-Ward system of state-years
  • Filter the dataset to include only years between 1946 and 1999
  • Add UCDP/PRIO Armed Conflict Dataset (ACD) data on intrastate wars
  • Add sets of variables and glimpse() the dataset after each set
    • Democracy variables
    • Fractionalization variables
    • GDP variables
    • Rugged terrain variables
  • Others?
10:00

Step 2: Approximate F&L

Replicate Fearon and Laitin (2003)


One way to do it:

conflict_model <- glm(ucdponset ~ ethfrac + relfrac + v2x_polyarchy + rugged +
                        wbgdppc2011est + wbpopest,
                  data = conflict_df,
                  family = "binomial")

summary(conflict_model)

Call:
glm(formula = ucdponset ~ ethfrac + relfrac + v2x_polyarchy + 
    rugged + wbgdppc2011est + wbpopest, family = "binomial", 
    data = conflict_df)

Coefficients:
               Estimate Std. Error z value Pr(>|z|)    
(Intercept)    -5.69260    1.40788  -4.043 5.27e-05 ***
ethfrac         0.80005    0.38072   2.101  0.03560 *  
relfrac        -0.39138    0.41673  -0.939  0.34764    
v2x_polyarchy  -0.60161    0.50879  -1.182  0.23704    
rugged          0.06413    0.07603   0.843  0.39897    
wbgdppc2011est -0.37188    0.12059  -3.084  0.00204 ** 
wbpopest        0.29318    0.06735   4.353 1.34e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1182.5  on 6150  degrees of freedom
Residual deviance: 1126.7  on 6144  degrees of freedom
  (885 observations deleted due to missingness)
AIC: 1140.7

Number of Fisher Scoring iterations: 7

Your Turn!

  • Approximate the Fearon and Laitin (2003) model
  • Use the glm() function to run the model
  • Add measures of ethnicity, democracy, terrain, population and wealth
  • Try replacing the original measures with different ones of the same concept
    • What happens?
  • What else could you add?
10:00

Step 3: Visualize Your Model


So we can use ggplot to make a coefficient plot instead…


Two steps… First, we need a coeficient map:

coef_map <- c("ethfrac" = "Ethnic Frac",  # map coefficients
        "relfrac" = "Religions Frac",     #(change names and order)
        "v2x_polyarchy" = "Polyarchy",
        "rugged" = "Terrain",
        "wbgdppc2011est" = "Per capita GDP",
        "wbpopest" = "Population",
        "(Intercept)" = "Intercept")


Then, we can use modelplot to visualize the model:

library(modelsummary)
library(ggplot2)

modelplot(conflict_model, 
          coef_map = rev(coef_map), # rev() reverses list order
          coef_omit = "Intercept", 
          color = "blue") + # use plus to add customizations like any ggplot object
  geom_vline(xintercept = 0, color = "red", linetype = "dashed", linewidth = .75) + # red 0 line
  labs(
    title = "Figure 1: Predictors of Conflict Onset",
    caption = "See appendix for data sources."
  ) 

Your Turn!


  • Create a coefficient map for your model
  • Use modelplot to visualize your model
  • Don’t forget to add the title and caption
10:00

Step 4: Exponentiate the Coefficients

Exponentiate the Coefficients

Exponentiate the Coefficients

modelplot(conflict_model, 
          exponentiate = TRUE, # exponentiate coefficients
          coef_map = rev(coef_map), # rev() reverses list order
          coef_omit = "Intercept", 
          color = "blue") + # use plus to add customizations like any ggplot object
  geom_vline(xintercept = 1, color = "red", linetype = "dashed", linewidth = .75) + # red 0 line
  labs(
    title = "Figure 1: Predictors of Conflict Onset",
    caption = "See appendix for data sources."
  ) 

Your Turn!

  • Exponentiate the coefficients in your model
  • Do this by setting exponentiate = TRUE in modelplot
  • Interpret the results
10:00

Step 5: Model Predictions

Using marginaleffects

# load the marginaleffects library
library(marginaleffects)

# select some countries for a given year
selected_countries <- conflict_df |>
  filter(
    statename %in% c("United States of America", "Venezuela", "Rwanda"),
    year == 1999)

# calculate margins for the subset
marg_effects <- predictions(conflict_model, newdata = selected_countries)

# tidy the results
tidy(marg_effects) |>
  select(estimate, p.value, conf.low, conf.high, statename)

Using marginaleffects


# A tibble: 3 × 5
  estimate  p.value conf.low conf.high statename               
     <dbl>    <dbl>    <dbl>     <dbl> <chr>                   
1   0.0123 2.23e-28  0.00567    0.0264 United States of America
2   0.0140 2.25e-70  0.00879    0.0222 Venezuela               
3   0.0286 8.46e-39  0.0170     0.0477 Rwanda                  

Your Turn!


  • Use marginaleffects to calculate the predicted probabilities for a few countries
  • Interpret the results
10:00

Step 6: Regression Tables

Run Multiple Models

ethnicity <- glm(ucdponset ~ ethfrac + relfrac + wbgdppc2011est + wbpopest, # store each model in an object
                  data = conflict_df,
                  family = "binomial")

democracy <- glm(ucdponset ~ v2x_polyarchy + wbgdppc2011est +  wbpopest,
                  data = conflict_df,
                  family = "binomial")

terrain <- glm(ucdponset ~ rugged + wbgdppc2011est + wbpopest ,
                  data = conflict_df,
                  family = "binomial")

full_model <- glm(ucdponset ~ ethfrac + relfrac + v2x_polyarchy + rugged +
                        wbgdppc2011est + wbpopest,
                  data = conflict_df,
                  family = "binomial")

Prep Data for Display


models <- list("Ethnicity" = ethnicity,  # store list of models in an object
               "Democracy" = democracy, 
               "Terrain" = terrain, 
               "Full Model" = full_model)

coef_map <- c("ethfrac" = "Ethnic Frac",  # map coefficients
        "relfrac" = "Religions Frac",     #(change names and order)
        "v2x_polyarchy" = "Polyarchy",
        "rugged" = "Terrain",
        "wbgdppc2011est" = "Per capita GDP",
        "wbpopest" = "Population",
        "(Intercept)" = "Intercept")

caption = "Table 1: Predictors of Conflict Onset" # store caption
reference = "See appendix for data sources."      # store reference notes

Display the Models


Note that you also need the gt package to display the table in this way…

library(modelsummary)
library(gt)

modelsummary(models,                      # display the table
             stars = TRUE,                # include stars for significance
             gof_map = c("nobs"),         # goodness of fit stats to include   
             coef_map = coef_map,         # coefficient mapping
             title = caption,             # title
             notes = reference, 
             output = "gt")           # source note

Display the Models

Table 1: Predictors of Conflict Onset
Ethnicity Democracy Terrain Full Model
Ethnic Frac 0.744* 0.800*
(0.367) (0.381)
Religions Frac -0.481 -0.391
(0.411) (0.417)
Polyarchy -0.228 -0.602
(0.436) (0.509)
Terrain 0.031 0.064
(0.076) (0.076)
Per capita GDP -0.474*** -0.512*** -0.543*** -0.372**
(0.104) (0.108) (0.092) (0.121)
Population 0.282*** 0.297*** 0.299*** 0.293***
(0.067) (0.051) (0.050) (0.067)
Intercept -4.703*** -4.407*** -4.296*** -5.693***
(1.327) (1.205) (1.143) (1.408)
Num.Obs. 6364 6772 6840 6151
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
See appendix for data sources.

Your Turn!

  • Run multiple models
  • Display the results in a regression table
  • Try rerunning with exponentiate = TRUE
  • Try getting predicted probabilities with marginaleffects
10:00