Elections in a Post-Roe Era: An Analysis of the 2022 Midterms Elections

By: Michael Dunphy

Presentation on the topic given at the University of Maryland, College Park on April 11th, 2023 as part of the Applied Political Analytics Master’s Program.

TL;DR

This research uses data at the candidate and district level to understand the impact of the Dobbs decision on the 2022 U.S. Midterm elections at the U.S. House and U.S. Senate level. Two measurements were modeled, controlling for relevant factors, to track individual candidate performance: individual contribution fundraising after the Dobbs decision and candidate win probability. Two measurements were modeled, controlling for relevant factors, to track electoral performance at the district level: vote margin shift from the 2020 Presidential election and the probability of a Democrat winning based on district characteristics. It was found that states with higher salience of abortion, measured by Google Trends search data, increased Democratic candidate fundraising at both office levels. States that implemented abortion bans or were hostile towards abortion saw an increased shift in Democratic vote share from the 2020 Presidential election at both office levels. It is recommended that Democrats focus on the abortion issue in campaign and party messaging in the upcoming 2024 elections to increase candidate fundraising performance and raise awareness of bans and hostile policies toward abortion to mobilize pro-choice voters, increasing Democratic vote share. Recommended competitive House districts to implement this strategy include: AZ-1, AZ-6, IA-3, MI-10, MT-1, NE-2, and WI-3. Recommended competitive Senate races to implement this strategy include: AZ, WI, and PA.

Introduction

On June 24th, 2022, the United States Supreme court decided in Dobbs v. Jackson Women’s Health Organization that the U.S. constitution does not provide the right to abortion, overruling Roe v. Wade and Planned Parenthood v. Casey. This gave individual states the power to regulate any aspect of abortion not protected by federal law. Debate over the abortion issue increased with many states implementing trigger bans and several other states proposing policies hostile towards abortion. This made abortion a highly salient issue during the 2022 Midterm election cycle with many candidates discussing the Dobbs decision in campaign messaging.

Political science research has shown that abortion can be considered an “easy issue” due to its persistence, salience, and ability to be easily understood election cycle to election cycle. The abortion issue has gradually transformed the political parties with elites polarizing on the issue with Democrats adopting the “pro-choice” policy position and Republicans adopting the “pro-life” policy position. This led to mass level polarization with voters sorting themselves along party lines on this issue. Previous research has shown that past Supreme Court decisions on abortion have had electoral impacts including influences on U.S. President, Senate, House, gubernatorial, and state legislature elections.

Given the surprising midterm election results with Democrats overperforming fundamentals and the high salience of abortion this election cycle, this research looks to address the question: what impact did the Dobbs decision have on the results of the 2022 U.S. House and U.S. Senate midterm elections?

Research Design

Four hypotheses were formed to test the electoral impact of the Dobbs decision:

  • Increased salience of abortion will improve the performance for Democrats as pro-choice voters will be mobilized due to the loss of the constitutional right to an abortion
  • Increased performance for Democrats in states that have banned or are hostile towards abortion
  • Gender of candidates will be significant with women Democratic candidates overperforming since voters assume Democrats and women candidates to be more pro-choice
  • Increased share of college educated voters and religious adherence of Evangelical protestants at the district level will increase and decrease Democratic performance respectively as these are major predictors of an individual’s position on abortion

Data used in this analysis was collected from multiple sources including:

  • FiveThirtyEight: 2022 U.S. House and U.S. Senate candidate data
  • Federal Election Commission (FEC): Individual contribution fundraising data
  • Dave’s Redistricting App (DRA): 2020 Presidential vote share by district
  • The New York Times: 2022 Midterm election results
  • Ballotpedia/Cook Political Report/USA Today: 2022 Midterm vote share margin shift from 2020 Presidential election at the district level
  • Census Bureau: 2021 American Community Survey demographic data at the district level
  • Google Trends: Number of searches including “abortion” at the state level in the last week of the election cycle relative to the 2022 peak for that state
  • Center for Reproductive Rights: Abortion law status tracking states that have implemented abortion bans or have hostile policies towards abortion at the state level
  • Association of Religion Data Archives: Religious adherence rate per 1,000 for Evangelical Protestants at the state level

Four multivariate regression models were created to measure electoral performance, controlling for relevant variables, among House, Senate, and competitive House candidates/districts with competitive House districts being determined by the 2020 Presidential vote share being within a margin of 10 ppt. The four measurements of electoral performance include: individual contribution fundraising proportion after the Dobbs decision (Democrat fundraising amount / Democrat and Republican fundraising amount in race), candidate win probability, vote margin shift from the 2020 Presidential election, and the probability of a Democrat winning based on district characteristics. Data was collected and processed in R with data visuals created in Tableau. The R Markdown file and Tableau workbook can be viewed on github upon request along with data files for replication purposes. Districts without a Democratic or Republican opponent or had two Republicans/Democrats running against each other were removed resulting in 848 candidates (786 House candidates, 62 Senate candidates) and 424 districts (393 House districts, 31 Senate districts) included in analysis.

Results

The results of the first model measuring the fundraising proportion of individual contributions given to candidates after the Dobbs decision found that salience of abortion was statistically significant, increasing the post-Dobbs fundraising proportion for Democrats among House, Senate, and Competitive House candidates. Abortion law status (whether the state banned or had hostile policies towards abortion) significantly increased the fundraising proportion for Democrats at the Senate level with religious adherence slightly increasing the fundraising proportion for Democrats among all House candidates. The results of the second model measuring the probability of a candidate winning the general election found that gender was the only variable of interest to be statistically significant, increasing the probability of a candidate win when the candidate was a woman by 8%.

The results of the third model measuring the Democratic vote margin shift from the 2020 Presidential election to the 2022 Midterm election found that salience of abortion significantly decreased the margin shift among all House districts while abortion law status significantly increased the vote margin shift among all House and Competitive House districts. Religious adherence for Evangelical Protestants significantly decreased the margin shift among all House districts. The results of the final model measuring the probability of a Democratic candidate winning based on district characteristics found that none of the variables of interest were statistically significant predictors.

It was found through this analysis that election denialism of the 2020 Presidential election hurt Republican candidates, decreasing the post-Dobbs fundraising proportion for these candidates by 16 ppt at the Senate level and increasing the shift in Democratic vote margin from 2020 by 1.3 ppt among all House districts. However, this helped House GOP candidates in the post-Dobbs fundraising proportion by 5 ppt.

Recommendations

Looking at the 2024 elections, it is recommended the Democratic party: Focus on the abortion issue in campaign and party messaging as increased salience on this issue increased Democratic candidate fundraising Raise awareness of bans and hostile abortion policies from GOP state legislatures as pro-choice voters become mobilized, increasing Democratic vote share Tie the Dobbs decision and election denialism to the GOP as these are unpopular issues that Democrats can use to hurt GOP candidate electoral performance

Pick-up House districts that were within a margin of 5 ppt in 2022 to target in 2024 with this strategy include: AZ-1, AZ-6, IA-3, MI-10, MT-1, NE-2, and WI-3. Competitive Senate districts to target in 2024 with this strategy include AZ, WI, and PA. These districts all have low Evangelical religious adherence rates at the state level and could improve candidate fundraising and voter mobilization efforts with a strategy focusing on the abortion issue.

Data

Data collected for this analysis came from multiple sources. To start, data was collected from 538’s “2022 Primary Project” GitHub repository which tracked the 2022 midterm primary candidates at the federal level. This data was processed to extract general election candidates by filtering candidates based on whether or not they won their primary election (or if there was one, their runoff election). 900 candidates were pulled with information on endorsements, incumbency status, race, and gender of the candidates.

Contributions to candidates were provided by the FEC which tracks federal level campaign finance information. This data included ‘Candidate master’, ‘Candidate-committee linkages’, and ‘Contributions by individuals’ on the bulk data webpage. Candidates not matched by the FEC fundraising data were manually confirmed on the FEC website to not having contribution records for this election cycle.

Google trends data was provided by Google, using the gtrendsR R package to identify the salience of the abortion issue this election cycle for each state.

District level data was provided by Dave’s Redistricting App (DRA) for each state. This data was manually collected for each state and inputted into this google sheet. The sources of data and processing done to calculate these values for districts can be viewed on DRA’s website. Data that was used was the 2020 presidential vote share for each party.

Election result data was manually collected for the New York Times Midterm Tracker for house and senate candidates and inputted into this google sheet.

Vote margin shift from 2020 Presidential election to 2022 Midterm election was collected in this google sheet. House level shift is provided by Ballotpedia and Senate level shift was calculated using data provided by Cook Political Report and USA Today.

Urbanization index of districts was provided by 538 and collected in this google sheet. House level data source can be found here and Senate level data source can be found here.

State region was provided by the Census Bureau and collected in this google sheet. The data source can be found here.

Religious adherence rates by state was provided by the Association of Religion Data Archives and collected in this google sheet. The data source can be found here.

State abortion law status was provided by the Center for Reproductive Rights and was collected in this google sheet. The data source can be found here.

