Created
June 17, 2017 23:03
-
-
Save elliottmorris/a7dacae5afdac42318b7dc3bffbcc551 to your computer and use it in GitHub Desktop.
Predicting #GA06
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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