Select variables of interest

V241221 (party id); V241177 (ideology); V241551 (gender); V241501x (race); V242337 (social class); V241465x (education); V241566x (household income); V241458x (age); V242305 (Because of the rich and powerful, it becomes difficult for the rest of us to get ahead); V242350 (minimum wage increase); V242316b (tax on millionaires); V242253x (government should reduce income inequality).

df_anes <- df_anes_raw %>% 
  rename(party_id = V241221,
         ideo = V241177,
         gender = V241551,
         race = V241501x,
         class = V242337,
         edu = V241465x,
         income = V241566x,
         age = V241458x,
         class_zs = V242305,
         minwage = V242350,
         taxrich = V242316b,
         reduceineq = V242253x) %>% 
  select(party_id,
         ideo,
         gender,
         race,
         class,
         edu,
         income,
         age,
         class_zs,
         minwage,
         reduceineq)

clean data

df_anes <- df_anes %>% 
  mutate(party_id = case_when(party_id == 1 ~ "dem",
                              party_id == 2 ~ "rep",
                              party_id == 3 ~ "ind",
                              party_id == 5 ~ "other",
                              .default = NA),
         ideo = case_when(ideo < 0 ~ NA,
                          ideo == 99 ~ NA,
                          .default = as.numeric(ideo)),
         gender = case_when(gender == 1 ~ "man",
                            gender == 2 ~ "woman",
                            gender == 3 ~ "nonbinary",
                            gender == 4 ~ "other",
                            .default = NA),
         race = case_when(race == 1 ~ "white,non-hisp",
                          race == 2 ~ "black,non-hisp",
                          race == 3 ~ "hisp",
                          race == 4 ~ "asian,non-hisp",
                          race == 5 ~ "native,non-hisp",
                          race == 6 ~ "multiracial,non-hisp",
                          .default = NA),
         class = case_when(class == 1 ~ "lower",
                           class == 2 ~ "working",
                           class == 3 ~ "middle",
                           class == 4 ~ "upper",
                           .default = NA),
         edu = case_when(edu < 0 ~ NA,
                         .default = as.numeric(edu)),
         income = case_when(income < 0 ~ NA,
                            .default = as.numeric(income)),
         age = case_when(age < 0 ~ NA,
                         .default = as.numeric(age)),
         class_zs = case_when(class_zs < 0 ~ NA,
                              .default = as.numeric(class_zs)),
         minwage = case_when(minwage < 0 ~ NA,
                             .default = as.numeric(minwage)),
         reduceineq = case_when(reduceineq < 0 ~ NA,
                                .default = as.numeric(reduceineq))) %>% 
  mutate(minwage_R = 5 - minwage,
         reduceineq_R = 8 - reduceineq,
         class_num = as.numeric(factor(class,levels = c("lower",
                                                           "working",
                                                           "middle",
                                                           "upper"))))

Ok, because the social class variable doesn’t really let us see if people self-identify as working class independently (it’s part of the SES scale), we’re gonna try to separate them out by looking at an objective measure: education. Anyone with a college degree who identifies as working class will be a 1. Those with a college degree who do not identify as working class will be a 0. Anyone without a college degree will be NA (note: this is just for a very specific analysis that I’ll try later).

df_anes <- df_anes %>% 
  mutate(wrkclassidentity = ifelse(edu > 3 & class == "working",1,
                                   ifelse(edu > 3 & class != "working",0,NA)))

Descriptives

Alright, let’s take a look at our sample.

Race

df_anes %>% 
  group_by(race) %>% 
  summarise(N = n()) %>% 
  ungroup() %>% 
  mutate(Perc = round(100*(N/sum(N)),2)) %>% 
  ungroup() %>% 
  arrange(desc(N)) %>% 
  kbl() %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
race N Perc
white,non-hisp 3946 71.47
hisp 582 10.54
black,non-hisp 508 9.20
asian,non-hisp 197 3.57
multiracial,non-hisp 188 3.41
NA 67 1.21
native,non-hisp 33 0.60

Gender

df_anes %>% 
  group_by(gender) %>% 
  summarise(N = n()) %>% 
  ungroup() %>% 
  mutate(Perc = round(100*(N/sum(N)),2)) %>% 
  ungroup() %>% 
  arrange(desc(N)) %>% 
  kbl() %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
gender N Perc
woman 2773 50.23
man 2397 43.42
NA 287 5.20
nonbinary 46 0.83
other 18 0.33

Education

  1. Less than high-school
  2. High school
  3. Some post high-school
  4. Bachelor’s degree
  5. Graduate degree
df_anes %>% 
  group_by(edu) %>% 
  summarise(N = n()) %>% 
  ungroup() %>% 
  mutate(Perc = round(100*(N/sum(N)),2)) %>% 
  ungroup() %>% 
  arrange(edu) %>% 
  kbl() %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
edu N Perc
1 282 5.11
2 971 17.59
3 1726 31.26
4 1374 24.89
5 1081 19.58
NA 87 1.58

Income

1 = Under 5000 to 28 = Over 250,000

df_anes %>% 
  ggplot(aes(x = income)) +
  geom_histogram(fill = "lightblue",
                 color = NA,
                 binwidth = 1) +
  scale_x_continuous(breaks = seq(1,28,3),
                     limits = c(0,29)) +
  geom_vline(xintercept = median(df_anes$income,na.rm = T),
             color = "grey15",
             size = 1,
             linetype = "dashed") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_line(color = "grey66"),
        axis.text.y = element_text(color = "black"),
        axis.text.x = element_text(color = "black",
                                   face = "bold"),
        axis.title.x = element_text(color = "black",
                                   face = "bold"))

Class

df_anes %>% 
  group_by(class) %>% 
  summarise(N = n()) %>% 
  ungroup() %>% 
  mutate(Perc = round(100*(N/sum(N)),2)) %>% 
  ungroup() %>% 
  kbl() %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
class N Perc
lower 418 7.57
middle 2520 45.64
upper 263 4.76
working 1707 30.92
NA 613 11.10

Class and education

I just want to square them to see how many people identify as working class even when they have a bachelor’s degree

df_anes %>% 
  group_by(edu,class) %>% 
  summarise(N = n()) %>% 
  ungroup() %>% 
  kbl() %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
## `summarise()` has grouped output by 'edu'. You can override using the `.groups`
## argument.
edu class N
1 lower 45
1 middle 70
1 upper 6
1 working 104
1 NA 57
2 lower 153
2 middle 270
2 upper 18
2 working 398
2 NA 132
3 lower 155
3 middle 646
3 upper 26
3 working 695
3 NA 204
4 lower 43
4 middle 790
4 upper 81
4 working 339
4 NA 121
5 lower 13
5 middle 709
5 upper 131
5 working 148
5 NA 80
NA lower 9
NA middle 35
NA upper 1
NA working 23
NA NA 19

Age

Note that they just assigned 80 to anyone over 80, so it looks skewed.

df_anes %>% 
  ggplot(aes(x = age)) +
  geom_histogram(fill = "lightblue",
                 color = NA,
                 binwidth = 1) +
  # scale_x_continuous(breaks = seq(1,28,3),
  #                    limits = c(0,29)) +
  geom_vline(xintercept = mean(df_anes$age,na.rm = T),
             color = "grey15",
             size = 1,
             linetype = "dashed") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_line(color = "grey66"),
        axis.text.y = element_text(color = "black"),
        axis.text.x = element_text(color = "black",
                                   face = "bold"),
        axis.title.x = element_text(color = "black",
                                   face = "bold"))

Party ID

df_anes %>% 
  group_by(party_id) %>% 
  summarise(N = n()) %>% 
  ungroup() %>% 
  mutate(Perc = round(100*(N/sum(N)),2)) %>% 
  ungroup() %>% 
  arrange(desc(N)) %>% 
  kbl() %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
party_id N Perc
dem 1865 33.78
rep 1652 29.92
ind 1553 28.13
NA 298 5.40
other 153 2.77

Political ideology

1 = Extremely Liberal to 7 = Extremely Conservative

df_anes %>% 
  ggplot(aes(x = ideo)) +
  geom_histogram(fill = "lightblue",
                 color = NA,
                 binwidth = 1) +
  scale_x_continuous(breaks = seq(1,7,1),
                      limits = c(0,8)) +
  geom_vline(xintercept = mean(df_anes$ideo,na.rm = T),
             color = "grey15",
             size = 1,
             linetype = "dashed") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_line(color = "grey66"),
        axis.text.y = element_text(color = "black"),
        axis.text.x = element_text(color = "black",
                                   face = "bold"),
        axis.title.x = element_text(color = "black",
                                   face = "bold"))