Actions

  • Candidates loaded from 538 and processed to only include general election candidates
  • FEC data (individual donations, candidates, candidate-committee link) was collected for the 2022 cycle and joined together. Fundraising amount total past Dobbs decision date (6/24/2022) aggregated by candidate.
  • FEC data and 538 candidates joined on LAST NAME, STATE, OFFICE, DISTRICT
  • Candidates not matched were checked with FEC website to make sure there were no records of transactions for these candidates
  • Districts with no Democratic or Republican opponent, had either two Republicans or two Democrats running were filtered out. 846 candidates (784 House candidates, 62 Senate candidates, 423 districts (392 House districts, 31 Senate districts)
  • District level data was aggregated and district level variables were calculated
  • DRA data (2020 pres Dem margin) was added to the district level data set
  • NYT election results (winner) was added to the candidate level data set
  • Shift from Pres 2020 was added to the district level data set
  • State abortions status was added to the district level data set with three numeric dummy variables representing: illegal status, hostile status, and other status
  • Google Trends data with number of hits for “abortion” last week of election cycle relative to 2022 peak was added to the district level data set
  • Census data (education, income, age, gender, and share white) processed and added to district level data
  • State region was processed and added to district level data
  • Urbanization index was processed and added to district level data
  • Religious adherence rate per 1000 by state was processed and added to district level data
  • Created three types for candidate and district data sets: house candidates/districts, senate candidates/districts, competitive house candidates/districts (competitive determined by 2020 margin within 10%)
  • Created the linear and logistic models with formatted output

Code

Candidate Information

# load 538 primary candidates
dem <- read.csv("https://raw.githubusercontent.com/fivethirtyeight/data/master/primary-project-2022/dem_candidates.csv") %>%
        select(Candidate, State, Office, District, Gender, Race.1, Race.2, Incumbent, Primary.Outcome, Runoff.Outcome)
rep <- read.csv("https://raw.githubusercontent.com/fivethirtyeight/data/master/primary-project-2022/rep_candidates.csv") %>%
        select(Candidate, State, Office, District, Gender, Race.1, Race.2, Incumbent, Primary.Outcome, Runoff.Outcome, X2020.Election.Stance)

# process 538 primary candidate data 
dem["Party"] <- "DEM"
rep["Party"] <- "GOP"

full_primary_candidates <- rbind.fill(dem, rep)
# head(full_primary_candidates)

# grab general election candidates 
# create new column for general election status
full_primary_candidates["General.Election.Candidate"] <- FALSE

# determine general election candidate
for (i in 1:nrow(full_primary_candidates)) {
  if (full_primary_candidates[i, "Primary.Outcome"] == "Won") {
    full_primary_candidates[i, "General.Election.Candidate"] <- TRUE
  } else if (full_primary_candidates[i, "Primary.Outcome"] == "Made runoff") {
    if (full_primary_candidates[i, "Runoff.Outcome"] == "Won" || full_primary_candidates[i, "Runoff.Outcome"] == "" || is.null(full_primary_candidates[i, "Runoff.Outcome"])) {
      full_primary_candidates[i, "General.Election.Candidate"] <- TRUE
    }
  }
}

# filter only general election candidates
full_general_candidates <- full_primary_candidates %>%
                            filter(General.Election.Candidate == TRUE) %>%
                            filter(Office == "Representative" | Office == "Senator (unexpired term)" | Office == "Senator")

# convert gender to a numeric with 1 representing male and 0 representing female
full_general_candidates$Gender.Num <- ifelse(full_general_candidates$Gender == "Male", 1, ifelse(full_general_candidates$Gender == "Female", 0, -99))

# convert race to dummy variables
full_general_candidates$Race.2 <- ifelse(full_general_candidates$Race.2 == "", NA, full_general_candidates$Race.2)
full_general_candidates$White <- ifelse(!is.na(full_general_candidates$Race.2), grepl("White", full_general_candidates$Race.1) | grepl("White", full_general_candidates$Race.2), grepl("White", full_general_candidates$Race.1))
full_general_candidates$White.Num <- ifelse(full_general_candidates$White, 1, 0)
full_general_candidates$Black <- ifelse(!is.na(full_general_candidates$Race.2), grepl("Black", full_general_candidates$Race.1) | grepl("Black", full_general_candidates$Race.2), grepl("Black", full_general_candidates$Race.1))
full_general_candidates$Black.Num <- ifelse(full_general_candidates$Black, 1, 0)
full_general_candidates$Asian <- ifelse(!is.na(full_general_candidates$Race.2), grepl("Asian", full_general_candidates$Race.1) | grepl("Asian", full_general_candidates$Race.2), grepl("Asian", full_general_candidates$Race.1))
full_general_candidates$Asian.Num <- ifelse(full_general_candidates$Asian, 1, 0)
full_general_candidates$Latino <- ifelse(!is.na(full_general_candidates$Race.2), grepl("Latino", full_general_candidates$Race.1) | grepl("Latino", full_general_candidates$Race.2), grepl("Latino", full_general_candidates$Race.1))
full_general_candidates$Latino.Num <- ifelse(full_general_candidates$Latino, 1, 0)
full_general_candidates$Middle_Eastern <- ifelse(!is.na(full_general_candidates$Race.2), grepl("Middle Eastern", full_general_candidates$Race.1) | grepl("Middle Eastern", full_general_candidates$Race.2), grepl("Middle Eastern", full_general_candidates$Race.1))
full_general_candidates$Middle_Eastern.Num <- ifelse(full_general_candidates$Middle_Eastern, 1, 0)
full_general_candidates$Native_American <- ifelse(!is.na(full_general_candidates$Race.2), grepl("Native", full_general_candidates$Race.1) | grepl("Native", full_general_candidates$Race.2), grepl("Native", full_general_candidates$Race.1))
full_general_candidates$Native_American.Num <- ifelse(full_general_candidates$Native_American, 1, 0)

# convert incumbent to a numeric dummy variable (incumbent as 1, else 0)
full_general_candidates$Incumbent.Num <- ifelse(str_detect(full_general_candidates$Incumbent, "Yes"), 1, 0)

# convert 2020 election stance to a numeric dummy variable (election denier marked as 1, else 0)
full_general_candidates$Election_Denier.Num <- ifelse(full_general_candidates$X2020.Election.Stance == "Fully denied", 1, 0)
full_general_candidates$Election_Denier.Num <- ifelse(is.na(full_general_candidates$X2020.Election.Stance), 0, full_general_candidates$Election_Denier.Num)

# convert Party to a numeric dummy variable (DEM as 1, REP as 0)
full_general_candidates$Party.Num <- ifelse(full_general_candidates$Party == "DEM", 1, 0)

# convert at-large and senate district values
full_general_candidates$District <- ifelse(full_general_candidates$District == "N/A" | full_general_candidates$District == "At-Large", 0, full_general_candidates$District)

# remove duplicate candidates
full_general_candidates$Office[full_general_candidates$Office == "Senator (unexpired term)"] <- "Senator"
full_general_candidates <- full_general_candidates %>%
                            filter(duplicated(Candidate) == FALSE)

# remove parts of name that interferes with grabbing last name
full_general_candidates$Candidate_processed <- paste(full_general_candidates$Candidate," ")
full_general_candidates$Candidate_processed <- gsub(" Sr. ", "", full_general_candidates$Candidate_processed)
full_general_candidates$Candidate_processed <- gsub(" Jr. ", "", full_general_candidates$Candidate_processed)
full_general_candidates$Candidate_processed <- gsub(" III ", "", full_general_candidates$Candidate_processed)
full_general_candidates$Candidate_processed <- gsub(" II ", "", full_general_candidates$Candidate_processed)
full_general_candidates$Candidate_processed <- trimws(full_general_candidates$Candidate_processed)

# extract last name and store in new column
full_general_candidates$Last_name <- word(full_general_candidates$Candidate_processed, - 1) 
full_general_candidates$Last_name <- toupper(full_general_candidates$Last_name)
full_general_candidates$Last_name <- gsub(" ", "", full_general_candidates$Last_name)
full_general_candidates$Last_name <- gsub("Ñ", "N", full_general_candidates$Last_name)
full_general_candidates$Last_name <- gsub("Á", "A", full_general_candidates$Last_name)
full_general_candidates$Last_name <- gsub("'", "", full_general_candidates$Last_name)
full_general_candidates$Last_name <- ifelse(grepl("-", full_general_candidates$Last_name) > 0, word(full_general_candidates$Last_name, sep = "-", -1), full_general_candidates$Last_name)

# convert full state names to abbreviated names to match FEC format
states_dict <- c(AL = "Alabama",
                AK = "Alaska",
                AZ = "Arizona",
                AR = "Arkansas",
                CA = "California",
                CO = "Colorado",
                CT = "Connecticut",
                DE = "Delaware",
                FL = "Florida",
                GA = "Georgia",
                HI = "Hawaii",
                ID = "Idaho",
                IL = "Illinois",
                IN = "Indiana",
                IA = "Iowa",
                KS = "Kansas",
                KY = "Kentucky",
                LA = "Louisiana",
                ME = "Maine",
                MD = "Maryland",
                MA = "Massachusetts",
                MI = "Michigan",
                MN = "Minnesota",
                MS = "Mississippi",
                MO = "Missouri",
                MT = "Montana",
                NE = "Nebraska",
                NV = "Nevada",
                NH = "New Hampshire",
                NJ = "New Jersey",
                NM = "New Mexico",
                NY = "New York",
                NC = "North Carolina",
                ND = "North Dakota",
                OH = "Ohio",
                OK = "Oklahoma",
                OR = "Oregon",
                PA = "Pennsylvania",
                RI = "Rhode Island",
                SC = "South Carolina",
                SD = "South Dakota",
                TN = "Tennessee",
                TX = "Texas",
                UT = "Utah",
                VT = "Vermont",
                VA = "Virginia",
                WA = "Washington",
                WV = "West Virginia",
                WI = "Wisconsin",
                WY = "Wyoming")

full_general_candidates$State_Abbr <- state.abb[match(full_general_candidates$State,state.name)]

# select relevant columns for final candidate data set
final_general_candidates <- full_general_candidates %>%
                              select(Candidate, Last_name, Party.Num, State, State_Abbr, Office, District, Gender.Num, White.Num, Black.Num, Asian.Num, Latino.Num, Middle_Eastern.Num, Native_American.Num, Incumbent.Num, Election_Denier.Num)

# head(final_general_candidates)
write.csv(final_general_candidates, "output data/final_general_candidates.csv")

Individual FEC Donations

# given how large of a file, the itcont.txt file used in the code below can be downloaded on the FEC website linked above in the Data section and added to the 'input data/FEC/Individual' folder in this repository.

# individual donations header
ind_header <- t((fread("input data/FEC/Individual/indiv_header_file.csv", header=FALSE)))

# individual donations 2022
ind_22 <- read.table("input data/FEC/Individual/indiv22/itcont.txt", header=FALSE, sep = '|', fill = TRUE, quote = "", col.names = ind_header[,1]) %>%
            filter(str_sub(toString(TRANSACTION_DT), -4, -1) == "2022") %>%
            select(TRAN_ID, TRANSACTION_DT, TRANSACTION_AMT, CMTE_ID, STATE)
# head(ind_22)

FEC Candidate Information

# candidate header
cn_header <- t((fread("input data/FEC/Candidates/cn_header_file.csv", header=FALSE)))

# candidates 2022
cn_22 <- read.table("input data/FEC/Candidates/cn22.txt", header=FALSE, sep = '|', fill = TRUE, quote = "", col.names = cn_header[,1]) %>%
         filter(CAND_ELECTION_YR == 2022 & (CAND_OFFICE == "H" | CAND_OFFICE == "S")) %>%
         select(CAND_ID, CAND_NAME, CAND_PTY_AFFILIATION, CAND_ELECTION_YR, CAND_OFFICE, CAND_OFFICE_ST, CAND_OFFICE_DISTRICT, CAND_PCC)

# clean party affiliation
cn_22$CAND_PTY_AFFILIATION <- ifelse(cn_22$CAND_PTY_AFFILIATION == "DFL", "DEM", cn_22$CAND_PTY_AFFILIATION)
cn_22$CAND_PTY_AFFILIATION <- ifelse(cn_22$CAND_ID == "H4MT01041", "REP", cn_22$CAND_PTY_AFFILIATION)

# found that candidate district information for Aja Smith was incorrect in FEC. District ran was CA-39, not CA-41
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H8CA41170", 39, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information for Luis Pozzolo was incorrect in FEC. District ran was AZ-7, not AZ-3
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H2AZ03152", 7, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information for David Schweikert was incorrect in FEC. District ran was AZ-1, not AZ-6
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H4AZ06045", 1, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information for Paul Jones was incorrect in FEC. District ran was CA-44, not CA-38
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H0CA38140", 44, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information for Lisa McClain was incorrect in FEC. District ran was MI-9, not MI-10
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H0MI10287", 9, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information for Tim Walberg was incorrect in FEC. District ran was MI-5, not MI-7
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H4MI07103", 5, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information for Ben Clark was incorrect in FEC. District ran was NC-9, not NC-4
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H2NC04150", 9, cn_22$CAND_OFFICE_DISTRICT)

# found that candidate district information and name for Nicholas J. LaLota was incorrect in FEC. District ran was NY-1, not NY-2
cn_22$CAND_OFFICE_DISTRICT <- ifelse(cn_22$CAND_ID == "H0NY02200", 1, cn_22$CAND_OFFICE_DISTRICT)
cn_22$CAND_NAME <- ifelse(cn_22$CAND_ID == "H0NY02200", "LALOTA, NICK", cn_22$CAND_NAME)

# change Antonio Daza's candidate name to DAZA, ANTONIO MIGUEL instead of DAZA-FERNANDEZ, ANTONIO MIGUEL
cn_22$CAND_NAME <- ifelse(cn_22$CAND_ID == "H2GA11230", "DAZA, ANTONIO MIGUEL", cn_22$CAND_NAME)

# change Ashley Hinson's candidate name to HINSON, ASHLEY instead of ARENHOLZ, ASHLEY HINSON
cn_22$CAND_NAME <- ifelse(cn_22$CAND_ID == "H0IA01174", "HINSON, ASHLEY", cn_22$CAND_NAME)

# change Jackie Walorski's candidate name to WALORSKI, JACKIE instead of WALORSKI SWIHART, JACKIE
cn_22$CAND_NAME <- ifelse(cn_22$CAND_ID == "H0IN02190", "WALORSKI, JACKIE", cn_22$CAND_NAME)

# head(cn_22)
write.csv(cn_22, "output data/FEC Candidates/cn_22.csv")

FEC Candidate-Committee Linkage

# candidate-committee linkage header
ccl_header <- t((fread("input data/FEC/Candidate-Committee Linkage/ccl_header_file.csv", header=FALSE)))

# candidate-committee linkage 2022
ccl_22 <- read.table("input data/FEC/Candidate-Committee Linkage/ccl22.txt", header=FALSE, sep = '|', fill = TRUE, quote = "", col.names = ccl_header[,1]) %>%
          filter(CAND_ELECTION_YR == 2022) %>%
          select(CAND_ID, CAND_ELECTION_YR, CMTE_ID, LINKAGE_ID)
# head(ccl_22)
write.csv(ccl_22, "output data/FEC Candidate-Committee/ccl_22.csv")

Join FEC Data

# 2022 fec data
fec_22 <- ind_22 %>% 
              inner_join(ccl_22, by = c("CMTE_ID")) %>%
              inner_join(cn_22, by = c("CAND_ID"))
# head(fec_22)
write.csv(fec_22, "output data/FEC Joined/fec_22.csv")

Candidate Fundraising Totals

# get fundraising totals for candidates by candidate ID for transactions after the Dobbs decision
fec_22_totaled <- fec_22 %>%
                  filter(TRANSACTION_DT >= 6242022 & TRANSACTION_DT <= 11082022) %>%
                  group_by(CAND_ID, CAND_NAME, CAND_PTY_AFFILIATION, CAND_OFFICE, CAND_OFFICE_ST, CAND_OFFICE_DISTRICT) %>%
                  dplyr::summarize(Fundraising_Total = sum(TRANSACTION_AMT, na.rm=TRUE))
## `summarise()` has grouped output by 'CAND_ID', 'CAND_NAME',
## 'CAND_PTY_AFFILIATION', 'CAND_OFFICE', 'CAND_OFFICE_ST'. You can override using
## the `.groups` argument.
# process data to be joined with 538 candidate data
fec_22_totaled$CAND_OFFICE <- ifelse(fec_22_totaled$CAND_OFFICE == "H", "Representative", "Senator")
fec_22_totaled$CAND_PTY_AFFILIATION <- ifelse(fec_22_totaled$CAND_PTY_AFFILIATION == "DEM", 1, 0)

# extract and clean candidate last name for joining
fec_22_totaled$CAND_LAST <- word(fec_22_totaled$CAND_NAME, sep = ",", 1)
fec_22_totaled$CAND_LAST <- gsub(" Sr.", "", fec_22_totaled$CAND_LAST)
fec_22_totaled$CAND_LAST <- gsub(" Jr.", "", fec_22_totaled$CAND_LAST)
fec_22_totaled$CAND_LAST <- gsub(" III", "", fec_22_totaled$CAND_LAST)
fec_22_totaled$CAND_LAST <- gsub(" II", "", fec_22_totaled$CAND_LAST)
fec_22_totaled$CAND_LAST <- gsub("'", "", fec_22_totaled$CAND_LAST)
fec_22_totaled$CAND_LAST <- ifelse(grepl(" ", fec_22_totaled$CAND_LAST) > 0, word(fec_22_totaled$CAND_LAST,-1), fec_22_totaled$CAND_LAST)
fec_22_totaled$CAND_LAST <- ifelse(grepl("-", fec_22_totaled$CAND_LAST) > 0, word(fec_22_totaled$CAND_LAST, sep = "-", -1), fec_22_totaled$CAND_LAST)

# change data type for district to string
fec_22_totaled$CAND_OFFICE_DISTRICT <- as.character(fec_22_totaled$CAND_OFFICE_DISTRICT)

# head(fec_22_totaled)
write.csv(fec_22_totaled, "output data/fec_22_totaled.csv")   


# join with 538 candidate data
candidate_fundraising <- final_general_candidates %>%
                          left_join(fec_22_totaled, by = c("Last_name" = "CAND_LAST", "District" = "CAND_OFFICE_DISTRICT", "Office" = "CAND_OFFICE", "State_Abbr" = "CAND_OFFICE_ST")) %>%
                          select(Candidate, Party.Num, State, State_Abbr, Office, District, Gender.Num, White.Num, Black.Num, Asian.Num, Latino.Num, Middle_Eastern.Num, Native_American.Num, Incumbent.Num, Election_Denier.Num, Fundraising_Total)

candidate_fundraising$index <- row.names(candidate_fundraising)
candidate_fundraising$Fundraising_Total <- ifelse(is.na(candidate_fundraising$Fundraising_Total), 0, candidate_fundraising$Fundraising_Total)

# remove duplicate matches
candidate_fundraising <- candidate_fundraising %>%
                          filter(index != 279 & index != 385 & index != 540 & index != 280 & index != 48)

# head(candidate_fundraising)
write.csv(candidate_fundraising, "output data/candidate_fundraising.csv") 

Filter out districts

# filter out districts with no Democratic or Republican opponent. This accounts for 27 districts.
# Districts included: AL-1, AL-6, AZ-8, AZ-9, CA-10, FL-5, FL-6, FL-18, IL-7, IL-16, MA-4, NY-9, NY-13, PA-3, PA-13, PA-14, SC-3, SC-4, SD-At-Large, TX-6, TX-11, TX-19, TX-25, TX-26, TX-31, UT Senate, WI-6, WI-8
# General elections for LA House districts were cancelled so were not included in analysis

# filter out districts that were missing a candidate in the 538 data. This accounts for 2 districts
# Districts included: MI-4, PA-15 (Democrat write-in candidates)
removed_districts <- c("AL-1", "AL-6", "AZ-8", "AZ-9", "CA-10", "FL-5", "FL-6", "FL-18", "IL-7", "IL-16", "MA-4", "NY-9", "NY-13", "PA-3", "PA-13", "PA-14", "SC-3", "SC-4", "SD-0", "TX-6", "TX-11", "TX-19", "TX-25", "TX-26", "TX-31", "WI-6", "WI-8", "MI-4", "PA-15", "UT-0")

candidate_fundraising_filtered <- candidate_fundraising %>%
                                    mutate(full_district = paste(State_Abbr, "-", as.character(District), sep='')) %>%
                                    filter(! full_district %in% removed_districts)

# remove Nicholas Begich running in AK-0 since he didn't make the final round of voting
# remove Buzz Kelley and Patricia Chesbro running in AK Senate since they didn't make it to the final round of voting
candidate_fundraising_filtered <- candidate_fundraising_filtered %>%
                                    filter(index != 836 & index != 835 & index != 380)

# indicate special election for OK Senate
candidate_fundraising_filtered$Special <- ifelse(candidate_fundraising_filtered$index == 281 | candidate_fundraising_filtered$index == 728, 1, 0)

# remove districts with either two Republicans or two Democrats running against one another
# Districts included: AK Senate, CA-15, CA-16, CA-29, CA-30, CA-34, CA-37
same_party_districts <- c("CA-15", "CA-16", "CA-29", "CA-30", "CA-34", "CA-37")
candidate_fundraising_filtered <- candidate_fundraising_filtered %>%
                                   filter(! full_district %in% same_party_districts)
candidate_fundraising_filtered <- candidate_fundraising_filtered %>%
                                   filter(!(full_district == "AK-0" & Office == "Senator"))

# head(candidate_fundraising_filtered)
write.csv(candidate_fundraising_filtered, "output data/candidate_fundraising_filtered.csv") 

District Level Data

districts <- data.frame(unique(candidate_fundraising_filtered[c("State","State_Abbr","Office","District","Special")]))

districts$Dem_Name <- ""
districts$Rep_Name <- ""
  
districts$Dem_Gender <- -1
districts$Rep_Gender <- -1
  
districts$Dem_Incumbent <- -1
districts$Rep_Incumbent <- -1
  
districts$Rep_Election_Denier <- 0

districts$Dem_Fundraised <- -1
districts$Rep_Fundraised <- -1
              
for (i in 1:nrow(districts)) {
  for (j in 1:nrow(candidate_fundraising_filtered)) {
    # match district with candidate info
    if (districts[i, "State_Abbr"] == candidate_fundraising_filtered[j, "State_Abbr"] &
          districts[i, "Office"] == candidate_fundraising_filtered[j, "Office"] &
          districts[i, "District"] == candidate_fundraising_filtered[j, "District"] &
          districts[i, "Special"] == candidate_fundraising_filtered[j, "Special"]) {
        # pull relevant fields
        party <- candidate_fundraising_filtered[j,"Party.Num"]
        name <- candidate_fundraising_filtered[j,"Candidate"]
        gender <- candidate_fundraising_filtered[j,"Gender.Num"]
        incumbent <- candidate_fundraising_filtered[j,"Incumbent.Num"]
        denier <- candidate_fundraising_filtered[j,"Election_Denier.Num"]
        fundraised <- candidate_fundraising_filtered[j,"Fundraising_Total"]
        
        # add values to district
        if (party == 1) {
          districts[i, "Dem_Name"] <- name
          districts[i, "Dem_Gender"] <- gender
          districts[i, "Dem_Incumbent"] <- incumbent
          districts[i, "Rep_Election_Denier"] <- 0
          districts[i, "Dem_Fundraised"] <- fundraised
        } else {
          districts[i, "Rep_Name"] <- name
          districts[i, "Rep_Gender"] <- gender
          districts[i, "Rep_Incumbent"] <- incumbent
          districts[i, "Rep_Election_Denier"] <- denier
          districts[i, "Rep_Fundraised"] <- fundraised
        }
    } 
  }
}

# create variables for models
districts$Open.Num <- ifelse(districts$Dem_Incumbent == 0 & districts$Rep_Incumbent == 0, 1, 0)
districts$Dem_Man_Rep_Man <- ifelse(districts$Dem_Gender == 1 & districts$Rep_Gender == 1, 1, 0)
districts$Dem_Woman_Rep_Man <- ifelse(districts$Dem_Gender == 0 & districts$Rep_Gender == 1, 1, 0)
districts$Dem_Man_Rep_Woman <- ifelse(districts$Dem_Gender == 1 & districts$Rep_Gender == 0, 1, 0)
districts$Dem_Woman_Rep_Woman <- ifelse(districts$Dem_Gender == 0 & districts$Rep_Gender == 0, 1, 0)

# get fundraising proportion by district 
# Dem Fundraising Amount / (Dem Fundraising Amount + Rep Fundraising Amount)
districts$Fundraising_Prop <- districts$Dem_Fundraised / (districts$Dem_Fundraised + districts$Rep_Fundraised)

# head(districts)
write.csv(districts, "output data/districts.csv") 

DRA District Information

# District data provided by Dave's Redistricting App https://davesredistricting.org/maps#home
# Each state's congressional district data was manually exported and combined into a csv
dra_house <- read.csv("input data/DRA/DRA Data - House Districts .csv") %>%
              select(DRA.Office, ID, State, Dem.2020.Pres, Rep.2020.Pres, Total.2020.Pres)
dra_senate <- read.csv("input data/DRA/DRA Data - Senate Districts.csv") %>%
              select(DRA.Office, ID, State, Dem.2020.Pres, Rep.2020.Pres, Total.2020.Pres)

# DRA processing
# append data sets 
full_dra_districts <- rbind.fill(dra_house, dra_senate)
# head(full_dra_districts)

# create 2020 presidential vote share for each party
full_dra_districts["Dem.2020.Pres.%"] <- as.double(full_dra_districts$Dem.2020.Pres) / as.double(full_dra_districts$Total.2020.Pres)
full_dra_districts["Rep.2020.Pres.%"] <- as.double(full_dra_districts$Rep.2020.Pres) / as.double(full_dra_districts$Total.2020.Pres)
full_dra_districts["Dem_Margin_2020"] <- (full_dra_districts["Dem.2020.Pres.%"] - full_dra_districts["Rep.2020.Pres.%"]) * 100

# select office, id, state, and created columns
final_dra_districts <- full_dra_districts %>%
                                select(DRA.Office, ID, State, Dem_Margin_2020)

names(final_dra_districts)[names(final_dra_districts) == "State"] <- "State.DRA"

# change district labels to match district data set
final_dra_districts$ID <- ifelse(final_dra_districts$ID == "At-Large" | final_dra_districts$ID == "N/A", "0", final_dra_districts$ID)

# join with district data
districts_dra <- districts %>%
                  left_join(final_dra_districts, by = c("Office" = "DRA.Office", "State_Abbr" = "State.DRA", "District" = "ID")) 

# head(districts_dra)
write.csv(districts_dra, "output data/districts_dra.csv")

NYT Election Results

# Election results were collected manually off of the NYT Election tracker: https://www.nytimes.com/interactive/2022/11/08/us/elections/results-senate.html?action=click&pgtype=Article&state=default&module=election-results&context=election_recirc&region=NavBar
# Data was collected and inputed into this spreadsheet: https://docs.google.com/spreadsheets/d/1PFxFBpbsdMT8_b8weiqAeTIx1Q11vgNIWIlYYAjOU0M/edit?usp=sharing

nyt_election_results <- read.csv("input data/NYT/NYT Election Tracker Data - General Election Candidates.csv") %>%
                          select(State, Office, District, Candidate, Party, Winner)

# change district labels to match candidate data set
nyt_election_results$District <- ifelse(nyt_election_results$District == "At-Large" | nyt_election_results$District == "N/A", "0", nyt_election_results$District)
nyt_election_results$Winner <- ifelse(nyt_election_results$Winner, 1, 0)

# join with candidate data set
candidate_fundraising_filtered_nyt <- candidate_fundraising_filtered %>%
                                        left_join(nyt_election_results, by = c("State" = "State", "Office" = "Office", "District" = "District", "Candidate" = "Candidate")) %>%
                                        select(-c(Party))
# head(candidate_fundraising_filtered_nyt)
write.csv(candidate_fundraising_filtered_nyt, "output data/candidate_fundraising_filtered_nyt.csv")

# create District Dem Win
nyt_election_results <- nyt_election_results %>%
                          filter(Party == "DEM") %>%
                          group_by(State, Office, District) %>%
                          dplyr::summarize(District_DEM_Win = sum(Winner))
## `summarise()` has grouped output by 'State', 'Office'. You can override using
## the `.groups` argument.
districts_dra_nyt <- districts_dra %>%
                      left_join(nyt_election_results, by = c("State" = "State", "Office" = "Office", "District" = "District"))
# head(districts_dra_nyt)

Shift from 2020

# house districts
house_shift <- read.csv("input data/Vote Shift/2020 to 2022 Shift - House Shift.csv") %>%
                select(District, X2022.U.S..House.margin, Difference)

# clean up data
house_shift$State.Shift <- word(house_shift$District, sep = "-", 1)
house_shift$District.Shift <- word(house_shift$District, sep = "-", 2)
house_shift$District.Shift <- sub("^0+", "", house_shift$District.Shift)
house_shift$District.Shift <- ifelse(house_shift$District.Shift == "AL", "0", house_shift$District.Shift)
house_shift$Margin_2022 <- ifelse(substr(house_shift$X2022.U.S..House.margin, 1, 1) == "D", as.double(substring(house_shift$X2022.U.S..House.margin, 3)), as.double(substring(house_shift$X2022.U.S..House.margin, 3)) * -1)
house_shift$Shift <- ifelse(substr(house_shift$Difference, 1, 1) == "D", as.double(substring(house_shift$Difference, 3)), as.double(substring(house_shift$Difference, 3)) * -1)
house_shift$Office.Shift <- "Representative"

house_shift <- house_shift %>%
                select(Office.Shift, State.Shift, District.Shift, Margin_2022, Shift)

# join with house district data
districts_dra_nyt_shift <- districts_dra_nyt %>%
                        left_join(house_shift, by = c("Office" = "Office.Shift", "State_Abbr" = "State.Shift", "District" = "District.Shift"))

# senate districts
senate_shift <- read.csv("input data/Vote Shift/2020 to 2022 Shift - Senate Shift.csv") %>%
                  select(stateid, X2022.Dem.This.Margin, X20.22.Dem.Margin.Shift, Special)

# clean up data
names(senate_shift)[names(senate_shift) == "X2022.Dem.This.Margin"] <- "Senate_Margin_2022"
names(senate_shift)[names(senate_shift) == "X20.22.Dem.Margin.Shift"] <- "Senate_Shift"
senate_shift$Senate_Margin_2022 <- as.double(sub("%","", senate_shift$Senate_Margin_2022))
senate_shift$Senate_Shift <- as.double(sub("%","", senate_shift$Senate_Shift))
senate_shift$Office.Shift <- "Senator"

# join with senate district data
districts_dra_nyt_shift <- districts_dra_nyt_shift %>%
                        left_join(senate_shift, by = c("Office" = "Office.Shift", "State_Abbr" = "stateid", "Special" = "Special"))

# combine house and senate columns
districts_dra_nyt_shift$Dem_Margin_2022 <- ifelse(is.na(districts_dra_nyt_shift$Margin_2022), districts_dra_nyt_shift$Senate_Margin_2022, districts_dra_nyt_shift$Margin_2022)
districts_dra_nyt_shift$Dem_Margin_Shift <- ifelse(is.na(districts_dra_nyt_shift$Shift), districts_dra_nyt_shift$Senate_Shift, districts_dra_nyt_shift$Shift)
districts_dra_nyt_shift <- districts_dra_nyt_shift %>%
                        select(-c(Margin_2022, Shift, Senate_Margin_2022, Senate_Shift))


# head(districts_dra_nyt_shift)
write.csv(districts_dra_nyt_shift, "output data/districts_dra_nyt_shift.csv")

State Abortion status

state_abortion_status <- read.csv("input data/Center for Reproductive Rights/State Abortion Status - Data.csv") 

# create numeric dummy variables for illegal, hostile, and other abortion status
state_abortion_status$Illegal.Status <- ifelse(state_abortion_status$Abortion.Status == "Illegal", 1, 0) 
state_abortion_status$Hostile.Status <- ifelse(state_abortion_status$Abortion.Status == "Hostile", 1, 0) 
state_abortion_status$Other.Status <- ifelse(state_abortion_status$Hostile.Status == 0 & state_abortion_status$Illegal.Status == 0, 1, 0) 

state_abortion_status <- state_abortion_status %>%
                          select(-c(Abortion.Status))

# join to district data set
districts_dra_nyt_shift_status <- districts_dra_nyt_shift %>%
                                left_join(state_abortion_status, by = c("State" = "State"))

# head(districts_dra_nyt_shift_status)
write.csv(districts_dra_nyt_shift_status, "output data/districts_dra_nyt_shift_status.csv")

Google Trends data

# get overall salience compared to other issues
Gtrenddata2022 <- data.frame(gtrends(c("Abortion", "Crime", "Inflation", "Gas Prices", "Border"), 
               geo = "US", time = "2022-01-01 2022-12-01",onlyInterest = TRUE))
write.csv(Gtrenddata2022, "output data/Gtrenddata2022.csv")

full_states <- c("AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY")

gtrends_data <- data.frame(full_states)
gtrends_data$Abortion_Salience <- 0

# get the relative number of searches for "abortion" in the last full week before the 2022 midterm general elections
for (i in 1:nrow(gtrends_data)) {
  # print(gtrends_data[i, "used_states"])
  temp <- data.frame(gtrends(c("abortion"), geo = paste0("US-", gtrends_data[i, "full_states"]), time = "2022-01-01 2022-12-01",onlyInterest = TRUE)) %>%
                       filter(as.character(interest_over_time.date) == "2022-10-30") %>%
                       select(interest_over_time.hits)
  gtrends_data$Abortion_Salience[i] <- temp[1, "interest_over_time.hits"]
}

write.csv(gtrends_data, "output data/gtrends_data.csv")

# join with district data
districts_dra_nyt_shift_status_trend <- districts_dra_nyt_shift_status %>%
                                      left_join(gtrends_data, by = c("State_Abbr" = "full_states"))

# head(districts_dra_nyt_shift_status_trend)

Census data

# pull relevant information
# education level: profln: 59 for population 25 and over, 68 for bachelor's degree or higher
census_education <- read.csv("input data/Census/DP02_1yr_500.csv") %>%
                      filter(PROFLN == 59 | PROFLN == 68) %>%
                      select(GEONAME, PROFLN, TITLE, PRF_ESTIMATE, PCT_ESTIMATE)
# process data
census_education$State <- trimws(word(census_education$GEONAME, sep = ",", -1))
census_education$District <- word(census_education$GEONAME, 3)
census_education$District <- ifelse(census_education$District == "(at", "0", census_education$District)
census_education$Total <- ifelse(census_education$PROFLN == 59, as.double(sub(",", "", census_education$PRF_ESTIMATE)), NA)
census_education$Bachelors <- ifelse(census_education$PROFLN == 68, as.double(sub(",", "", census_education$PRF_ESTIMATE)), NA)
names(census_education)[names(census_education) == "PCT_ESTIMATE"] <- "Share_Bachelors"
census_education$Share_Bachelors <- as.double(census_education$Share_Bachelors)
## Warning: NAs introduced by coercion
census_education$Office <- "Representative"

census_education_house <- census_education %>%
                            filter(PROFLN == 68) %>%
                            select(State, District, Office, Share_Bachelors)

census_education_senate <- census_education %>%
                            group_by(State) %>%
                            dplyr::summarize(State_Total = sum(Total, na.rm=TRUE), State_Bachelors = sum(Bachelors, na.rm=TRUE))

census_education_senate$Share_Bachelors <- census_education_senate$State_Bachelors / census_education_senate$State_Total * 100
census_education_senate$District <- "0"
census_education_senate$Office <- "Senator"

census_education_senate <- census_education_senate %>%
                            select(-c(State_Total, State_Bachelors))

# union the two data sets
census_education_total <- rbind(census_education_house, census_education_senate)

# join with district data set
districts_dra_nyt_shift_status_trend_census <- districts_dra_nyt_shift_status_trend %>%
                                            left_join(census_education_total, by = c("State" = "State", "District" = "District", "Office" = "Office"))


# income level: profln: 51 for total households, 57-61 for households above $50k income
census_income <- read.csv("input data/Census/DP03_1yr_500.csv") %>%
                      filter(PROFLN == 51 | (PROFLN >= 58 & PROFLN <= 61)) %>%
                      select(GEONAME, PROFLN, TITLE, PRF_ESTIMATE)

# process data
census_income$State <- trimws(word(census_income$GEONAME, sep = ",", -1))
census_income$District <- word(census_income$GEONAME, 3)
census_income$District <- ifelse(census_income$District == "(at", "0", census_income$District)
census_income$Income_Group <- ifelse(census_income$PROFLN == 51, "Total", "Above 75k")
census_income <- census_income %>%
                  group_by(State, District, Income_Group) %>%
                  dplyr::summarize(Summed = sum(as.double(sub(",", "", PRF_ESTIMATE)), na.rm=TRUE))
## Warning in mask$eval_all_summarise(quo): NAs introduced by coercion
## `summarise()` has grouped output by 'State', 'District'. You can override using
## the `.groups` argument.
census_income$Total <- ifelse(census_income$Income_Group == "Total", census_income$Summed, NA)
census_income$Above <- ifelse(census_income$Income_Group == "Above 75k", census_income$Summed, NA)

census_income <- census_income %>%
                  group_by(State, District) %>%
                  dplyr::summarize(Total = sum(Total, na.rm=TRUE), Above = sum(Above, na.rm=TRUE))
## `summarise()` has grouped output by 'State'. You can override using the
## `.groups` argument.
census_income$Share_Above_75k <- census_income$Above / census_income$Total * 100
census_income$Office <- "Representative"

census_income_house <- census_income %>%
                        select(State, District, Office, Share_Above_75k)

census_income_senate <- census_income %>%
                       group_by(State) %>%
                       dplyr::summarize(State_Total = sum(Total, na.rm=TRUE), State_Above = sum(Above, na.rm=TRUE))

census_income_senate$Share_Above_75k <- census_income_senate$State_Above / census_income_senate$State_Total * 100
census_income_senate$District <- "0"
census_income_senate$Office <- "Senator"

census_income_senate <- census_income_senate %>%
                          select(State, District, Office, Share_Above_75k)

# union the two data sets
census_income_total <- rbind(census_income_house, census_income_senate)

# join with district data set
districts_dra_nyt_shift_status_trend_census <- districts_dra_nyt_shift_status_trend_census %>%
                                            left_join(census_income_total, by = c("State" = "State", "District" = "District", "Office" = "Office"))


# share white: profln: 37 for white alone, 33 for total population
census_race <- read.csv("input data/Census/DP05_1yr_500.csv") %>%
                      filter(PROFLN == 37 | PROFLN == 33) %>%
                      select(GEONAME, PROFLN, TITLE, PRF_ESTIMATE, PCT_ESTIMATE)

# process data
census_race$State <- trimws(word(census_race$GEONAME, sep = ",", -1))
census_race$District <- word(census_race$GEONAME, 3)
census_race$District <- ifelse(census_race$District == "(at", "0", census_race$District)
census_race$Total <- ifelse(census_race$PROFLN == 33, as.double(sub(",", "", census_race$PRF_ESTIMATE)), NA)
## Warning in ifelse(census_race$PROFLN == 33, as.double(sub(",", "",
## census_race$PRF_ESTIMATE)), : NAs introduced by coercion
census_race$White <- ifelse(census_race$PROFLN == 37, as.double(sub(",", "", census_race$PRF_ESTIMATE)), NA)
## Warning in ifelse(census_race$PROFLN == 37, as.double(sub(",", "",
## census_race$PRF_ESTIMATE)), : NAs introduced by coercion
names(census_race)[names(census_race) == "PCT_ESTIMATE"] <- "Share_White"
census_race$Share_White <- as.double(census_race$Share_White)
## Warning: NAs introduced by coercion
census_race$Office <- "Representative"

census_race_house <- census_race %>%
                      filter(PROFLN == 37) %>%
                      select(State, District, Office, Share_White)

census_race_senate <- census_race %>%
                       group_by(State) %>%
                       dplyr::summarize(State_Total = sum(Total, na.rm=TRUE), State_White = sum(White, na.rm=TRUE))

census_race_senate$Share_White <- census_race_senate$State_White / census_race_senate$State_Total * 100
census_race_senate$District <- "0"
census_race_senate$Office <- "Senator"

census_race_senate <- census_race_senate %>%
                       select(-c(State_Total, State_White))

# union the two data sets
census_race_total <- rbind(census_race_house, census_race_senate)

# join with district data set
districts_dra_nyt_shift_status_trend_census <- districts_dra_nyt_shift_status_trend_census %>%
                                            left_join(census_race_total, by = c("State" = "State", "District" = "District", "Office" = "Office"))


# gender share: profln: 3 for female, 1 for total population
census_gender <- read.csv("input data/Census/DP05_1yr_500.csv") %>%
                      filter(PROFLN == 3 | PROFLN == 1) %>%
                      select(GEONAME, PROFLN, TITLE, PRF_ESTIMATE, PCT_ESTIMATE)

# process data
census_gender$State <- trimws(word(census_gender$GEONAME, sep = ",", -1))
census_gender$District <- word(census_gender$GEONAME, 3)
census_gender$District <- ifelse(census_gender$District == "(at", "0", census_gender$District)
census_gender$Total <- ifelse(census_gender$PROFLN == 1, as.double(sub(",", "", census_gender$PRF_ESTIMATE)), NA)
## Warning in ifelse(census_gender$PROFLN == 1, as.double(sub(",", "",
## census_gender$PRF_ESTIMATE)), : NAs introduced by coercion
census_gender$Female <- ifelse(census_gender$PROFLN == 3, as.double(sub(",", "", census_gender$PRF_ESTIMATE)), NA)
## Warning in ifelse(census_gender$PROFLN == 3, as.double(sub(",", "",
## census_gender$PRF_ESTIMATE)), : NAs introduced by coercion
names(census_gender)[names(census_gender) == "PCT_ESTIMATE"] <- "Share_Female"
census_gender$Share_Female <- as.double(census_gender$Share_Female)
## Warning: NAs introduced by coercion
census_gender$Office <- "Representative"

census_gender_house <- census_gender %>%
                            filter(PROFLN == 3) %>%
                            select(State, District, Office, Share_Female)

census_gender_senate <- census_gender %>%
                            group_by(State) %>%
                            dplyr::summarize(State_Total = sum(Total, na.rm=TRUE), State_Female = sum(Female, na.rm=TRUE))

census_gender_senate$Share_Female <- census_gender_senate$State_Female / census_gender_senate$State_Total * 100
census_gender_senate$District <- "0"
census_gender_senate$Office <- "Senator"

census_gender_senate <- census_gender_senate %>%
                            select(-c(State_Total, State_Female))

# union the two data sets
census_gender_total <- rbind(census_gender_house, census_gender_senate)

# join with district data set
districts_dra_nyt_shift_status_trend_census <- districts_dra_nyt_shift_status_trend_census %>%
                                            left_join(census_gender_total, by = c("State" = "State", "District" = "District", "Office" = "Office"))


# age share: profln: 1 for total population, 8-11 for 15 to 44 years old
census_age <- read.csv("input data/Census/DP05_1yr_500.csv") %>%
                      filter(PROFLN == 1 | (PROFLN >= 8 & PROFLN <= 11)) %>%
                      select(GEONAME, PROFLN, TITLE, PRF_ESTIMATE, PCT_ESTIMATE)
# process data
census_age$State <- trimws(word(census_age$GEONAME, sep = ",", -1))
census_age$District <- word(census_age$GEONAME, 3)
census_age$District <- ifelse(census_age$District == "(at", "0", census_age$District)
census_age$Age_Group <- ifelse(census_age$PROFLN == 1, "Total", "Age 15-44")
census_age <- census_age %>%
                  group_by(State, District, Age_Group) %>%
                  dplyr::summarize(Summed = sum(as.double(sub(",", "", PRF_ESTIMATE)), na.rm=TRUE))
## Warning in mask$eval_all_summarise(quo): NAs introduced by coercion
## Warning in mask$eval_all_summarise(quo): NAs introduced by coercion
## `summarise()` has grouped output by 'State', 'District'. You can override using
## the `.groups` argument.
census_age$Total <- ifelse(census_age$Age_Group == "Total", census_age$Summed, NA)
census_age$Age <- ifelse(census_age$Age_Group == "Age 15-44", census_age$Summed, NA)

census_age <- census_age %>%
                  group_by(State, District) %>%
                  dplyr::summarize(Total = sum(Total, na.rm=TRUE), Age = sum(Age, na.rm=TRUE))
## `summarise()` has grouped output by 'State'. You can override using the
## `.groups` argument.
census_age$Total <- ifelse(census_age$State == "Delaware", 1003384, census_age$Total)
census_age$Share_Age_15_to_44 <- census_age$Age / census_age$Total * 100
census_age$Office <- "Representative"

census_age_house <- census_age %>%
                        select(State, District, Office, Share_Age_15_to_44)

census_age_senate <- census_age %>%
                       group_by(State) %>%
                       dplyr::summarize(State_Total = sum(Total, na.rm=TRUE), State_Age = sum(Age, na.rm=TRUE))

census_age_senate$Share_Age_15_to_44 <- census_age_senate$State_Age / census_age_senate$State_Total * 100
census_age_senate$District <- "0"
census_age_senate$Office <- "Senator"

census_age_senate <- census_age_senate %>%
                          select(State, District, Office, Share_Age_15_to_44)

# union the two data sets
census_age_total <- rbind(census_age_house, census_age_senate)

# join with district data set
districts_dra_nyt_shift_status_trend_census <- districts_dra_nyt_shift_status_trend_census %>%
                                            left_join(census_age_total, by = c("State" = "State", "District" = "District", "Office" = "Office"))


# head(districts_dra_nyt_shift_status_trend_census)
write.csv(districts_dra_nyt_shift_status_trend_census, "output data/districts_dra_nyt_shift_trend_census.csv")

State Region

# regions provided by the Census
regions <- read.csv("input data/Census/State Regions - State.csv") 

# create dummy variables
regions$South <- ifelse(regions$Region == "South", 1, 0)
regions$West <- ifelse(regions$Region == "West", 1, 0)
regions$Northeast <- ifelse(regions$Region == "Northeast", 1, 0)
regions$Midwest <- ifelse(regions$Region == "Midwest", 1, 0)

# join with district data set
districts_dra_nyt_shift_status_trend_census_regions <- districts_dra_nyt_shift_status_trend_census %>%
                                            left_join(regions, by = c("State" = "State")) %>%
                                            select(-c(Region))

# head(districts_dra_nyt_shift_status_trend_census_regions)

Urbanization Index

# house level
urban_house <- read.csv("input data/538/Urbanization Index - House.csv")

# process data
urban_house$Office <- "Representative"
urban_house$District <- as.character(as.integer(word(urban_house$tcd, sep = "-", 2)))
urban_house$District <- ifelse(urban_house$state == "ND" | urban_house$state == "SD" | urban_house$state == "DE" | urban_house$state == "WY" | urban_house$state == "VT", 0, urban_house$District)
names(urban_house)[names(urban_house) == "state"] <- "State_Abbr"
urban_house <- urban_house %>%
                select(State_Abbr, Office, District, urbanindex)

# senate level
urban_senate <- read.csv("input data/538/Urbanization Index - Senate.csv")

# process data
names(urban_senate)[names(urban_senate) == "Urbanization.Index"] <- "urbanindex"
urban_senate$Office <- "Senator"
urban_senate$District <- "0"
urban_senate$State_Abbr <- state.abb[match(urban_senate$State,state.name)]
urban_senate <- urban_senate %>%
                select(State_Abbr, Office, District, urbanindex)

# union two data sets
urban_total <- rbind(urban_house, urban_senate)

# join with district data set
districts_dra_nyt_shift_status_trend_census_regions_urban <- districts_dra_nyt_shift_status_trend_census_regions %>%
                                            left_join(urban_total, by = c("State_Abbr" = "State_Abbr", "Office" = "Office", "District" = "District"))

# head(districts_dra_nyt_shift_status_trend_census_regions_urban)

State Religious Adherence

all_denominations <- read.csv("input data/ARDA/Religious Adherence - All Denominations.csv") %>%
                      select(name, value)
names(all_denominations)[names(all_denominations) == "value"] <- "Adherence_per_1000_All"

evangelical <- read.csv("input data/ARDA/Religious Adherence - Evangelical Protestant.csv") %>%
                      select(name, value)
names(evangelical)[names(evangelical) == "value"] <- "Adherence_per_1000_Evan"

# join the two data sets 
adherence_both <- all_denominations %>%
                    left_join(evangelical, by = c("name"))
write.csv(adherence_both, "output data/adherence_both.csv")

# join with district data set
districts_dra_nyt_shift_status_trend_census_regions_urban_religion <- districts_dra_nyt_shift_status_trend_census_regions_urban %>%
                                                                        left_join(adherence_both, by = c("State" = "name"))

# head(districts_dra_nyt_shift_status_trend_census_regions_urban_religion)

Processing final data sets for models

# candidate data set full
final_candidates <- candidate_fundraising_filtered_nyt %>%
                      left_join(districts_dra_nyt_shift_status_trend_census_regions_urban_religion, by = c("State" = "State", "State_Abbr" = "State_Abbr", "Office" = "Office", "District" = "District", "Special" = "Special")) %>%
                      select(State,
                             Office, 
                             District,
                             Abortion_Salience, 
                             Illegal.Status, 
                             Hostile.Status, 
                             Gender.Num,                             
                             Share_Bachelors,
                             Adherence_per_1000_Evan,
                             Election_Denier.Num,
                             Party.Num, 
                             White.Num, 
                             Black.Num, 
                             Latino.Num, 
                             Incumbent.Num, 
                             Open.Num, 
                             Dem_Margin_2020, 
                             Share_Above_75k, 
                             Share_Age_15_to_44,
                             Share_Female,
                             Share_White, 
                             urbanindex, 
                             South, 
                             West,
                             Midwest,
                             Fundraising_Prop,
                             Winner)

head(final_candidates)
##   State         Office District Abortion_Salience Illegal.Status Hostile.Status
## 1 Texas Representative        1                11              1              0
## 2 Texas Representative        2                11              1              0
## 3 Texas Representative        3                11              1              0
## 4 Texas Representative        4                11              1              0
## 5 Texas Representative        5                11              1              0
## 6 Texas Representative        7                11              1              0
##   Gender.Num Share_Bachelors Adherence_per_1000_Evan Election_Denier.Num
## 1          1            22.1                   235.4                   0
## 2          0            37.7                   235.4                   0
## 3          1            48.0                   235.4                   0
## 4          0            45.8                   235.4                   0
## 5          0            23.9                   235.4                   0
## 6          0            50.2                   235.4                   0
##   Party.Num White.Num Black.Num Latino.Num Incumbent.Num Open.Num
## 1         1         0         1          0             0        1
## 2         1         1         0          0             0        0
## 3         1         0         0          0             0        1
## 4         1         0         1          0             0        0
## 5         1         0         1          0             0        0
## 6         1         1         0          0             1        0
##   Dem_Margin_2020 Share_Above_75k Share_Age_15_to_44 Share_Female Share_White
## 1       -45.87259        35.44609           38.51167         50.5        66.6
## 2       -22.76599        57.17593           41.07412         50.9        54.2
## 3       -14.37608        62.71501           39.47224         50.5        60.2
## 4       -25.90530        54.34124           40.49916         50.7        64.1
## 5       -22.42478        43.41911           39.48683         51.4        51.4
## 6        29.72940        46.04369           47.60404         51.1        31.1
##   urbanindex South West Midwest Fundraising_Prop Winner
## 1    9.61616     1    0       0       0.26942006      0
## 2   11.66319     1    0       0       0.03808307      0
## 3   11.57905     1    0       0       0.20247471      0
## 4   10.84754     1    0       0       0.11091497      0
## 5   10.95429     1    0       0       0.01358806      0
## 6   12.90726     1    0       0       0.93232706      1
write.csv(final_candidates, "output data/final_candidates.csv")

# house candidates data
candidate_house <- final_candidates %>%
                    filter(Office == "Representative") %>%
                    select(-c(Office, District, State))

# senate candidates data
candidate_senate <- final_candidates %>%
                    filter(Office == "Senator") %>%
                    select(-c(Office, District, State))

# competitive house candidates data
competitive_candidate_house <- final_candidates %>%
                                filter(Office == "Representative" & abs(Dem_Margin_2020) <= 10) %>%
                                select(-c(Office, District, State))

# district data set full
final_districts <- districts_dra_nyt_shift_status_trend_census_regions_urban_religion %>%
                    select(State,
                           Office,
                           District,
                           Special,
                           Abortion_Salience,
                           Illegal.Status, 
                           Hostile.Status, 
                           Dem_Woman_Rep_Man, 
                           Dem_Man_Rep_Woman, 
                           Dem_Woman_Rep_Woman,
                           Share_Bachelors,
                           Adherence_per_1000_Evan,                           
                           Rep_Election_Denier, 
                           Dem_Incumbent, 
                           Rep_Incumbent, 
                           Dem_Margin_2020, 
                           Share_Above_75k, 
                           Share_White,
                           Share_Age_15_to_44,
                           Share_Female,
                           urbanindex, 
                           South, 
                           West, 
                           Midwest, 
                           Fundraising_Prop,
                           Dem_Margin_Shift,
                           District_DEM_Win)

head(final_districts)
##   State         Office District Special Abortion_Salience Illegal.Status
## 1 Texas Representative        1       0                11              1
## 2 Texas Representative        2       0                11              1
## 3 Texas Representative        3       0                11              1
## 4 Texas Representative        4       0                11              1
## 5 Texas Representative        5       0                11              1
## 6 Texas Representative        7       0                11              1
##   Hostile.Status Dem_Woman_Rep_Man Dem_Man_Rep_Woman Dem_Woman_Rep_Woman
## 1              0                 0                 0                   0
## 2              0                 1                 0                   0
## 3              0                 0                 0                   0
## 4              0                 1                 0                   0
## 5              0                 1                 0                   0
## 6              0                 1                 0                   0
##   Share_Bachelors Adherence_per_1000_Evan Rep_Election_Denier Dem_Incumbent
## 1            22.1                   235.4                   0             0
## 2            37.7                   235.4                   0             0
## 3            48.0                   235.4                   1             0
## 4            45.8                   235.4                   1             0
## 5            23.9                   235.4                   1             0
## 6            50.2                   235.4                   0             1
##   Rep_Incumbent Dem_Margin_2020 Share_Above_75k Share_White Share_Age_15_to_44
## 1             0       -45.87259        35.44609        66.6           38.51167
## 2             1       -22.76599        57.17593        54.2           41.07412
## 3             0       -14.37608        62.71501        60.2           39.47224
## 4             1       -25.90530        54.34124        64.1           40.49916
## 5             1       -22.42478        43.41911        51.4           39.48683
## 6             0        29.72940        46.04369        31.1           47.60404
##   Share_Female urbanindex South West Midwest Fundraising_Prop Dem_Margin_Shift
## 1         50.5    9.61616     1    0       0       0.26942006            -10.3
## 2         50.9   11.66319     1    0       0       0.03808307             -9.0
## 3         50.5   11.57905     1    0       0       0.20247471             -9.2
## 4         50.7   10.84754     1    0       0       0.11091497             -9.8
## 5         51.4   10.95429     1    0       0       0.01358806             -7.7
## 6         51.1   12.90726     1    0       0       0.93232706             -2.1
##   District_DEM_Win
## 1                0
## 2                0
## 3                0
## 4                0
## 5                0
## 6                1
write.csv(final_districts, "output data/final_districts.csv")

# house districts data
district_house <- final_districts %>%
                    filter(Office == "Representative") %>%
                    select(-c(Office, District, State, Special))

# senate districts data
district_senate <- final_districts %>%
                    filter(Office == "Senator") %>%
                    select(-c(Office, District, State, Special))

# competitive house districts data
competitive_districts_house <- final_districts %>%
                                filter(Office == "Representative" & abs(Dem_Margin_2020) <= 10) %>%
                                select(-c(Office, District, State, Special))

Fundraising model

candidate_house_fundraising <- glm(Fundraising_Prop ~ . - Winner, data = candidate_house, family="gaussian")
summary(candidate_house_fundraising)
## 
## Call:
## glm(formula = Fundraising_Prop ~ . - Winner, family = "gaussian", 
##     data = candidate_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -0.63410  -0.13162   0.00857   0.13026   0.69643  
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)    
## (Intercept)              7.708e-01  5.384e-01   1.432  0.15265    
## Abortion_Salience        1.028e-02  3.188e-03   3.225  0.00131 ** 
## Illegal.Status          -2.924e-02  2.569e-02  -1.138  0.25537    
## Hostile.Status          -3.949e-02  1.888e-02  -2.091  0.03684 *  
## Gender.Num              -7.473e-03  1.464e-02  -0.511  0.60983    
## Share_Bachelors         -8.266e-04  1.390e-03  -0.595  0.55216    
## Adherence_per_1000_Evan  2.917e-04  1.474e-04   1.979  0.04813 *  
## Election_Denier.Num     -5.378e-02  2.077e-02  -2.590  0.00979 ** 
## Party.Num               -6.685e-03  1.609e-02  -0.416  0.67784    
## White.Num                4.737e-02  2.839e-02   1.668  0.09563 .  
## Black.Num               -3.677e-02  3.164e-02  -1.162  0.24555    
## Latino.Num               1.032e-02  3.304e-02   0.312  0.75478    
## Incumbent.Num            5.772e-03  1.489e-02   0.388  0.69843    
## Open.Num                 2.882e-02  1.879e-02   1.533  0.12557    
## Dem_Margin_2020          1.053e-02  5.024e-04  20.951  < 2e-16 ***
## Share_Above_75k          4.606e-04  1.315e-03   0.350  0.72625    
## Share_Age_15_to_44      -8.608e-04  2.679e-03  -0.321  0.74809    
## Share_Female            -6.664e-05  9.770e-03  -0.007  0.99456    
## Share_White             -1.181e-03  7.621e-04  -1.550  0.12150    
## urbanindex              -2.447e-02  9.954e-03  -2.458  0.01418 *  
## South                   -1.764e-01  3.220e-02  -5.478 5.85e-08 ***
## West                    -6.213e-02  2.537e-02  -2.449  0.01454 *  
## Midwest                 -7.853e-02  2.500e-02  -3.141  0.00175 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.03306338)
## 
##     Null deviance: 107.878  on 785  degrees of freedom
## Residual deviance:  25.227  on 763  degrees of freedom
##   (2 observations deleted due to missingness)
## AIC: -424.5
## 
## Number of Fisher Scoring iterations: 2
candidate_senate_fundraising <- glm(Fundraising_Prop ~ . - Winner, data = candidate_senate, family="gaussian")
summary(candidate_senate_fundraising)
## 
## Call:
## glm(formula = Fundraising_Prop ~ . - Winner, family = "gaussian", 
##     data = candidate_senate)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -0.25470  -0.08776  -0.01271   0.06814   0.33190  
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)    
## (Intercept)              4.9123467  3.4410920   1.428 0.161379    
## Abortion_Salience        0.0403511  0.0100779   4.004 0.000271 ***
## Illegal.Status           0.3777728  0.0978391   3.861 0.000414 ***
## Hostile.Status           0.2076278  0.0767153   2.706 0.010036 *  
## Gender.Num               0.0115064  0.0503462   0.229 0.820416    
## Share_Bachelors          0.0312148  0.0139184   2.243 0.030673 *  
## Adherence_per_1000_Evan -0.0009983  0.0005060  -1.973 0.055632 .  
## Election_Denier.Num      0.1358189  0.0648043   2.096 0.042637 *  
## Party.Num                0.0437034  0.0447306   0.977 0.334573    
## White.Num                0.0341978  0.1034687   0.331 0.742781    
## Black.Num                0.0366673  0.1261842   0.291 0.772908    
## Latino.Num               0.0152442  0.1187832   0.128 0.898542    
## Incumbent.Num            0.0186913  0.0481982   0.388 0.700272    
## Open.Num                 0.1471787  0.0744451   1.977 0.055141 .  
## Dem_Margin_2020          0.0128065  0.0027044   4.735 2.88e-05 ***
## Share_Above_75k         -0.0216190  0.0097682  -2.213 0.032804 *  
## Share_Age_15_to_44      -0.0330758  0.0242757  -1.363 0.180855    
## Share_Female            -0.0878430  0.0645169  -1.362 0.181154    
## Share_White             -0.0046213  0.0027813  -1.662 0.104625    
## urbanindex               0.0894317  0.0470481   1.901 0.064730 .  
## South                    0.1782944  0.1161134   1.536 0.132730    
## West                     0.1015878  0.0974309   1.043 0.303524    
## Midwest                  0.2489830  0.0869841   2.862 0.006730 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.02100723)
## 
##     Null deviance: 6.72894  on 61  degrees of freedom
## Residual deviance: 0.81928  on 39  degrees of freedom
## AIC: -44.292
## 
## Number of Fisher Scoring iterations: 2
competitive_candidate_house_fundraising <- glm(Fundraising_Prop ~ . - Winner, data = competitive_candidate_house, family="gaussian")
summary(competitive_candidate_house_fundraising)
## 
## Call:
## glm(formula = Fundraising_Prop ~ . - Winner, family = "gaussian", 
##     data = competitive_candidate_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -0.31045  -0.12713   0.00371   0.11336   0.38221  
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)    
## (Intercept)              0.3892630  2.0195311   0.193  0.84745    
## Abortion_Salience        0.0220186  0.0081893   2.689  0.00809 ** 
## Illegal.Status           0.0106163  0.0869439   0.122  0.90300    
## Hostile.Status          -0.0414703  0.0418267  -0.991  0.32325    
## Gender.Num              -0.0328413  0.0311922  -1.053  0.29431    
## Share_Bachelors          0.0029117  0.0033659   0.865  0.38856    
## Adherence_per_1000_Evan  0.0004750  0.0005544   0.857  0.39314    
## Election_Denier.Num      0.0056337  0.0451880   0.125  0.90097    
## Party.Num                0.0140944  0.0320878   0.439  0.66120    
## White.Num                0.1195727  0.0633592   1.887  0.06131 .  
## Black.Num               -0.0065050  0.0741638  -0.088  0.93024    
## Latino.Num               0.0444779  0.0670055   0.664  0.50797    
## Incumbent.Num           -0.0205920  0.0351686  -0.586  0.55919    
## Open.Num                 0.0189792  0.0366768   0.517  0.60569    
## Dem_Margin_2020          0.0184408  0.0029347   6.284 4.38e-09 ***
## Share_Above_75k          0.0024235  0.0030830   0.786  0.43321    
## Share_Age_15_to_44       0.0051080  0.0084984   0.601  0.54883    
## Share_Female             0.0026979  0.0363875   0.074  0.94101    
## Share_White             -0.0016904  0.0020639  -0.819  0.41423    
## urbanindex              -0.0580724  0.0223054  -2.604  0.01028 *  
## South                   -0.1797212  0.0916540  -1.961  0.05198 .  
## West                    -0.0212826  0.0616346  -0.345  0.73041    
## Midwest                 -0.0535294  0.0578421  -0.925  0.35641    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.03010349)
## 
##     Null deviance: 8.3762  on 155  degrees of freedom
## Residual deviance: 4.0038  on 133  degrees of freedom
## AIC: -80.66
## 
## Number of Fisher Scoring iterations: 2
a <- candidate_house_fundraising
b <- candidate_senate_fundraising
c <- competitive_candidate_house_fundraising

