From cbda7b1e5c1bbd68ae7263ffc59be4baedca6fa6 Mon Sep 17 00:00:00 2001 From: NunoSempere Date: Sun, 14 Apr 2024 21:42:38 -0400 Subject: [PATCH] move glue code function to the end --- main.go | 356 +++++++++++++++++++++++++++----------------------------- 1 file changed, 172 insertions(+), 184 deletions(-) diff --git a/main.go b/main.go index 36e0d58..569cd4e 100644 --- a/main.go +++ b/main.go @@ -34,180 +34,6 @@ type Poll struct { /* Globals */ var r = rand.New(rand.NewPCG(uint64(100), uint64(2224))) -var dev = false - -/* Load data from csvs */ -func readStates() ([]State, error) { - var states map[string]State = make(map[string]State) - - /* Electoral college votes for the 2024 election*/ - votes_file, err := os.Open("data/num-electors/electoral-college-votes.csv") - // votes_file, err := os.Open("data/electoral-college-votes-2010-census.csv") - if err != nil { - return nil, fmt.Errorf("error opening the votes file: %v", err) - } - defer votes_file.Close() - - votes_reader := csv.NewReader(votes_file) - if _, err := votes_reader.Read(); err != nil { // Skip header - return nil, fmt.Errorf("error reading votes header: %v", err) - } - for { - csv_record, err := votes_reader.Read() - if err != nil { - break // EOF or an error - } - votes, err := strconv.Atoi(csv_record[1]) - if err != nil { - continue // Error in converting votes, skip this record - } - state := csv_record[0] - if _, exists := states[state]; !exists { - states[state] = State{Name: state, Votes: votes, PresidentialElectoralHistory: make(map[string]string)} - } - } - - /* Election results */ - var years = []string{"2000", "2004", "2008", "2012", "2016", "2020"} - for _, year := range years { - electoral_history_filename := fmt.Sprintf("data/electoral-history/%s.csv", year) - electoral_history_file, err := os.Open(electoral_history_filename) - if err != nil { - return nil, fmt.Errorf("error opening the electoral_history file for %s: %v", year, err) - } - electoral_history_reader := csv.NewReader(electoral_history_file) - if _, err := electoral_history_reader.Read(); err != nil { // Skip header - return nil, fmt.Errorf("error reading electoral_history header for %s: %v", year, err) - } - for { - record, err := electoral_history_reader.Read() - if err != nil { - break // EOF or an error - } - state, party := record[0], record[1] - data, exists := states[state] - if !exists { - continue // State not found in votes map, skip - } - // Update the party winning in the specific year - data.PresidentialElectoralHistory[year] = party - states[state] = data - } - - electoral_history_file.Close() - } - - /* Read polls */ - polls_file, err := os.Open("data/polls/president_polls_state.csv") // Make sure to update this path - if err != nil { - return nil, fmt.Errorf("error opening the polls file: %v", err) - } - defer polls_file.Close() - - // Using a temporary map to group poll results by state and poll ID - state_polls_map := make(map[string]map[string]Poll) - - polls_reader := csv.NewReader(polls_file) - _, err = polls_reader.Read() // Skip the header - if err != nil { - return nil, fmt.Errorf("error reading polls header: %v", err) - } - - for { - record, err := polls_reader.Read() - if err != nil { - break // EOF or an error - } - - poll_id := record[0] - state_name := record[12] - end_date := record[14] - partisan := record[32] - candidate_name := record[44] - - date_layout := "1/2/06" - parsed_date, err := time.Parse(date_layout, end_date) - if err != nil { - fmt.Println("Error parsing date: ", err) - } - - sample_size, err := strconv.Atoi(record[22]) - if err != nil { - continue // If error, skip this record - } - - percentage, err := strconv.ParseFloat(record[47], 64) // percentage is in the 42nd column - if err != nil { - fmt.Printf("Error parsing percentage") - continue // If error, skip this record - } - - if _, exists := state_polls_map[state_name]; !exists { - state_polls_map[state_name] = make(map[string]Poll) - } - - poll, exists := state_polls_map[state_name][poll_id] - if !exists { - poll = Poll{ - PollId: poll_id, - SampleSize: sample_size, - PollResults: make(map[string]float64), - Date: parsed_date, - Partisan: partisan, - } - } - poll.PollResults[candidate_name] = percentage - state_polls_map[state_name][poll_id] = poll - } - - // Add the aggregated poll data to the respective states - for state_name, polls := range state_polls_map { - - // Filter polls by recency and by having both Biden and Trump - var recent_polls []Poll - for _, poll := range polls { - if poll.Date.After(time.Now().AddDate(0, 0, -30)) { - recent_polls = append(recent_polls, poll) - } - } - var recent_biden_trump_polls []Poll - for _, recent_poll := range recent_polls { - has_biden := false - has_trump := false - for candidate_name, _ := range recent_poll.PollResults { - if candidate_name == "Biden" { - has_biden = true - } else if candidate_name == "Trump" { - has_trump = true - } - } - if has_biden && has_trump { - recent_biden_trump_polls = append(recent_biden_trump_polls, recent_poll) - } - } - - if state, exists := states[state_name]; exists { - state.Polls = recent_biden_trump_polls - states[state_name] = state // Not redundant - } else { - // fmt.Printf("Encountered new state: %s\n", state_name) - /* - states[state_name] = State{ - Name: state_name, - Polls: polls_slice, - } - */ - } - } - - // Convert statesData map to a slice for returning - var states_slice []State - for _, state := range states { - states_slice = append(states_slice, state) - } - - return states_slice, nil -} /* Sampling helper functions */ func getNormalCDF(x float64, mean float64, std float64) float64 { @@ -225,7 +51,6 @@ func getChanceCandidateWinsFromPollShare(candidate_p float64, poll_sample_size f } func getChanceRepublicanWinFromPoll(poll Poll, pretty_print bool) float64 { - biden_percentage, biden_exists := poll.PollResults["Biden"] trump_percentage, trump_exists := poll.PollResults["Trump"] if !biden_exists || !trump_exists { @@ -249,11 +74,9 @@ func getChanceRepublicanWinFromPoll(poll Poll, pretty_print bool) float64 { fmt.Printf("\n\t\tPoll says chance of R win: %f", p_republican_win) } return p_republican_win - } func getChanceRepublicanWinFromPollPlusUncertainty(poll Poll, state State, pretty_print bool) float64 { - // Uncertainty from the state n_republican_win := 0 for _, party := range state.PresidentialElectoralHistory { @@ -297,7 +120,6 @@ func getChanceRepublicanWinFromPollPlusUncertainty(poll Poll, state State, prett fmt.Printf("\n\t\tN republican wins: %d", n_republican_win) fmt.Printf("\n\t\t=> Reducing additional uncertainty") } - } std_error := std_error_poll_mean + std_additional_uncertainty @@ -310,7 +132,6 @@ func getChanceRepublicanWinFromPollPlusUncertainty(poll Poll, state State, prett fmt.Printf("\n\t\tPoll plus uncertainty says chance of R win: %f", p_republican_win) } return p_republican_win - } /* Print state by state data */ @@ -357,9 +178,7 @@ func printStates(states []State) { _ = getChanceRepublicanWinFromPoll(aggregate_poll, true) _ = getChanceRepublicanWinFromPollPlusUncertainty(aggregate_poll, state, true) } - } - } /* Sample state by state */ @@ -445,7 +264,6 @@ func sampleFromState(state State) VotesForEachParty { /* Simulate election */ func simulateElection(states []State) int { - republican_seats := 0 for _, state := range states { election_sample := sampleFromState(state) @@ -464,7 +282,6 @@ func barString(n int) string { } func printElectoralCollegeHistogram(samples []int) { - histogram := [538]int{} for _, sample := range samples { histogram[sample]++ @@ -490,7 +307,179 @@ func printElectoralCollegeHistogram(samples []int) { } } +} + +/* Load data from csvs */ +// Glue code +func readStates() ([]State, error) { + var states map[string]State = make(map[string]State) + + /* Electoral college votes for the 2024 election*/ + votes_file, err := os.Open("data/num-electors/electoral-college-votes.csv") + // votes_file, err := os.Open("data/electoral-college-votes-2010-census.csv") + if err != nil { + return nil, fmt.Errorf("error opening the votes file: %v", err) + } + defer votes_file.Close() + + votes_reader := csv.NewReader(votes_file) + if _, err := votes_reader.Read(); err != nil { // Skip header + return nil, fmt.Errorf("error reading votes header: %v", err) + } + for { + csv_record, err := votes_reader.Read() + if err != nil { + break // EOF or an error + } + votes, err := strconv.Atoi(csv_record[1]) + if err != nil { + continue // Error in converting votes, skip this record + } + state := csv_record[0] + if _, exists := states[state]; !exists { + states[state] = State{Name: state, Votes: votes, PresidentialElectoralHistory: make(map[string]string)} + } + } + + /* Election results */ + var years = []string{"2000", "2004", "2008", "2012", "2016", "2020"} + for _, year := range years { + electoral_history_filename := fmt.Sprintf("data/electoral-history/%s.csv", year) + electoral_history_file, err := os.Open(electoral_history_filename) + if err != nil { + return nil, fmt.Errorf("error opening the electoral_history file for %s: %v", year, err) + } + electoral_history_reader := csv.NewReader(electoral_history_file) + if _, err := electoral_history_reader.Read(); err != nil { // Skip header + return nil, fmt.Errorf("error reading electoral_history header for %s: %v", year, err) + } + for { + record, err := electoral_history_reader.Read() + if err != nil { + break // EOF or an error + } + state, party := record[0], record[1] + data, exists := states[state] + if !exists { + continue // State not found in votes map, skip + } + // Update the party winning in the specific year + data.PresidentialElectoralHistory[year] = party + states[state] = data + } + + electoral_history_file.Close() + } + + /* Read polls */ + polls_file, err := os.Open("data/polls/president_polls_state.csv") // Make sure to update this path + if err != nil { + return nil, fmt.Errorf("error opening the polls file: %v", err) + } + defer polls_file.Close() + + // Using a temporary map to group poll results by state and poll ID + state_polls_map := make(map[string]map[string]Poll) + + polls_reader := csv.NewReader(polls_file) + _, err = polls_reader.Read() // Skip the header + if err != nil { + return nil, fmt.Errorf("error reading polls header: %v", err) + } + + for { + record, err := polls_reader.Read() + if err != nil { + break // EOF or an error + } + poll_id := record[0] + state_name := record[12] + end_date := record[14] + partisan := record[32] + candidate_name := record[44] + + date_layout := "1/2/06" + parsed_date, err := time.Parse(date_layout, end_date) + if err != nil { + fmt.Println("Error parsing date: ", err) + } + + sample_size, err := strconv.Atoi(record[22]) + if err != nil { + continue // If error, skip this record + } + + percentage, err := strconv.ParseFloat(record[47], 64) // percentage is in the 42nd column + if err != nil { + fmt.Printf("Error parsing percentage") + continue // If error, skip this record + } + + if _, exists := state_polls_map[state_name]; !exists { + state_polls_map[state_name] = make(map[string]Poll) + } + + poll, exists := state_polls_map[state_name][poll_id] + if !exists { + poll = Poll{ + PollId: poll_id, + SampleSize: sample_size, + PollResults: make(map[string]float64), + Date: parsed_date, + Partisan: partisan, + } + } + poll.PollResults[candidate_name] = percentage + state_polls_map[state_name][poll_id] = poll + } + + // Add the aggregated poll data to the respective states + for state_name, polls := range state_polls_map { + + // Filter polls by recency and by having both Biden and Trump + var recent_polls []Poll + for _, poll := range polls { + if poll.Date.After(time.Now().AddDate(0, 0, -30)) { + recent_polls = append(recent_polls, poll) + } + } + var recent_biden_trump_polls []Poll + for _, recent_poll := range recent_polls { + has_biden := false + has_trump := false + for candidate_name, _ := range recent_poll.PollResults { + if candidate_name == "Biden" { + has_biden = true + } else if candidate_name == "Trump" { + has_trump = true + } + } + if has_biden && has_trump { + recent_biden_trump_polls = append(recent_biden_trump_polls, recent_poll) + } + } + + if state, exists := states[state_name]; exists { + state.Polls = recent_biden_trump_polls + states[state_name] = state // Not redundant + } else { + // fmt.Printf("Encountered new state: %s\n", state_name) + /* + states[state_name] = State{ + Name: state_name, + Polls: polls_slice, + } + */ + } + } + + // Convert statesData map to a slice for returning + var states_slice []State + for _, state := range states { + states_slice = append(states_slice, state) + } + return states_slice, nil } func main() { @@ -518,5 +507,4 @@ func main() { p_republicans = p_republicans / float64(n_sims) fmt.Printf("\n%% republicans: %f\n", p_republicans) - }