Class Zero-Sum

How well does the following statement describe your view? (1 = Not at all well to 5 = Extremely well)

Because of the rich and powerful, it becomes difficult for the rest of us to get ahead.

df_anes %>% 
  ggplot(aes(x = class_zs)) +
  geom_histogram(fill = "lightblue",
                 color = NA,
                 binwidth = 1) +
  scale_x_continuous(breaks = seq(1,5,1),
                    limits = c(0,6)) +
  geom_vline(xintercept = mean(df_anes$class_zs,na.rm = T),
             color = "grey15",
             size = 1,
             linetype = "dashed") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_line(color = "grey66"),
        axis.text.y = element_text(color = "black"),
        axis.text.x = element_text(color = "black",
                                   face = "bold"),
        axis.title.x = element_text(color = "black",
                                   face = "bold"))

Minimum wage increase

Should the federal minimum wage be [raised (4), kept the same (3),lowered but not eliminated (2), or eliminated altogether (1)]?

df_anes %>% 
  ggplot(aes(x = minwage_R)) +
  geom_histogram(fill = "lightblue",
                 color = NA,
                 binwidth = 1) +
  scale_x_continuous(breaks = seq(1,4,1),
                    limits = c(0,5)) +
  geom_vline(xintercept = mean(df_anes$minwage_R,na.rm = T),
             color = "grey15",
             size = 1,
             linetype = "dashed") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_line(color = "grey66"),
        axis.text.y = element_text(color = "black"),
        axis.text.x = element_text(color = "black",
                                   face = "bold"),
        axis.title.x = element_text(color = "black",
                                   face = "bold"))

Reduce inequality

Do you favor or oppose, or neither favor nor oppose the government trying to reduce the difference in incomes between the richest and poorest households? (1 = Oppose a great deal to 7 = Favor a great deal)

df_anes %>% 
  ggplot(aes(x = reduceineq_R)) +
  geom_histogram(fill = "lightblue",
                 color = NA,
                 binwidth = 1) +
  scale_x_continuous(breaks = seq(1,7,1),
                    limits = c(0,8)) +
  geom_vline(xintercept = mean(df_anes$reduceineq_R,na.rm = T),
             color = "grey15",
             size = 1,
             linetype = "dashed") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_line(color = "grey66"),
        axis.text.y = element_text(color = "black"),
        axis.text.x = element_text(color = "black",
                                   face = "bold"),
        axis.title.x = element_text(color = "black",
                                   face = "bold"))

Analysis

Correlation matrix

df_anes %>% 
  select(class_zs,minwage_R,reduceineq_R,ideo,income,edu,age) %>%
  corPlot(upper = TRUE,stars = TRUE,xsrt = 270)

The “reducing inequality” item looks very weird. Feels like they made a coding error, or the codebook is wrong. I think it’s the opposite of what they’re saying. Hmm. The rest makes sense.

Linear models

Linear model 1A

Outcome: Minimum wage support; predictor: class zero-sum.

m1 <- lm(minwage_R ~ class_zs,data = df_anes)

apa_lm <- apa_print(m1)

kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 2.81 [2.74, 2.88] 82.54 4854 < .001
Class zs 0.19 [0.17, 0.21] 19.15 4854 < .001

Linear model 1B

Outcome: Minimum wage support;
Predictor: class zero-sum;
Controls: Party ID and political ideology