stargazer(a, b, c,
          title="Table 1. Candidate Fundraising Model Results", 
          type = "html", 
          out="figures/Table_1.doc",
          align=TRUE)
## 
## <table style="text-align:center"><caption><strong>Table 1. Candidate Fundraising Model Results</strong></caption>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"></td><td colspan="3"><em>Dependent variable:</em></td></tr>
## <tr><td></td><td colspan="3" style="border-bottom: 1px solid black"></td></tr>
## <tr><td style="text-align:left"></td><td colspan="3">Fundraising_Prop</td></tr>
## <tr><td style="text-align:left"></td><td>(1)</td><td>(2)</td><td>(3)</td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Abortion_Salience</td><td>0.010<sup>***</sup></td><td>0.040<sup>***</sup></td><td>0.022<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.003)</td><td>(0.010)</td><td>(0.008)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Illegal.Status</td><td>-0.029</td><td>0.378<sup>***</sup></td><td>0.011</td></tr>
## <tr><td style="text-align:left"></td><td>(0.026)</td><td>(0.098)</td><td>(0.087)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Hostile.Status</td><td>-0.039<sup>**</sup></td><td>0.208<sup>**</sup></td><td>-0.041</td></tr>
## <tr><td style="text-align:left"></td><td>(0.019)</td><td>(0.077)</td><td>(0.042)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Gender.Num</td><td>-0.007</td><td>0.012</td><td>-0.033</td></tr>
## <tr><td style="text-align:left"></td><td>(0.015)</td><td>(0.050)</td><td>(0.031)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Bachelors</td><td>-0.001</td><td>0.031<sup>**</sup></td><td>0.003</td></tr>
## <tr><td style="text-align:left"></td><td>(0.001)</td><td>(0.014)</td><td>(0.003)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Adherence_per_1000_Evan</td><td>0.0003<sup>**</sup></td><td>-0.001<sup>*</sup></td><td>0.0005</td></tr>
## <tr><td style="text-align:left"></td><td>(0.0001)</td><td>(0.001)</td><td>(0.001)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Election_Denier.Num</td><td>-0.054<sup>***</sup></td><td>0.136<sup>**</sup></td><td>0.006</td></tr>
## <tr><td style="text-align:left"></td><td>(0.021)</td><td>(0.065)</td><td>(0.045)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Party.Num</td><td>-0.007</td><td>0.044</td><td>0.014</td></tr>
## <tr><td style="text-align:left"></td><td>(0.016)</td><td>(0.045)</td><td>(0.032)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">White.Num</td><td>0.047<sup>*</sup></td><td>0.034</td><td>0.120<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.028)</td><td>(0.103)</td><td>(0.063)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Black.Num</td><td>-0.037</td><td>0.037</td><td>-0.007</td></tr>
## <tr><td style="text-align:left"></td><td>(0.032)</td><td>(0.126)</td><td>(0.074)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Latino.Num</td><td>0.010</td><td>0.015</td><td>0.044</td></tr>
## <tr><td style="text-align:left"></td><td>(0.033)</td><td>(0.119)</td><td>(0.067)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Incumbent.Num</td><td>0.006</td><td>0.019</td><td>-0.021</td></tr>
## <tr><td style="text-align:left"></td><td>(0.015)</td><td>(0.048)</td><td>(0.035)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Open.Num</td><td>0.029</td><td>0.147<sup>*</sup></td><td>0.019</td></tr>
## <tr><td style="text-align:left"></td><td>(0.019)</td><td>(0.074)</td><td>(0.037)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Margin_2020</td><td>0.011<sup>***</sup></td><td>0.013<sup>***</sup></td><td>0.018<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.001)</td><td>(0.003)</td><td>(0.003)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Above_75k</td><td>0.0005</td><td>-0.022<sup>**</sup></td><td>0.002</td></tr>
## <tr><td style="text-align:left"></td><td>(0.001)</td><td>(0.010)</td><td>(0.003)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Age_15_to_44</td><td>-0.001</td><td>-0.033</td><td>0.005</td></tr>
## <tr><td style="text-align:left"></td><td>(0.003)</td><td>(0.024)</td><td>(0.008)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Female</td><td>-0.0001</td><td>-0.088</td><td>0.003</td></tr>
## <tr><td style="text-align:left"></td><td>(0.010)</td><td>(0.065)</td><td>(0.036)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_White</td><td>-0.001</td><td>-0.005</td><td>-0.002</td></tr>
## <tr><td style="text-align:left"></td><td>(0.001)</td><td>(0.003)</td><td>(0.002)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">urbanindex</td><td>-0.024<sup>**</sup></td><td>0.089<sup>*</sup></td><td>-0.058<sup>**</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.010)</td><td>(0.047)</td><td>(0.022)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">South</td><td>-0.176<sup>***</sup></td><td>0.178</td><td>-0.180<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.032)</td><td>(0.116)</td><td>(0.092)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">West</td><td>-0.062<sup>**</sup></td><td>0.102</td><td>-0.021</td></tr>
## <tr><td style="text-align:left"></td><td>(0.025)</td><td>(0.097)</td><td>(0.062)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Midwest</td><td>-0.079<sup>***</sup></td><td>0.249<sup>***</sup></td><td>-0.054</td></tr>
## <tr><td style="text-align:left"></td><td>(0.025)</td><td>(0.087)</td><td>(0.058)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Constant</td><td>0.771</td><td>4.912</td><td>0.389</td></tr>
## <tr><td style="text-align:left"></td><td>(0.538)</td><td>(3.441)</td><td>(2.020)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Observations</td><td>786</td><td>62</td><td>156</td></tr>
## <tr><td style="text-align:left">Log Likelihood</td><td>235.252</td><td>45.146</td><td>63.330</td></tr>
## <tr><td style="text-align:left">Akaike Inf. Crit.</td><td>-424.504</td><td>-44.292</td><td>-80.660</td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"><em>Note:</em></td><td colspan="3" style="text-align:right"><sup>*</sup>p<0.1; <sup>**</sup>p<0.05; <sup>***</sup>p<0.01</td></tr>
## </table>
house_r_squared <- with(summary(candidate_house_fundraising), 1 - deviance/null.deviance)
house_adj_r_squared <- adjR2(candidate_house_fundraising)
## [1] 0.7594
senate_r_squared <- with(summary(candidate_senate_fundraising), 1 - deviance/null.deviance)
senate_adj_r_squared <- adjR2(candidate_senate_fundraising)
## [1] 0.8096
house_comp_r_squared <- with(summary(competitive_candidate_house_fundraising), 1 - deviance/null.deviance)
house_compe_adj_r_squared <- adjR2(competitive_candidate_house_fundraising )
## [1] 0.4429
r_squared <- round(c(house_r_squared, senate_r_squared, house_comp_r_squared), 3)
r_squared
## [1] 0.766 0.878 0.522
adj_r_squared <- round(c(house_adj_r_squared, senate_adj_r_squared, house_compe_adj_r_squared), 3)
adj_r_squared
## [1] 0.759 0.810 0.443

