Skip to content

Instantly share code, notes, and snippets.

@elliottmorris
Created June 17, 2017 23:03
Show Gist options
  • Save elliottmorris/a7dacae5afdac42318b7dc3bffbcc551 to your computer and use it in GitHub Desktop.
Save elliottmorris/a7dacae5afdac42318b7dc3bffbcc551 to your computer and use it in GitHub Desktop.
Predicting #GA06
# Libraries, data, setup ####
rm(list=ls())
library(tidyverse)
library(gridExtra)
library(googlesheets)
source("~/Desktop/theme_elliott.R")
# load in data from Gsheet
my_sheets <- gs_ls()
suppressMessages(sheet <- gs_title("Georgia 06 Polls (and Benchmarks)"))
suppressMessages(worksheet <- gs_read(sheet,ws = "Benchmarks",range="A6:T214"))
results <- as.data.frame(worksheet) %>% rename(PRIMARY.OSSOFF)
#check for an update
LAST_OUT <- read.csv("output.csv",stringsAsFactors = FALSE)
if(!isTRUE(
unique(
as.numeric(as.character(
(results$GE.OSSOFF/results$GE.VOTES*100)[!is.na(results$GE.OSSOFF/results$GE.VOTES)*100])) %in% as.numeric(LAST_OUT$Ossoff.Share.in.Reporting.Precincts)
)
)
){ # if new precinct data, update
cat("
New Precincts Returns!
")
# first, fill in empty benchmark with Clinton percent
results <- results %>%
mutate(Ossoff.Benchmark = ifelse(is.na(Ossoff.Benchmark),Clinton.Percent,Ossoff.Benchmark))
# predict ####
fit <- lm(GE.OSSOFF ~ Ossoff.Benchmark + PRIMARY.DEM,data = results)
suppressWarnings(summary(fit))
results$predicted <- predict(fit,results)
# replace values that already exist
results <- results %>%
mutate(outcome = ifelse(is.na(GE.OSSOFF),predicted,GE.OSSOFF))
##### repeat for total votes, then get % ##
fit_total <- lm(GE.VOTES ~ Ossoff.Percent + PRIMARY.VOTES,data = results)
suppressWarnings(summary(fit_total))
results$predicted_total <- predict(fit_total,results)
# replace values that already exist
results <- results %>%
mutate(outcome_total = ifelse(is.na(GE.VOTES),predicted_total,GE.VOTES))
# look again
# percents
results$GE.Percent.Ossoff <- (results$outcome / results$outcome_total)
# cap percent at 100, 0 --- THIS IS A WEAKNESS IN THE MODEL
results <- results %>%
mutate(GE.Percent.Ossoff = ifelse(GE.Percent.Ossoff >= 1,1,GE.Percent.Ossoff)) %>%
mutate(GE.Percent.Ossoff = ifelse(GE.Percent.Ossoff <= 0,0,GE.Percent.Ossoff))
#plot(results$Ossoff..,results$GE.Percent.Ossoff)
# graphics ####
gg1 <- ggplot(data=results,aes(x=Ossoff.Benchmark/100, y=GE.OSSOFF/GE.VOTES)) +
#geom_point(aes(size=(results$GE.OSSOFF/max(results$GE.OSSOFF,na.rm=TRUE))*2,col=GE.OSSOFF),alpha=.5) +
geom_point(aes(size=GE.VOTES,col=round((GE.OSSOFF/GE.VOTES),2)>=round((Ossoff.Benchmark/100),2),alpha=.5)) +
geom_smooth(col="gray",linetype=2,method="lm",se=FALSE,fullrange = TRUE)+
scale_color_manual(values=c("TRUE"="#3498DB","FALSE"="#F39C12")) +
scale_size("GE.VOTES",range = c(0, 10)) +
geom_abline(intercept = 0,slope=1) +
labs(title = "#GA06 Reported Ossoff Vote Share\nby Precinct",
subtitle="Among precincts that are reporting votes",
y="Ossoff Vote Share in Round 2 (%)",
x="Democrat's Total Vote Share in Round 1 (%)") +
theme_elliott() +
scale_y_continuous(labels=scales::percent_format()) +
scale_x_continuous(labels=scales::percent_format()) +
coord_cartesian(ylim=c(0,1),xlim=c(0,1))
gg2 <- ggplot(data=results,aes(x=Ossoff.Benchmark/100, y=GE.Percent.Ossoff)) +
geom_point(aes(size=outcome,
col=round(GE.Percent.Ossoff,2)>=round((Ossoff.Benchmark/100),2)),alpha=.5) +
geom_smooth(col="gray",linetype=2,method="lm",se=FALSE,fullrange = TRUE)+
scale_color_manual(values=c("TRUE"="#3498DB","FALSE"="#F39C12")) +
scale_size("GE.VOTES",range = c(0, 10)) +
geom_abline(intercept = 0,slope=1) +
labs(title = "#GA06 Projected Ossoff Vote Share\nby Precinct",
subtitle="Among results or projections for all precincts",
x="Democrat's Total Vote Share in Round 1 (%)",
y = "Ossoff Vote Share in Round 2 (%)") +
theme_elliott() +
coord_cartesian(ylim=c(0,1),xlim=c(0,1)) +
scale_x_continuous(labels = scales::percent_format()) +
scale_y_continuous(labels = scales::percent_format())
median_precinct <- results[round(results$GE.Percent.Ossoff,2) == round(median(results$GE.Percent.Ossoff,na.rm=TRUE),2),]$Order
median_precinct <- median_precinct[!is.na(median_precinct)][3]
gg3 <- ggplot(data=results,aes(x=as.numeric(reorder(Order,GE.Percent.Ossoff)), y=GE.Percent.Ossoff)) +
theme_elliott() +
geom_point(aes(col=GE.Percent.Ossoff>.5,
fill=GE.Percent.Ossoff>.5),alpha=.5) +
geom_area(aes(col=GE.Percent.Ossoff>.5,
fill=GE.Percent.Ossoff>.5),alpha=.5) +
geom_hline(yintercept = .5,linetype=2) +
labs(title = "#GA06 Precinct-level Projections",
subtitle="Projected votes in all precincts",
x="Precinct (Each point is a precinct)",
y="Ossoff Vote Share (%)") +
scale_color_manual(values=c("TRUE"="#3498DB","FALSE"="#E74C3C")) +
scale_fill_manual(values=c("TRUE"="#3498DB","FALSE"="#E74C3C")) +
annotate("text",
x=25,
y=.47,label="Handel Wins Precinct↓",col="#E74C3C") +
annotate("text",
x=25,
y=.53,label="Ossoff Wins Precinct↑",col="#3498DB") +
geom_vline(xintercept = 105,linetype=2,col="#888888") +
annotate("text",x=107,y=.8,hjust = 0,label="If blue area\nis to the left\nof this line,\nOssoff is\nwinning",col="#888888") +
theme(panel.grid.major.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank()) +
scale_y_continuous(labels = scales::percent_format())+
coord_cartesian(ylim=c(0,1))
gg4 <- ggplot(data=
data.frame("Candidate" = c("Ossoff","Handel"),
"Vote.Share" = c(sum(results$outcome,na.rm=TRUE) / sum(results$outcome_total,na.rm=TRUE), 1-sum(results$outcome,na.rm=TRUE) / sum(results$outcome_total,na.rm=TRUE))),
aes(x=Candidate,y=Vote.Share,col=Candidate,fill=Candidate)) +
geom_bar(stat="identity",alpha=.9,width=.6) +
geom_hline(yintercept = .50,linetype=2) +
theme_elliott()+
labs(title = "#GA06 Projected Vote Shares",
subtitle ="Based on a projection of all precincts from those already reporting",
x = "Candidate",
y = "Vote Share (%)") +
scale_y_continuous(breaks=c(0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
labels = scales::percent_format(),limits = c(0,.7)) +
scale_color_manual(values=c("Ossoff" = "#5DADE2","Handel" = "#EC7063")) +
scale_fill_manual(values=c("Ossoff" = "#5DADE2","Handel" = "#EC7063")) +
geom_label(aes(label=paste0(round(Vote.Share,3)*100,"%")),col="white")
grid.arrange(grid.arrange(gg1,gg2,gg3,gg4,ncol=2),
my_g,heights=c(9, .2))
#gg1
dev.copy(png,"GA06Plot.png",width=12,height=10,unit="in",res=350)
dev.off()
### analyze ####
primary_current_report <- round(sum(results[!is.na(results$GE.OSSOFF),]$PRIMARY.DEM,na.rm=TRUE) / sum(results[!is.na(results$GE.OSSOFF),]$PRIMARY.VOTES,na.rm=TRUE),4) * 100
runoff_current_report <- round(sum(results$GE.OSSOFF,na.rm=TRUE) / sum(results$GE.VOTES,na.rm=TRUE),4) * 100
runoff_project <- round(sum(results$outcome,na.rm=TRUE) / sum(results$outcome_total,na.rm=TRUE),4)*100
#View(results)
cat("
OSSOFF VOTE IN DISTRICT-WIDE PRIMARY: 48.1%
DEM VOTE IN DISTRICT-WIDE PRIMARY: 48.9%
")
cat("------------------
")
cat("PRIMARY (AMONG CURRENTLY REPORTING PRECINCTS)
")
cat(paste0("Ossoff: ",primary_current_report,"%
"))
cat("------------------
")
cat("CURRENTLY REPORTING OSSOFF PERCENT
")
cat(paste0("Ossoff: ",runoff_current_report,"%
"))
cat("------------------
")
cat("PROJECTED DISTRICT-WIDE GE RESULT
")
cat(paste0("Ossoff: ",runoff_project,"%
"))
# write to gsheet ####
outputCSV <- results %>%
mutate("Ossoff.Share.Projected" = GE.Percent.Ossoff*100,
ossoffsharenow = (GE.OSSOFF/GE.VOTES )*100,
target = Ossoff.Benchmark + 1.08194984654851) %>%
dplyr::select(County,
Precinct,
"Dem Share Round 1" = Ossoff.Benchmark,
"Ossoff Target to Win Runoff" = target,
"Ossoff Share in Reporting Precincts" = ossoffsharenow,
"Ossoff Share in Projected Precincts" = Ossoff.Share.Projected,
"Round 1 Dem Votes" = PRIMARY.DEM,
"Round 1 Total Votes" = PRIMARY.VOTES,
"Round 2 Ossoff Votes" = GE.OSSOFF,
"Round 2 Total Votes" = GE.VOTES)
output_head <- data.frame(" " =c(primary_current_report,
runoff_current_report,
runoff_project))
gs_edit_cells(sheet,"Projections",input=output_head,anchor="E1")
write.csv(outputCSV,"output.csv",row.names = FALSE,na = "")
gs_edit_cells(sheet,"Projections",input=outputCSV,anchor="A5")
}else{cat("
No New Precinct Returns
")}
suppressMessages(gs_edit_cells(sheet,"Projections",input=data.frame("Last updated" = Sys.time()),anchor="F1"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment