If you look at the highlighted portions in the abstract you can probably figure out the kind of model that was used to get these results. Any guesses?
We will not go through the entire data analysis used in the paper but focus only on the relevant sections for this class. You can check out the replication package to work through the rest of the analysis. I highly recommend this if you want to learn data analysis using R. The author has also used R so it should be smooth.
The paper tests the following hypotheses:
As (perceived) polarization increases, partisans become less likely to negatively evaluate the economy when their party holds presidency. (Hypothesis 3a in the paper)
As perceived polarization increases, partisans who negatively evaluate the economy become less likely to punish their preferred party in response to economic conditions. (Hypothesis 3b in the paper)
where, the probability that the respondent \(i\) will select category \(e\) is a function of her perception, of the ideological gap between two major parties, a partisanship variable that indicates if the respondent is a member of the president’s party, independent or a member of the opposition party (Partisan), and several other control variables. \(e\) can take three values:
economy has gotten better
stayed the same
gotten worse
This model is slightly different from our earlier models. We have a dependent variable that is no longer a yes/no or a 1/0. But its still a discrete choice (just not binary). This kind of a model is called an ordered logit model where the dependent variable can represent ranks (ex: good to bad, high to low etc.). In addition to that we also have an interaction term \(\text{polarisation} \times \text{partisanship}\). You can read the paper to understand that. We are going to use the idea from the paper to test a very simple hypothesis.
First, lets simplify the dependent variable to a binary variable. Let’s say we are only interested in understanding whether a respondent would say that the economy is doing good or bad based on their party affiliation. Party affiliation is captured in the variable \(Partisan\). It can be either \(Inpart\) meaning that the respondent’s party is the party in power; and \(Outpart\) meaning the respondent’s party is the opposition. Then we test the following simplified hypothesis:
If my party is in power I would say that the economy is doing well, otherwise no.
I have pre-processed the data for you. You will need to run the codes in the class_demo1.R file to get this simplified dataset. Then, just load it here (from YOUR directory) and run the following codes.
# step 1: load the data (remember, you might have to load some packages)library(margins) # For marginal effectslibrary(gt) # For tables library(jtools) # For tables (has the export_summs function in it)library(ggeffects) # marginal effect of interaction terms library(ggplot2)library(tidyverse)load("C:/Users/rzs0133/OneDrive - Auburn University/Desktop_Auburn Department Computer/Teaching/R_probit_logit_models/Replication Data_Moreira et al 2024/voting_logit.RData")model_voting <-glm(econ_eval ~ percep_polar + partisan + female + black + hispanic + asian + other_race + log_age + college + income + election,family =binomial(link ="logit"),data = logit_data)# let's get the marginal effectsmargins_voting <-margins(model_voting, type ="response")export_summs(model_voting, margins_voting,model.names =c("Logit", "AME"))
Logit
AME
(Intercept)
-3.38 ***
(0.27)
percep_polar
0.75 ***
0.11 ***
(0.09)
(0.01)
partisanInpart
1.43 ***
0.28 ***
(0.07)
(0.01)
partisanOutpart
-1.21 ***
-0.16 ***
(0.08)
(0.01)
female
-0.26 ***
-0.04 ***
(0.04)
(0.01)
black
0.42 ***
0.06 ***
(0.08)
(0.01)
hispanic
0.21 **
0.03 **
(0.08)
(0.01)
asian
0.25
0.04
(0.13)
(0.02)
other_race
0.07
0.01
(0.11)
(0.02)
log_age
-0.11
-0.02
(0.06)
(0.01)
college
0.11 *
0.02 *
(0.05)
(0.01)
income
0.02 ***
0.00 ***
(0.00)
(0.00)
election1996
3.63 ***
0.51 ***
(0.37)
(0.06)
election2000
4.44 ***
0.65 ***
(0.19)
(0.02)
election2004
2.40 ***
0.30 ***
(0.15)
(0.02)
election2008
1.67 ***
0.19 ***
(0.22)
(0.03)
election2012
2.77 ***
0.36 ***
(0.13)
(0.01)
election2016
2.89 ***
0.39 ***
(0.13)
(0.01)
election2020
1.57 ***
0.17 ***
(0.13)
(0.01)
N
13940
0
AIC
12531.30
12531.30
BIC
12674.60
12674.60
Pseudo R2
0.45
*** p < 0.001; ** p < 0.01; * p < 0.05.
What if you wanted to also see the interaction effects of polarization and partisanship on the evaluation of the economy? We can run the model with the interaction term:
interaction_model <-glm(good_eval ~ percep_polar * partisan + female + black + hispanic + asian + other_race + log_age + college + income + election,family =binomial(link ="logit"),data = logit_data)interaction_margins1 <-margins(interaction_model, type ="response")export_summs(interaction_model, interaction_margins1,model.names =c("Logit", "AME"))
Logit
AME
(Intercept)
-3.33 ***
(0.28)
percep_polar
0.70 ***
0.11 ***
(0.20)
(0.01)
partisanInpart
0.96 ***
0.28 ***
(0.13)
(0.01)
partisanOutpart
-0.28
-0.16 ***
(0.15)
(0.01)
female
-0.26 ***
-0.04 ***
(0.05)
(0.01)
black
0.42 ***
0.06 ***
(0.08)
(0.01)
hispanic
0.22 **
0.03 **
(0.08)
(0.01)
asian
0.26
0.04
(0.13)
(0.02)
other_race
0.08
0.01
(0.11)
(0.02)
log_age
-0.11
-0.02
(0.06)
(0.01)
college
0.13 **
0.02 **
(0.05)
(0.01)
income
0.02 ***
0.00 ***
(0.00)
(0.00)
election1996
3.65 ***
0.52 ***
(0.36)
(0.06)
election2000
4.38 ***
0.64 ***
(0.19)
(0.02)
election2004
2.35 ***
0.29 ***
(0.15)
(0.02)
election2008
1.66 ***
0.18 ***
(0.22)
(0.03)
election2012
2.77 ***
0.37 ***
(0.13)
(0.01)
election2016
2.89 ***
0.39 ***
(0.13)
(0.01)
election2020
1.50 ***
0.16 ***
(0.13)
(0.01)
percep_polar:partisanInpart
0.81 ***
(0.23)
percep_polar:partisanOutpart
-1.56 ***
(0.25)
N
13940
0
AIC
12398.30
12398.30
BIC
12556.69
12556.69
Pseudo R2
0.45
*** p < 0.001; ** p < 0.01; * p < 0.05.
# what do you notice? the interaction terms don't have marginal effects.# we will use the ggeffect package to get the predicted probability for each combination which indirectly displays the interaction effects interaction_margins <-ggeffect(interaction_model, terms =c("partisan", "percep_polar[0.1, 0.5, 1]"), ci.lvl =0.95)# to visualize the marginal effects, we will have to convert the stored marginal effects first into a dataframe and then plot. I follow the same structure as the replication package.interaction_margins <-data.frame(interaction_margins)interaction_margins <- interaction_margins %>%rename(partisan = x) interaction_margins <- interaction_margins %>%mutate(partisan =factor(partisan, levels =c("Inpart", "Ind", "Outpart"),labels =c("President's Party", "Independent","Opposing Party")),group =as.factor(group))# now your interaction_margins data is ready for plottingggplot(interaction_margins, aes(shape = group)) +geom_pointrange(aes(x = partisan, y = predicted, ymin = conf.low, ymax = conf.high),lwd = .85, position =position_dodge(width = .5),color ="darkslategray") +theme_light() +labs(x ="Partisan Attachment", y ="Probability of Positive Economic Evaluation") +scale_shape_manual(name ="Perceived Ideological Gap:",labels =c("0.1", "0.5", "1"),values =c(15, 16, 17)) +scale_y_continuous(breaks =seq(0, 1, 0.2), limits =c(0, 1)) +theme(axis.text.x =element_text(hjust =0.5, size =12),axis.text.y =element_text(size =10),axis.title.x =element_text(size =12),axis.title.y =element_text(size =12),legend.text =element_text(size =12),legend.title =element_text(size =12),legend.position ="bottom",legend.direction ="horizontal",plot.title =element_text(size =14))
You can click on the link to the replication package and try running the other models. In the interest of time, I do not show it here.
Final Summary
We have learnt the following:
Estimation using logit and probit models
Estimate the marginal effects
Model interaction-terms
Extract the marginal effects of interaction terms and plot it graphically (for ease of interpretation)
References
M. Q. Moreira, Thiago. 2025. “Is It Still the Economy? Economic Voting in Polarized Politics.”British Journal of Political Science 55: e45. https://doi.org/10.1017/S0007123424000619.