Candidate Win model

candidate_house_win <- glm(Winner ~ . , data = candidate_house, family="binomial")
summary(candidate_house_win)
## 
## Call:
## glm(formula = Winner ~ ., family = "binomial", data = candidate_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -3.02956  -0.19068  -0.01626   0.22979   3.01891  
## 
## Coefficients:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)             -1.012e+01  1.363e+01  -0.743  0.45767    
## Abortion_Salience        2.741e-02  7.538e-02   0.364  0.71612    
## Illegal.Status           2.091e-01  6.218e-01   0.336  0.73668    
## Hostile.Status           6.625e-02  4.362e-01   0.152  0.87929    
## Gender.Num               3.604e-01  3.384e-01   1.065  0.28682    
## Share_Bachelors          1.113e-02  3.440e-02   0.323  0.74636    
## Adherence_per_1000_Evan  3.562e-04  3.831e-03   0.093  0.92591    
## Election_Denier.Num      6.002e-01  4.977e-01   1.206  0.22785    
## Party.Num               -3.144e-01  3.535e-01  -0.889  0.37385    
## White.Num                3.209e-01  6.388e-01   0.502  0.61538    
## Black.Num                3.203e-01  7.007e-01   0.457  0.64760    
## Latino.Num               2.052e+00  7.539e-01   2.721  0.00651 ** 
## Incumbent.Num            7.796e+00  5.656e-01  13.784  < 2e-16 ***
## Open.Num                 4.011e+00  4.536e-01   8.843  < 2e-16 ***
## Dem_Margin_2020          4.814e-03  1.369e-02   0.352  0.72503    
## Share_Above_75k          6.901e-03  3.101e-02   0.223  0.82386    
## Share_Age_15_to_44      -1.110e-02  6.411e-02  -0.173  0.86251    
## Share_Female             1.293e-01  2.454e-01   0.527  0.59824    
## Share_White              1.554e-03  1.767e-02   0.088  0.92994    
## urbanindex              -1.627e-01  2.268e-01  -0.717  0.47324    
## South                   -2.250e-01  8.050e-01  -0.280  0.77986    
## West                     8.821e-02  5.946e-01   0.148  0.88206    
## Midwest                  1.738e-01  5.837e-01   0.298  0.76594    
## Fundraising_Prop        -9.708e-02  7.884e-01  -0.123  0.90199    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1089.63  on 785  degrees of freedom
## Residual deviance:  313.99  on 762  degrees of freedom
##   (2 observations deleted due to missingness)
## AIC: 361.99
## 
## Number of Fisher Scoring iterations: 6
candidate_senate_win <- glm(Winner ~ . - Incumbent.Num, data = candidate_senate, family="binomial")
summary(candidate_senate_win)
## 
## Call:
## glm(formula = Winner ~ . - Incumbent.Num, family = "binomial", 
##     data = candidate_senate)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -2.0067  -0.8351  -0.2531   0.8716   1.6818  
## 
## Coefficients:
##                           Estimate Std. Error z value Pr(>|z|)  
## (Intercept)             -5.092e+01  6.453e+01  -0.789   0.4300  
## Abortion_Salience        8.696e-02  2.113e-01   0.412   0.6806  
## Illegal.Status          -1.041e+00  1.820e+00  -0.572   0.5674  
## Hostile.Status           2.373e-01  1.303e+00   0.182   0.8555  
## Gender.Num               1.724e+00  8.569e-01   2.011   0.0443 *
## Share_Bachelors          9.856e-02  2.486e-01   0.396   0.6918  
## Adherence_per_1000_Evan  4.583e-03  8.339e-03   0.550   0.5826  
## Election_Denier.Num     -6.594e-01  1.028e+00  -0.642   0.5210  
## Party.Num                5.883e-01  7.222e-01   0.815   0.4153  
## White.Num                1.011e+00  1.613e+00   0.627   0.5307  
## Black.Num               -2.541e+00  2.094e+00  -1.214   0.2249  
## Latino.Num               2.304e+00  1.889e+00   1.219   0.2227  
## Open.Num                -1.113e+00  1.163e+00  -0.957   0.3388  
## Dem_Margin_2020          2.089e-03  5.264e-02   0.040   0.9683  
## Share_Above_75k         -5.785e-02  1.637e-01  -0.353   0.7237  
## Share_Age_15_to_44      -5.910e-02  4.745e-01  -0.125   0.9009  
## Share_Female             1.046e+00  1.176e+00   0.890   0.3737  
## Share_White             -5.122e-04  4.473e-02  -0.011   0.9909  
## urbanindex              -3.310e-01  8.676e-01  -0.382   0.7028  
## South                    1.071e-01  2.240e+00   0.048   0.9619  
## West                     7.758e-01  1.681e+00   0.462   0.6444  
## Midwest                  4.541e-01  1.609e+00   0.282   0.7777  
## Fundraising_Prop        -6.502e-01  2.523e+00  -0.258   0.7966  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 85.886  on 61  degrees of freedom
## Residual deviance: 68.192  on 39  degrees of freedom
## AIC: 114.19
## 
## Number of Fisher Scoring iterations: 4
competitive_candidate_house_win <- glm(Winner ~ . , data = competitive_candidate_house, family="binomial")
summary(competitive_candidate_house_win)
## 
## Call:
## glm(formula = Winner ~ ., family = "binomial", data = competitive_candidate_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -2.46181  -0.62521   0.00135   0.58853   2.27556  
## 
## Coefficients:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)             -1.800e+01  3.499e+01  -0.514 0.606926    
## Abortion_Salience       -4.282e-02  1.368e-01  -0.313 0.754183    
## Illegal.Status          -1.108e+00  1.471e+00  -0.753 0.451471    
## Hostile.Status           8.661e-02  6.983e-01   0.124 0.901288    
## Gender.Num               9.174e-01  5.494e-01   1.670 0.094965 .  
## Share_Bachelors         -2.868e-03  5.751e-02  -0.050 0.960224    
## Adherence_per_1000_Evan -2.661e-04  9.254e-03  -0.029 0.977058    
## Election_Denier.Num     -8.520e-01  7.941e-01  -1.073 0.283274    
## Party.Num               -1.480e+00  5.442e-01  -2.719 0.006544 ** 
## White.Num               -3.479e-01  1.115e+00  -0.312 0.755015    
## Black.Num               -5.646e-01  1.276e+00  -0.442 0.658229    
## Latino.Num               2.071e+00  1.175e+00   1.763 0.077958 .  
## Incumbent.Num            4.864e+00  7.670e-01   6.342 2.27e-10 ***
## Open.Num                 2.317e+00  6.314e-01   3.669 0.000243 ***
## Dem_Margin_2020         -3.434e-03  5.816e-02  -0.059 0.952918    
## Share_Above_75k         -2.877e-03  5.117e-02  -0.056 0.955157    
## Share_Age_15_to_44       4.176e-02  1.420e-01   0.294 0.768656    
## Share_Female             2.780e-01  6.287e-01   0.442 0.658322    
## Share_White              1.438e-02  3.286e-02   0.438 0.661586    
## urbanindex              -8.095e-03  3.527e-01  -0.023 0.981688    
## South                    1.925e-01  1.554e+00   0.124 0.901429    
## West                     2.845e-01  1.074e+00   0.265 0.791206    
## Midwest                  1.217e-01  9.613e-01   0.127 0.899258    
## Fundraising_Prop         2.921e-01  1.532e+00   0.191 0.848852    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 216.26  on 155  degrees of freedom
## Residual deviance: 127.47  on 132  degrees of freedom
## AIC: 175.47
## 
## Number of Fisher Scoring iterations: 5
logit2prob <- function(logit){
  odds <- exp(logit)
  prob <- odds / (1 + odds)
  return(prob)
}