m1 <- lm(minwage_R ~ class_zs + party_id + ideo,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.79 [3.68, 3.90] 66.20 4045 < .001
Class zs 0.10 [0.08, 0.12] 8.91 4045 < .001
Party idind -0.14 [-0.20, -0.07] -4.21 4045 < .001
Party idother -0.47 [-0.63, -0.31] -5.67 4045 < .001
Party idrep -0.29 [-0.37, -0.21] -7.04 4045 < .001
Ideo -0.13 [-0.15, -0.11] -13.26 4045 < .001

Linear model 1C

Outcome: Minimum wage support;
Predictor: class zero-sum;
Controls: Party ID, political ideology, race, gender, income, education, and age

m1 <- lm(minwage_R ~ class_zs + party_id + ideo + race + gender + income + edu + age,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.76 [3.53, 3.99] 32.00 3676 < .001
Class zs 0.10 [0.08, 0.12] 8.47 3676 < .001
Party idind -0.10 [-0.17, -0.03] -2.90 3676 .004
Party idother -0.45 [-0.62, -0.27] -5.09 3676 < .001
Party idrep -0.27 [-0.36, -0.19] -6.34 3676 < .001
Ideo -0.13 [-0.16, -0.11] -12.51 3676 < .001
Raceblack,non-hisp 0.07 [-0.10, 0.23] 0.81 3676 .415
Racehisp 0.10 [-0.05, 0.26] 1.30 3676 .192
Racemultiracial,non-hisp 0.07 [-0.12, 0.26] 0.74 3676 .459
Racenative,non-hisp 0.12 [-0.28, 0.51] 0.58 3676 .562
Racewhite,non-hisp 0.00 [-0.14, 0.13] -0.03 3676 .973
Gendernonbinary 0.13 [-0.13, 0.38] 0.97 3676 .331
Genderother 0.05 [-0.48, 0.58] 0.19 3676 .849
Genderwoman 0.14 [0.09, 0.19] 5.41 3676 < .001
Income 0.00 [-0.01, 0.00] -1.21 3676 .228
Edu -0.02 [-0.05, 0.00] -1.87 3676 .061
Age 0.00 [0.00, 0.00] 1.39 3676 .165

Linear model 1D

Outcome: Minimum wage support;
Predictor: class zero-sum;
Controls: Party ID, political ideology, race, gender, income, education, age, and class

m1 <- lm(minwage_R ~ class_zs + party_id + ideo + race + gender + income + edu + age + class,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.76 [3.52, 4.00] 30.31 3670 < .001
Class zs 0.10 [0.08, 0.12] 8.34 3670 < .001
Party idind -0.10 [-0.17, -0.03] -2.97 3670 .003
Party idother -0.45 [-0.62, -0.28] -5.10 3670 < .001
Party idrep -0.27 [-0.36, -0.19] -6.35 3670 < .001
Ideo -0.13 [-0.15, -0.11] -12.44 3670 < .001
Raceblack,non-hisp 0.07 [-0.10, 0.23] 0.81 3670 .421
Racehisp 0.11 [-0.05, 0.26] 1.33 3670 .185
Racemultiracial,non-hisp 0.07 [-0.12, 0.26] 0.73 3670 .464
Racenative,non-hisp 0.11 [-0.29, 0.50] 0.54 3670 .589
Racewhite,non-hisp 0.00 [-0.14, 0.14] 0.02 3670 .986
Gendernonbinary 0.12 [-0.13, 0.37] 0.92 3670 .356
Genderother 0.04 [-0.48, 0.57] 0.16 3670 .871
Genderwoman 0.14 [0.09, 0.19] 5.39 3670 < .001
Income 0.00 [0.00, 0.00] -0.67 3670 .501
Edu -0.02 [-0.05, 0.01] -1.42 3670 .154
Age 0.00 [0.00, 0.00] 1.67 3670 .095
Classmiddle -0.08 [-0.19, 0.04] -1.34 3670 .180
Classupper 0.00 [-0.15, 0.15] 0.03 3670 .979
Classworking -0.02 [-0.13, 0.08] -0.43 3670 .667

Linear model 2

Ok, let’s take only those who have a bachelor’s degree or more (that’s what’s often used a separator of working class from middle class). And for them, we’ll see if they identify as working class.

Outcome: Minimum wage support;
Predictor: identifying as working class
Subsample: Only those with bachelor’s degree or more

m1 <- lm(minwage_R ~ wrkclassidentity,data = df_anes %>% filter(!is.na(wrkclassidentity)))

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.42 [3.38, 3.46] 165.82 2237 < .001
Wrkclassidentity 0.04 [-0.05, 0.12] 0.85 2237 .394

hmm, they’re not more likely to support minimum wage increase. Ok.

Linear model 3A

Let’s just see if class is predictive of minimum wage support at all. Here, we’ll treat class a numeric variable (1 = lower; 2 = working; 3 = middle; 4 = upper).

Outcome: Minimum wage support;
Predictor: class

m1 <- lm(minwage_R ~ class_num,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.60 [3.51, 3.68] 81.03 4871 < .001
Class num -0.07 [-0.10, -0.04] -4.11 4871 < .001

Linear model 3B

Outcome: Minimum wage support;
Predictor: class;
Controls: Education and income

m1 <- lm(minwage_R ~ class_num + edu + income,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.55 [3.45, 3.66] 68.70 4377 < .001
Class num -0.07 [-0.11, -0.03] -3.60 4377 < .001
Edu 0.04 [0.02, 0.07] 3.16 4377 .002
Income 0.00 [-0.01, 0.00] -2.43 4377 .015

Linear model 3C

Outcome: Minimum wage support;
Predictor: class;
Controls: Education, income, race, gender, age

m1 <- lm(minwage_R ~ class_num + edu + income + race + gender + age,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 3.34 [3.15, 3.54] 34.22 4240 < .001
Class num -0.05 [-0.09, -0.01] -2.39 4240 .017
Edu 0.04 [0.01, 0.06] 2.92 4240 .003
Income 0.00 [0.00, 0.00] -0.57 4240 .571
Raceblack,non-hisp 0.26 [0.10, 0.42] 3.21 4240 .001
Racehisp 0.15 [-0.01, 0.31] 1.86 4240 .063
Racemultiracial,non-hisp 0.07 [-0.12, 0.26] 0.76 4240 .448
Racenative,non-hisp 0.15 [-0.20, 0.50] 0.83 4240 .409
Racewhite,non-hisp -0.02 [-0.16, 0.12] -0.30 4240 .762
Gendernonbinary 0.43 [0.17, 0.68] 3.23 4240 .001
Genderother 0.26 [-0.18, 0.69] 1.15 4240 .251
Genderwoman 0.23 [0.18, 0.28] 8.90 4240 < .001
Age 0.00 [0.00, 0.00] -1.11 4240 .267

Linear model 3D

Outcome: Minimum wage support;
Predictor: class;
Controls: Education, income, race, gender, age, party ID, and political ideology

m1 <- lm(minwage_R ~ class_num + edu + income + race + gender + age + party_id + ideo,data = df_anes)

apa_lm <- apa_print(m1)
kbl(apa_lm$table) %>% 
  kable_styling(bootstrap_options = "hover",
                full_width = F,
                position = "left")
term estimate conf.int statistic df p.value
Intercept 4.31 [4.10, 4.52] 40.57 3678 < .001
Class num -0.04 [-0.08, 0.00] -2.05 3678 .041
Edu -0.02 [-0.05, 0.00] -1.61 3678 .107
Income 0.00 [-0.01, 0.00] -0.97 3678 .331
Raceblack,non-hisp 0.07 [-0.09, 0.24] 0.86 3678 .392
Racehisp 0.10 [-0.05, 0.26] 1.30 3678 .193
Racemultiracial,non-hisp 0.08 [-0.11, 0.27] 0.80 3678 .424
Racenative,non-hisp 0.16 [-0.23, 0.54] 0.79 3678 .430
Racewhite,non-hisp 0.01 [-0.13, 0.14] 0.08 3678 .934
Gendernonbinary 0.12 [-0.14, 0.37] 0.89 3678 .371
Genderother 0.07 [-0.46, 0.60] 0.27 3678 .790
Genderwoman 0.14 [0.09, 0.19] 5.43 3678 < .001
Age 0.00 [0.00, 0.00] 0.24 3678 .808
Party idind -0.12 [-0.19, -0.05] -3.47 3678 < .001
Party idother -0.47 [-0.65, -0.30] -5.37 3678 < .001
Party idrep -0.32 [-0.40, -0.23] -7.34 3678 < .001
Ideo -0.15 [-0.17, -0.13] -14.48 3678 < .001

Mediation

Mediation model 1

Predictor: Class Zero-Sum
Mediator: Class
Outcome: Minimum wage support

m1 <- psych::mediate(minwage_R ~ class_zs + (class_num),data = df_anes,std = T,n.iter = 10000)

beta coefficients are standardized

a = -0.14 (p = 0)
b = -0.02 (p = 0.083)
c = 0.26 (p = 0)
c’= 0.26 (p = 0)

Mediation model 2

Predictor: Class
Mediator: Class Zero-Sum
Outcome: Minimum wage support

m1 <- psych::mediate(minwage_R ~ class_num + (class_zs),data = df_anes,std = T,n.iter = 10000)


a = -0.14 (p = 0)
b = 0.26 (p = 0)
c = -0.06 (p = 0)
c’= -0.02 (p = 0.083)