#!/usr/bin/perl -w # # Digest Florida election results # use strict; my $dem_turnout = 0.659; # Exit poll values my $rep_turnout = 0.799; my $ind_turnout = 0.813; my $dem_prefer_kerry = 0.85; my $rep_prefer_kerry = 0.07; my $ind_prefer_kerry = 0.57; ##my $dem_prefer_bush = 0.14; ##my $rep_prefer_bush = 0.93; ##my $ind_prefer_bush = 0.41; my $lm_dem_prefer_kerry_et = 0.65095; # Preferences set from the linearized model of 2004 ET votes my $lm_rep_prefer_kerry_et = 0.08187; my $lm_ind_prefer_kerry_et = 0.36361; my $lm_dem_prefer_kerry_all = 0.4438; # Preferences set from the linearized model of total 2004 votes my $lm_rep_prefer_kerry_all = -0.1708; my $lm_ind_prefer_kerry_all = 1.1174; my $lm_dem_prefer_kerry_et_2000 = 0.6446; # Preferences set from the linearized model of 2000 ET votes my $lm_rep_prefer_kerry_et_2000 = -0.1229; my $lm_ind_prefer_kerry_et_2000 = 0.8198; my $lm_dem_prefer_kerry_all_2000 = 0.3889; # Preferences set from the linearized model of total 2000 votes my $lm_rep_prefer_kerry_all_2000 = -0.3480; my $lm_ind_prefer_kerry_all_2000 = 1.8702; my @counties; # County names -- other tables are indexed by name my %c_used_op_scan; # 1 => used op_scan voting, 0 => used e-touch my %c_voted; # Triples, [rep, dem, total] my %c_reg; # Triples, [rep, dem, total] my $tot_os = 0; my $tot_et = 0; my $vote_file = "florida_votes_reduced.txt"; my $file_set = 0; my $use_2000_data = 0; my $use_lm = 0; # Set => use the linear model, not the exit poll data my $use_all_votes = 0; # Set => use model for full state, not just ET counties my $dbg = 0; sub dbprint ($) { my ($str) = (@_); if ($dbg) { print $str; } } # **************************************************************** # Read arguments while (@ARGV > 0) { $_ = shift; if (/^-debug/) { $dbg = 1; } elsif (/^-2000/) { if (!$file_set) { $vote_file = "florida_votes_reduced_2000.txt"; } $use_2000_data = 1; $use_lm = 1; # We have no exit poll data for 2000 so use the linear model } elsif (/^-lm/) { # Switch to using a multilinear regression model of the votes $use_lm = 1; } elsif (/^-use_all_votes/) { $use_all_votes = 1; $use_lm = 1; } elsif (/^-file/) { # To use 2000 models with 2004 file or vice versa $file_set = 1; $vote_file = shift; } else { die "Argument $_ not understood\n"; } } if ($use_lm) { $dem_turnout = 1; # 100 percent turnout $rep_turnout = 1; $ind_turnout = 1; if (!$use_2000_data) { # Using 2004 model? if ($use_all_votes) { $dem_prefer_kerry = $lm_dem_prefer_kerry_all; $rep_prefer_kerry = $lm_rep_prefer_kerry_all; $ind_prefer_kerry = $lm_ind_prefer_kerry_all; } else { $dem_prefer_kerry = $lm_dem_prefer_kerry_et; $rep_prefer_kerry = $lm_rep_prefer_kerry_et; $ind_prefer_kerry = $lm_ind_prefer_kerry_et; } } else { # Using 2000 model? if ($use_all_votes) { $dem_prefer_kerry = $lm_dem_prefer_kerry_all_2000; $rep_prefer_kerry = $lm_rep_prefer_kerry_all_2000; $ind_prefer_kerry = $lm_ind_prefer_kerry_all_2000; } else { $dem_prefer_kerry = $lm_dem_prefer_kerry_et_2000; $rep_prefer_kerry = $lm_rep_prefer_kerry_et_2000; $ind_prefer_kerry = $lm_ind_prefer_kerry_et_2000; } } } # **************************************************************** # Print some general headers printf "Breakdown of county voting, by population bands,\n" . "split into counties using E-touch and opscan machines in 2004.\n" . "Models used are from the year %d.\n" . "Baseline expected values from %s.\n", $use_2000_data ? 2000 : 2004, !$use_lm ? "exit poll data" : !$use_all_votes ? "linearized model of ET county voting" : "linearized model of statewide voting"; print "Vote data from vote file $vote_file\n"; print "\n"; # **************************************************************** # Read the vote file open VFILE, "<$vote_file" or die "Can't open vote file $vote_file\n"; while () { chomp; if (! /^ (E-Touchscreen|Op-Scan-Precinct) \s+ # Machine type (\S+) \s+ # County name (\d+) \s+ # Rep votes (\d+) \s+ # Dem votes (\d+) \s+ # Total votes (\d+) \s+ # Rep registration (\d+) \s+ # Dem registration (\d+) # Total registration (?: \s+ (?:[0-9.\-]+) \s+ # %votes difference (?:[0-9.\-]+) # %reg difference ) ? $/x) { dbprint "Line not matched: $_\n"; next; } my ($mach,$county,$repv,$demv,$totv,$repr,$demr,$totr) = ($1,$2,$3,$4,$5,$6,$7,$8); ##dbprint "Machine: $mach ; County: $county\n"; push @counties, $county; my $is_os = ($mach eq "Op-Scan-Precinct") ? 1 : 0; if ($is_os) { $tot_os++; } else { $tot_et++; } $c_used_op_scan{$county} = $is_os; $c_voted{$county} = [$repv, $demv, $totv]; $c_reg{$county} = [$repr, $demr, $totr]; } close VFILE or die "Can't close votes file"; # **************************************************************** # Digest one variety of vote sub do_votes ($$) { my ($pop_low,$pop_high) = (@_); my $tot_votes = 0; my $tot_regs = 0; my $tot_excess = 0; my $tot_kerry_votes = 0; my $excess_et_votes = 0; my $excess_os_votes = 0; my $tot_et_kerry_votes = 0; my $tot_os_kerry_votes = 0; my $title; my $opscan_title = 0; foreach my $county (@counties) { my $c_opscan = $c_used_op_scan{$county}; my $voted = $c_voted{$county}; my $reg = $c_reg{$county}; my $rep_c_votes = $$voted[0]; my $dem_c_votes = $$voted[1]; my $tot_c_votes = $$voted[2]; my $rep_c_reg = $$reg[0]; my $dem_c_reg = $$reg[1]; my $tot_c_reg = $$reg[2]; my $other_c_reg = $tot_c_reg - ($rep_c_reg + $dem_c_reg); if ($tot_c_reg < $pop_low || $tot_c_reg >= $pop_high) { next; } if (! $title || $c_opscan != $opscan_title) { if ($title) { printf "Total excess votes for E-touch counties: %d (%.1f%%)\n\n", $excess_et_votes, $excess_et_votes * 100 / $tot_et_kerry_votes; } $opscan_title = $c_opscan; $title = ($c_opscan ? "Opscan counties:\n" : "E-touch counties:\n"); print $title; } my $expected_c_kerry_votes = $rep_c_reg * $rep_turnout * $rep_prefer_kerry; $expected_c_kerry_votes += $dem_c_reg * $dem_turnout * $dem_prefer_kerry; $expected_c_kerry_votes += $other_c_reg * $ind_turnout * $ind_prefer_kerry; my $excess = $dem_c_votes - $expected_c_kerry_votes; my $excess_pct = ($excess / $expected_c_kerry_votes) * 100; printf "%15s: Expected: %10d; Observed: %10d; Excess: %10.f (%5.1f%%)\n", $county, $expected_c_kerry_votes, $dem_c_votes, $excess, $excess_pct; if ($c_opscan) { $excess_os_votes += $excess; $tot_os_kerry_votes += $dem_c_votes; } else { $excess_et_votes += $excess; $tot_et_kerry_votes += $dem_c_votes; } $tot_excess += $excess; $tot_kerry_votes += $dem_c_votes; $tot_votes += $tot_c_votes; $tot_regs += $tot_c_reg; } printf "Total excess votes for Opscan counties: %d (%.1f%%)\n\n", $excess_os_votes, $tot_os_kerry_votes ? $excess_os_votes * 100 / $tot_os_kerry_votes : 0; if ($dbg) { foreach my $county (@counties) { print "$county\n"; } } printf "Total votes: $tot_votes; Total dem votes: $tot_kerry_votes; Total registered: $tot_regs\n" . " Total excess votes: %6d (%4.1f%%) \n", $tot_excess, $tot_kerry_votes ? $tot_excess * 100 / $tot_kerry_votes : 0; print "Total OS: $tot_os; Total ET: $tot_et\n"; } # **************************************************************** print "All counties:\n"; do_votes (0, 100000000); print "\nCounties < 50,000 registered voters:\n"; do_votes (0,50000); print "\nCounties >50,000, <100,000 registered voters:\n"; do_votes (50000, 100000); print "\nCounties >100,000, <200,000 registered voters:\n"; do_votes (100000, 200000); print "\nCounties >200,000, <300,000 registered voters:\n"; do_votes (200000, 300000); print "\nCounties >300,000 registered voters:\n"; do_votes (300000, 100000000);