logit2prob(coef(candidate_senate_win))
##             (Intercept)       Abortion_Salience          Illegal.Status 
##            7.649635e-23            5.217259e-01            2.609862e-01 
##          Hostile.Status              Gender.Num         Share_Bachelors 
##            5.590428e-01            8.486038e-01            5.246204e-01 
## Adherence_per_1000_Evan     Election_Denier.Num               Party.Num 
##            5.011457e-01            3.408637e-01            6.429781e-01 
##               White.Num               Black.Num              Latino.Num 
##            7.332158e-01            7.305217e-02            9.091914e-01 
##                Open.Num         Dem_Margin_2020         Share_Above_75k 
##            2.473620e-01            5.005222e-01            4.855405e-01 
##      Share_Age_15_to_44            Share_Female             Share_White 
##            4.852297e-01            7.399409e-01            4.998720e-01 
##              urbanindex                   South                    West 
##            4.179909e-01            5.267525e-01            6.847674e-01 
##                 Midwest        Fundraising_Prop 
##            6.116211e-01            3.429403e-01
a <- candidate_house_win
b <- candidate_senate_win
c <- competitive_candidate_house_win

stargazer(a, b, c,
          title="Table 2. Candidate Win Model Results", 
          type = "html", 
          out="figures/Table_2.doc",
          align=TRUE)
## 
## <table style="text-align:center"><caption><strong>Table 2. Candidate Win Model Results</strong></caption>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"></td><td colspan="3"><em>Dependent variable:</em></td></tr>
## <tr><td></td><td colspan="3" style="border-bottom: 1px solid black"></td></tr>
## <tr><td style="text-align:left"></td><td colspan="3">Winner</td></tr>
## <tr><td style="text-align:left"></td><td>(1)</td><td>(2)</td><td>(3)</td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Abortion_Salience</td><td>0.027</td><td>0.087</td><td>-0.043</td></tr>
## <tr><td style="text-align:left"></td><td>(0.075)</td><td>(0.211)</td><td>(0.137)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Illegal.Status</td><td>0.209</td><td>-1.041</td><td>-1.108</td></tr>
## <tr><td style="text-align:left"></td><td>(0.622)</td><td>(1.820)</td><td>(1.471)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Hostile.Status</td><td>0.066</td><td>0.237</td><td>0.087</td></tr>
## <tr><td style="text-align:left"></td><td>(0.436)</td><td>(1.303)</td><td>(0.698)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Gender.Num</td><td>0.360</td><td>1.724<sup>**</sup></td><td>0.917<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.338)</td><td>(0.857)</td><td>(0.549)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Bachelors</td><td>0.011</td><td>0.099</td><td>-0.003</td></tr>
## <tr><td style="text-align:left"></td><td>(0.034)</td><td>(0.249)</td><td>(0.058)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Adherence_per_1000_Evan</td><td>0.0004</td><td>0.005</td><td>-0.0003</td></tr>
## <tr><td style="text-align:left"></td><td>(0.004)</td><td>(0.008)</td><td>(0.009)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Election_Denier.Num</td><td>0.600</td><td>-0.659</td><td>-0.852</td></tr>
## <tr><td style="text-align:left"></td><td>(0.498)</td><td>(1.028)</td><td>(0.794)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Party.Num</td><td>-0.314</td><td>0.588</td><td>-1.480<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.354)</td><td>(0.722)</td><td>(0.544)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">White.Num</td><td>0.321</td><td>1.011</td><td>-0.348</td></tr>
## <tr><td style="text-align:left"></td><td>(0.639)</td><td>(1.613)</td><td>(1.115)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Black.Num</td><td>0.320</td><td>-2.541</td><td>-0.565</td></tr>
## <tr><td style="text-align:left"></td><td>(0.701)</td><td>(2.094)</td><td>(1.276)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Latino.Num</td><td>2.052<sup>***</sup></td><td>2.304</td><td>2.071<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.754)</td><td>(1.889)</td><td>(1.175)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Incumbent.Num</td><td>7.796<sup>***</sup></td><td></td><td>4.864<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.566)</td><td></td><td>(0.767)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Open.Num</td><td>4.011<sup>***</sup></td><td>-1.113</td><td>2.317<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.454)</td><td>(1.163)</td><td>(0.631)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Margin_2020</td><td>0.005</td><td>0.002</td><td>-0.003</td></tr>
## <tr><td style="text-align:left"></td><td>(0.014)</td><td>(0.053)</td><td>(0.058)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Above_75k</td><td>0.007</td><td>-0.058</td><td>-0.003</td></tr>
## <tr><td style="text-align:left"></td><td>(0.031)</td><td>(0.164)</td><td>(0.051)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Age_15_to_44</td><td>-0.011</td><td>-0.059</td><td>0.042</td></tr>
## <tr><td style="text-align:left"></td><td>(0.064)</td><td>(0.475)</td><td>(0.142)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Female</td><td>0.129</td><td>1.046</td><td>0.278</td></tr>
## <tr><td style="text-align:left"></td><td>(0.245)</td><td>(1.176)</td><td>(0.629)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_White</td><td>0.002</td><td>-0.001</td><td>0.014</td></tr>
## <tr><td style="text-align:left"></td><td>(0.018)</td><td>(0.045)</td><td>(0.033)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">urbanindex</td><td>-0.163</td><td>-0.331</td><td>-0.008</td></tr>
## <tr><td style="text-align:left"></td><td>(0.227)</td><td>(0.868)</td><td>(0.353)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">South</td><td>-0.225</td><td>0.107</td><td>0.193</td></tr>
## <tr><td style="text-align:left"></td><td>(0.805)</td><td>(2.240)</td><td>(1.554)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">West</td><td>0.088</td><td>0.776</td><td>0.284</td></tr>
## <tr><td style="text-align:left"></td><td>(0.595)</td><td>(1.681)</td><td>(1.074)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Midwest</td><td>0.174</td><td>0.454</td><td>0.122</td></tr>
## <tr><td style="text-align:left"></td><td>(0.584)</td><td>(1.609)</td><td>(0.961)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Fundraising_Prop</td><td>-0.097</td><td>-0.650</td><td>0.292</td></tr>
## <tr><td style="text-align:left"></td><td>(0.788)</td><td>(2.523)</td><td>(1.532)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Constant</td><td>-10.121</td><td>-50.925</td><td>-18.003</td></tr>
## <tr><td style="text-align:left"></td><td>(13.628)</td><td>(64.528)</td><td>(34.994)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Observations</td><td>786</td><td>62</td><td>156</td></tr>
## <tr><td style="text-align:left">Log Likelihood</td><td>-156.994</td><td>-34.096</td><td>-63.735</td></tr>
## <tr><td style="text-align:left">Akaike Inf. Crit.</td><td>361.988</td><td>114.192</td><td>175.470</td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"><em>Note:</em></td><td colspan="3" style="text-align:right"><sup>*</sup>p<0.1; <sup>**</sup>p<0.05; <sup>***</sup>p<0.01</td></tr>
## </table>
house_r_squared <- with(summary(candidate_house_win), 1 - deviance/null.deviance)
house_adj_r_squared <- adjR2(candidate_house_win)
## [1] 0.7031
senate_r_squared <- with(summary(candidate_senate_win), 1 - deviance/null.deviance)
senate_adj_r_squared <- adjR2(candidate_senate_win)
## [1] -0.2419
house_comp_r_squared <- with(summary(competitive_candidate_house_win), 1 - deviance/null.deviance)
house_compe_adj_r_squared <- adjR2(competitive_candidate_house_win)
## [1] 0.3079
r_squared <- round(c(house_r_squared, senate_r_squared, house_comp_r_squared), 3)
r_squared
## [1] 0.712 0.206 0.411
adj_r_squared <- round(c(house_adj_r_squared, senate_adj_r_squared, house_compe_adj_r_squared), 3)
adj_r_squared
## [1]  0.703 -0.242  0.308

District Shift model

district_house_shift <- glm(Dem_Margin_Shift ~ ., data = district_house, family="gaussian")
summary(district_house_shift)
## 
## Call:
## glm(formula = Dem_Margin_Shift ~ ., family = "gaussian", data = district_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -11.3083   -2.3129   -0.1258    2.2451   24.1810  
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             19.15347   17.76635   1.078  0.28170    
## Abortion_Salience       -0.33375    0.10662  -3.130  0.00189 ** 
## Illegal.Status           4.41746    0.85383   5.174 3.77e-07 ***
## Hostile.Status           4.31183    0.63057   6.838 3.33e-11 ***
## Dem_Woman_Rep_Man       -0.54103    0.49450  -1.094  0.27462    
## Dem_Man_Rep_Woman        0.32371    0.73585   0.440  0.66025    
## Dem_Woman_Rep_Woman     -0.08178    0.79719  -0.103  0.91835    
## Share_Bachelors          0.03260    0.04640   0.703  0.48276    
## Adherence_per_1000_Evan -0.01296    0.00491  -2.639  0.00867 ** 
## Rep_Election_Denier      1.30717    0.50693   2.579  0.01031 *  
## Dem_Incumbent            1.06740    0.76976   1.387  0.16638    
## Rep_Incumbent           -1.30620    0.77405  -1.687  0.09235 .  
## Dem_Margin_2020         -0.04419    0.02216  -1.995  0.04682 *  
## Share_Above_75k         -0.07443    0.04398  -1.692  0.09144 .  
## Share_White              0.11214    0.02479   4.523 8.23e-06 ***
## Share_Age_15_to_44      -0.08218    0.08901  -0.923  0.35649    
## Share_Female            -0.48973    0.32081  -1.527  0.12772    
## urbanindex              -0.51994    0.33185  -1.567  0.11802    
## South                    2.75534    1.08661   2.536  0.01163 *  
## West                     1.67229    0.84459   1.980  0.04844 *  
## Midwest                  1.75110    0.83936   2.086  0.03764 *  
## Fundraising_Prop         9.57720    1.32352   7.236 2.68e-12 ***
## District_DEM_Win         4.50261    1.02852   4.378 1.56e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 18.1776)
## 
##     Null deviance: 13516.0  on 392  degrees of freedom
## Residual deviance:  6725.7  on 370  degrees of freedom
##   (1 observation deleted due to missingness)
## AIC: 2279.4
## 
## Number of Fisher Scoring iterations: 2
district_senate_shift <- glm(Dem_Margin_Shift ~ ., data = district_senate, family="gaussian")
summary(district_senate_shift)
## 
## Call:
## glm(formula = Dem_Margin_Shift ~ ., family = "gaussian", data = district_senate)
## 
## Deviance Residuals: 
##    Min      1Q  Median      3Q     Max  
## -4.177  -1.248   0.204   1.901   3.945  
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)  
## (Intercept)             485.147728 230.014340   2.109   0.0680 .
## Abortion_Salience         0.526353   0.588602   0.894   0.3973  
## Illegal.Status           13.345946   5.594487   2.386   0.0442 *
## Hostile.Status            6.755777   3.987420   1.694   0.1287  
## Dem_Woman_Rep_Man        -1.649461   2.908349  -0.567   0.5862  
## Dem_Man_Rep_Woman        -4.020081   3.856900  -1.042   0.3277  
## Dem_Woman_Rep_Woman      -7.362884   6.908707  -1.066   0.3176  
## Share_Bachelors           0.749649   0.672470   1.115   0.2973  
## Adherence_per_1000_Evan   0.013594   0.025886   0.525   0.6137  
## Rep_Election_Denier      -1.954112   3.531101  -0.553   0.5951  
## Dem_Incumbent            -0.424918   7.088472  -0.060   0.9537  
## Rep_Incumbent            -8.091423   5.956094  -1.359   0.2114  
## Dem_Margin_2020          -0.003393   0.189877  -0.018   0.9862  
## Share_Above_75k          -0.183352   0.515028  -0.356   0.7310  
## Share_White              -0.125617   0.165189  -0.760   0.4688  
## Share_Age_15_to_44       -3.055194   1.707213  -1.790   0.1113  
## Share_Female             -7.467760   3.859605  -1.935   0.0891 .
## urbanindex               -1.635559   2.514936  -0.650   0.5337  
## South                     7.322645   7.778260   0.941   0.3740  
## West                      5.723521   6.286324   0.910   0.3892  
## Midwest                  11.180536   8.534203   1.310   0.2265  
## Fundraising_Prop         -3.070798  11.100885  -0.277   0.7891  
## District_DEM_Win         10.640023   7.790518   1.366   0.2092  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 18.78929)
## 
##     Null deviance: 1143.50  on 30  degrees of freedom
## Residual deviance:  150.31  on  8  degrees of freedom
## AIC: 184.92
## 
## Number of Fisher Scoring iterations: 2
competitive_districts_house_shift <- glm(Dem_Margin_Shift ~ ., data = competitive_districts_house, family="gaussian")
summary(competitive_districts_house_shift)
## 
## Call:
## glm(formula = Dem_Margin_Shift ~ ., family = "gaussian", data = competitive_districts_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -10.5796   -2.0587   -0.0487    1.3447    9.4971  
## 
## Coefficients:
##                          Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             -41.48910   61.17167  -0.678 0.500463    
## Abortion_Salience        -0.43112    0.26871  -1.604 0.114356    
## Illegal.Status            8.12014    2.72766   2.977 0.004322 ** 
## Hostile.Status            3.91459    1.35543   2.888 0.005533 ** 
## Dem_Woman_Rep_Man        -0.38734    1.21735  -0.318 0.751552    
## Dem_Man_Rep_Woman         1.30907    1.45768   0.898 0.373071    
## Dem_Woman_Rep_Woman      -0.35299    1.41790  -0.249 0.804324    
## Share_Bachelors           0.10855    0.11029   0.984 0.329315    
## Adherence_per_1000_Evan  -0.02415    0.01845  -1.309 0.196010    
## Rep_Election_Denier       1.54103    1.10622   1.393 0.169207    
## Dem_Incumbent             3.45055    1.36371   2.530 0.014290 *  
## Rep_Incumbent            -1.98977    1.28037  -1.554 0.125908    
## Dem_Margin_2020          -0.32656    0.13312  -2.453 0.017359 *  
## Share_Above_75k          -0.13803    0.09759  -1.414 0.162879    
## Share_White               0.18440    0.06530   2.824 0.006591 ** 
## Share_Age_15_to_44        0.07642    0.27106   0.282 0.779050    
## Share_Female              0.52029    1.10612   0.470 0.639950    
## urbanindex               -0.68500    0.72403  -0.946 0.348240    
## South                     5.48802    3.05482   1.797 0.077906 .  
## West                      6.37090    1.92145   3.316 0.001623 ** 
## Midwest                   3.40902    1.85702   1.836 0.071803 .  
## Fundraising_Prop         10.64218    2.86712   3.712 0.000482 ***
## District_DEM_Win          6.59599    1.61261   4.090 0.000142 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 14.6557)
## 
##     Null deviance: 4417.79  on 77  degrees of freedom
## Residual deviance:  806.06  on 55  degrees of freedom
## AIC: 451.52
## 
## Number of Fisher Scoring iterations: 2
a <- district_house_shift
b <- district_senate_shift
c <- competitive_districts_house_shift

stargazer(a, b, c,
          title="Table 3. District Margin Shift Model Results", 
          type = "html", 
          out="figures/Table_3.doc",
          align=TRUE)
## 
## <table style="text-align:center"><caption><strong>Table 3. District Margin Shift Model Results</strong></caption>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"></td><td colspan="3"><em>Dependent variable:</em></td></tr>
## <tr><td></td><td colspan="3" style="border-bottom: 1px solid black"></td></tr>
## <tr><td style="text-align:left"></td><td colspan="3">Dem_Margin_Shift</td></tr>
## <tr><td style="text-align:left"></td><td>(1)</td><td>(2)</td><td>(3)</td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Abortion_Salience</td><td>-0.334<sup>***</sup></td><td>0.526</td><td>-0.431</td></tr>
## <tr><td style="text-align:left"></td><td>(0.107)</td><td>(0.589)</td><td>(0.269)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Illegal.Status</td><td>4.417<sup>***</sup></td><td>13.346<sup>**</sup></td><td>8.120<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.854)</td><td>(5.594)</td><td>(2.728)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Hostile.Status</td><td>4.312<sup>***</sup></td><td>6.756</td><td>3.915<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.631)</td><td>(3.987)</td><td>(1.355)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Woman_Rep_Man</td><td>-0.541</td><td>-1.649</td><td>-0.387</td></tr>
## <tr><td style="text-align:left"></td><td>(0.494)</td><td>(2.908)</td><td>(1.217)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Man_Rep_Woman</td><td>0.324</td><td>-4.020</td><td>1.309</td></tr>
## <tr><td style="text-align:left"></td><td>(0.736)</td><td>(3.857)</td><td>(1.458)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Woman_Rep_Woman</td><td>-0.082</td><td>-7.363</td><td>-0.353</td></tr>
## <tr><td style="text-align:left"></td><td>(0.797)</td><td>(6.909)</td><td>(1.418)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Bachelors</td><td>0.033</td><td>0.750</td><td>0.109</td></tr>
## <tr><td style="text-align:left"></td><td>(0.046)</td><td>(0.672)</td><td>(0.110)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Adherence_per_1000_Evan</td><td>-0.013<sup>***</sup></td><td>0.014</td><td>-0.024</td></tr>
## <tr><td style="text-align:left"></td><td>(0.005)</td><td>(0.026)</td><td>(0.018)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Rep_Election_Denier</td><td>1.307<sup>**</sup></td><td>-1.954</td><td>1.541</td></tr>
## <tr><td style="text-align:left"></td><td>(0.507)</td><td>(3.531)</td><td>(1.106)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Incumbent</td><td>1.067</td><td>-0.425</td><td>3.451<sup>**</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.770)</td><td>(7.088)</td><td>(1.364)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Rep_Incumbent</td><td>-1.306<sup>*</sup></td><td>-8.091</td><td>-1.990</td></tr>
## <tr><td style="text-align:left"></td><td>(0.774)</td><td>(5.956)</td><td>(1.280)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Margin_2020</td><td>-0.044<sup>**</sup></td><td>-0.003</td><td>-0.327<sup>**</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.022)</td><td>(0.190)</td><td>(0.133)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Above_75k</td><td>-0.074<sup>*</sup></td><td>-0.183</td><td>-0.138</td></tr>
## <tr><td style="text-align:left"></td><td>(0.044)</td><td>(0.515)</td><td>(0.098)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_White</td><td>0.112<sup>***</sup></td><td>-0.126</td><td>0.184<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.025)</td><td>(0.165)</td><td>(0.065)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Age_15_to_44</td><td>-0.082</td><td>-3.055</td><td>0.076</td></tr>
## <tr><td style="text-align:left"></td><td>(0.089)</td><td>(1.707)</td><td>(0.271)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Female</td><td>-0.490</td><td>-7.468<sup>*</sup></td><td>0.520</td></tr>
## <tr><td style="text-align:left"></td><td>(0.321)</td><td>(3.860)</td><td>(1.106)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">urbanindex</td><td>-0.520</td><td>-1.636</td><td>-0.685</td></tr>
## <tr><td style="text-align:left"></td><td>(0.332)</td><td>(2.515)</td><td>(0.724)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">South</td><td>2.755<sup>**</sup></td><td>7.323</td><td>5.488<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(1.087)</td><td>(7.778)</td><td>(3.055)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">West</td><td>1.672<sup>**</sup></td><td>5.724</td><td>6.371<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.845)</td><td>(6.286)</td><td>(1.921)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Midwest</td><td>1.751<sup>**</sup></td><td>11.181</td><td>3.409<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.839)</td><td>(8.534)</td><td>(1.857)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Fundraising_Prop</td><td>9.577<sup>***</sup></td><td>-3.071</td><td>10.642<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(1.324)</td><td>(11.101)</td><td>(2.867)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">District_DEM_Win</td><td>4.503<sup>***</sup></td><td>10.640</td><td>6.596<sup>***</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(1.029)</td><td>(7.791)</td><td>(1.613)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Constant</td><td>19.153</td><td>485.148<sup>*</sup></td><td>-41.489</td></tr>
## <tr><td style="text-align:left"></td><td>(17.766)</td><td>(230.014)</td><td>(61.172)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td><td></td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Observations</td><td>393</td><td>31</td><td>78</td></tr>
## <tr><td style="text-align:left">Log Likelihood</td><td>-1,116.680</td><td>-69.458</td><td>-202.760</td></tr>
## <tr><td style="text-align:left">Akaike Inf. Crit.</td><td>2,279.360</td><td>184.915</td><td>451.520</td></tr>
## <tr><td colspan="4" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"><em>Note:</em></td><td colspan="3" style="text-align:right"><sup>*</sup>p<0.1; <sup>**</sup>p<0.05; <sup>***</sup>p<0.01</td></tr>
## </table>
house_r_squared <- with(summary(district_house_shift), 1 - deviance/null.deviance)
house_adj_r_squared <- adjR2(district_house_shift)
## [1] 0.4728
senate_r_squared <- with(summary(district_senate_shift), 1 - deviance/null.deviance)
senate_adj_r_squared <- adjR2(district_senate_shift)
## [1] 0.5071
house_comp_r_squared <- with(summary(competitive_districts_house_shift), 1 - deviance/null.deviance)
house_compe_adj_r_squared <- adjR2(competitive_districts_house_shift)
## [1] 0.7446
r_squared <- round(c(house_r_squared, senate_r_squared, house_comp_r_squared), 3)
r_squared
## [1] 0.502 0.869 0.818
adj_r_squared <- round(c(house_adj_r_squared, senate_adj_r_squared, house_compe_adj_r_squared), 3)
adj_r_squared
## [1] 0.473 0.507 0.745

District Win model

district_house_win <- glm(District_DEM_Win ~ . - Dem_Margin_Shift - Share_White - Share_Age_15_to_44 - Share_Female - Share_Above_75k , data = district_house, family="binomial")
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(district_house_win)
## 
## Call:
## glm(formula = District_DEM_Win ~ . - Dem_Margin_Shift - Share_White - 
##     Share_Age_15_to_44 - Share_Female - Share_Above_75k, family = "binomial", 
##     data = district_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -2.23209  -0.00001   0.00000   0.00011   1.90205  
## 
## Coefficients:
##                         Estimate Std. Error z value Pr(>|z|)   
## (Intercept)              6.74318    9.04761   0.745  0.45609   
## Abortion_Salience       -0.65091    0.42763  -1.522  0.12797   
## Illegal.Status          -4.16932   27.82084  -0.150  0.88087   
## Hostile.Status           2.08570    1.74350   1.196  0.23159   
## Dem_Woman_Rep_Man        1.25835    1.63754   0.768  0.44223   
## Dem_Man_Rep_Woman        6.97448    3.77285   1.849  0.06452 . 
## Dem_Woman_Rep_Woman     -0.05878    1.58230  -0.037  0.97037   
## Share_Bachelors         -0.10138    0.06812  -1.488  0.13668   
## Adherence_per_1000_Evan  0.03557    0.02159   1.648  0.09939 . 
## Rep_Election_Denier      2.69299    1.59722   1.686  0.09179 . 
## Dem_Incumbent            3.42009    1.29802   2.635  0.00842 **
## Rep_Incumbent           -7.02974    2.96842  -2.368  0.01788 * 
## Dem_Margin_2020          0.62343    0.20946   2.976  0.00292 **
## urbanindex              -0.88623    0.77482  -1.144  0.25271   
## South                   -4.98394    3.06318  -1.627  0.10373   
## West                    -1.90650    1.90887  -0.999  0.31791   
## Midwest                 -1.44982    2.19616  -0.660  0.50915   
## Fundraising_Prop        10.92936    5.44756   2.006  0.04483 * 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 544.750  on 392  degrees of freedom
## Residual deviance:  36.545  on 375  degrees of freedom
##   (1 observation deleted due to missingness)
## AIC: 72.545
## 
## Number of Fisher Scoring iterations: 13
competitive_districts_house_win <- glm(District_DEM_Win ~ . - Dem_Margin_Shift - Share_White - Share_Age_15_to_44 - Share_Female - Share_Above_75k - South - Midwest - West, data = competitive_districts_house, family="binomial")
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(competitive_districts_house_win)
## 
## Call:
## glm(formula = District_DEM_Win ~ . - Dem_Margin_Shift - Share_White - 
##     Share_Age_15_to_44 - Share_Female - Share_Above_75k - South - 
##     Midwest - West, family = "binomial", data = competitive_districts_house)
## 
## Deviance Residuals: 
##      Min        1Q    Median        3Q       Max  
## -1.81897  -0.00072   0.00000   0.00260   1.84993  
## 
## Coefficients:
##                           Estimate Std. Error z value Pr(>|z|)  
## (Intercept)               30.91869   17.73965   1.743   0.0813 .
## Abortion_Salience         -3.05691    1.69406  -1.804   0.0712 .
## Illegal.Status            -2.53702 3215.93978  -0.001   0.9994  
## Hostile.Status             6.61548    3.64572   1.815   0.0696 .
## Dem_Woman_Rep_Man          6.79193    4.47562   1.518   0.1291  
## Dem_Man_Rep_Woman          9.40211    8.44607   1.113   0.2656  
## Dem_Woman_Rep_Woman       -4.50385    3.92825  -1.147   0.2516  
## Share_Bachelors           -0.54902    0.28921  -1.898   0.0577 .
## Adherence_per_1000_Evan   -0.02432    0.02303  -1.056   0.2909  
## Rep_Election_Denier        5.53850    3.05982   1.810   0.0703 .
## Dem_Incumbent              7.08121    4.47236   1.583   0.1133  
## Rep_Incumbent            -11.89676    8.83897  -1.346   0.1783  
## Dem_Margin_2020            1.55300    0.76483   2.031   0.0423 *
## urbanindex                -0.46092    1.02758  -0.449   0.6538  
## Fundraising_Prop          34.66176   20.06711   1.727   0.0841 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 102.945  on 77  degrees of freedom
## Residual deviance:  17.449  on 63  degrees of freedom
## AIC: 47.449
## 
## Number of Fisher Scoring iterations: 17
logit2prob <- function(logit){
  odds <- exp(logit)
  prob <- odds / (1 + odds)
  return(prob)
}

logit2prob(coef(district_house_win))
##             (Intercept)       Abortion_Salience          Illegal.Status 
##            0.9988224911            0.3427834846            0.0152273052 
##          Hostile.Status       Dem_Woman_Rep_Man       Dem_Man_Rep_Woman 
##            0.8895053599            0.7787417653            0.9990654200 
##     Dem_Woman_Rep_Woman         Share_Bachelors Adherence_per_1000_Evan 
##            0.4853095669            0.4746768857            0.5088924055 
##     Rep_Election_Denier           Dem_Incumbent           Rep_Incumbent 
##            0.9366115425            0.9683265524            0.0008843755 
##         Dem_Margin_2020              urbanindex                   South 
##            0.6509987157            0.2918875905            0.0068004901 
##                    West                 Midwest        Fundraising_Prop 
##            0.1293742462            0.1900290573            0.9999820762
a <- district_house_win
c <- competitive_districts_house_win

stargazer(a, c,
          title="Table 4. District Democrat Win Model Results", 
          type = "html", 
          out="figures/Table_4.doc",
          align=TRUE)
## 
## <table style="text-align:center"><caption><strong>Table 4. District Democrat Win Model Results</strong></caption>
## <tr><td colspan="3" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"></td><td colspan="2"><em>Dependent variable:</em></td></tr>
## <tr><td></td><td colspan="2" style="border-bottom: 1px solid black"></td></tr>
## <tr><td style="text-align:left"></td><td colspan="2">District_DEM_Win</td></tr>
## <tr><td style="text-align:left"></td><td>(1)</td><td>(2)</td></tr>
## <tr><td colspan="3" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Abortion_Salience</td><td>-0.651</td><td>-3.057<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.428)</td><td>(1.694)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Illegal.Status</td><td>-4.169</td><td>-2.537</td></tr>
## <tr><td style="text-align:left"></td><td>(27.821)</td><td>(3,215.940)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Hostile.Status</td><td>2.086</td><td>6.615<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(1.743)</td><td>(3.646)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Woman_Rep_Man</td><td>1.258</td><td>6.792</td></tr>
## <tr><td style="text-align:left"></td><td>(1.638)</td><td>(4.476)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Man_Rep_Woman</td><td>6.974<sup>*</sup></td><td>9.402</td></tr>
## <tr><td style="text-align:left"></td><td>(3.773)</td><td>(8.446)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Woman_Rep_Woman</td><td>-0.059</td><td>-4.504</td></tr>
## <tr><td style="text-align:left"></td><td>(1.582)</td><td>(3.928)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Share_Bachelors</td><td>-0.101</td><td>-0.549<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.068)</td><td>(0.289)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Adherence_per_1000_Evan</td><td>0.036<sup>*</sup></td><td>-0.024</td></tr>
## <tr><td style="text-align:left"></td><td>(0.022)</td><td>(0.023)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Rep_Election_Denier</td><td>2.693<sup>*</sup></td><td>5.538<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(1.597)</td><td>(3.060)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Incumbent</td><td>3.420<sup>***</sup></td><td>7.081</td></tr>
## <tr><td style="text-align:left"></td><td>(1.298)</td><td>(4.472)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Rep_Incumbent</td><td>-7.030<sup>**</sup></td><td>-11.897</td></tr>
## <tr><td style="text-align:left"></td><td>(2.968)</td><td>(8.839)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Dem_Margin_2020</td><td>0.623<sup>***</sup></td><td>1.553<sup>**</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(0.209)</td><td>(0.765)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">urbanindex</td><td>-0.886</td><td>-0.461</td></tr>
## <tr><td style="text-align:left"></td><td>(0.775)</td><td>(1.028)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">South</td><td>-4.984</td><td></td></tr>
## <tr><td style="text-align:left"></td><td>(3.063)</td><td></td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">West</td><td>-1.907</td><td></td></tr>
## <tr><td style="text-align:left"></td><td>(1.909)</td><td></td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Midwest</td><td>-1.450</td><td></td></tr>
## <tr><td style="text-align:left"></td><td>(2.196)</td><td></td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Fundraising_Prop</td><td>10.929<sup>**</sup></td><td>34.662<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(5.448)</td><td>(20.067)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td style="text-align:left">Constant</td><td>6.743</td><td>30.919<sup>*</sup></td></tr>
## <tr><td style="text-align:left"></td><td>(9.048)</td><td>(17.740)</td></tr>
## <tr><td style="text-align:left"></td><td></td><td></td></tr>
## <tr><td colspan="3" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left">Observations</td><td>393</td><td>78</td></tr>
## <tr><td style="text-align:left">Log Likelihood</td><td>-18.272</td><td>-8.725</td></tr>
## <tr><td style="text-align:left">Akaike Inf. Crit.</td><td>72.545</td><td>47.449</td></tr>
## <tr><td colspan="3" style="border-bottom: 1px solid black"></td></tr><tr><td style="text-align:left"><em>Note:</em></td><td colspan="2" style="text-align:right"><sup>*</sup>p<0.1; <sup>**</sup>p<0.05; <sup>***</sup>p<0.01</td></tr>
## </table>
house_r_squared <- with(summary(district_house_win), 1 - deviance/null.deviance)
house_adj_r_squared <- adjR2(district_house_win)
## [1] 0.9299
house_comp_r_squared <- with(summary(competitive_districts_house_win), 1 - deviance/null.deviance)
house_compe_adj_r_squared <- adjR2(competitive_districts_house_win)
## [1] 0.7928
r_squared <- round(c(house_r_squared, house_comp_r_squared), 3)
r_squared
## [1] 0.933 0.830
adj_r_squared <- round(c(house_adj_r_squared, house_compe_adj_r_squared), 3)
adj_r_squared
## [1] 0.930 0.793