Political Modeling & Election Simulations

Dr. Dobb's Journal October, 2004

Software tools for examining real-world processes

By Mary Lynn Reed

Mary Lynn is a mathematician, programmer, and writer who lives in Tampa, Florida. She can be reached at marylynnreedyahoo.com.

Politics is a messy game that gets even uglier at election time. Voters struggle to determine which candidate best represents their views, while candidates strategize on how to win the most votes on election day. It is a complex system, perhaps even chaotic at times, which makes it an interesting subject for modeling and simulation.

Agent-based modeling and simulation are natural tools for social science research and modeling real-world processes that involve individual and group behavior. Agent-based models contain a set of actors (possibly with several types, such as voters and candidates) that each follow a simple set of rules. Usually, each type of actor has the same set of rules. Simulations involve stepping through time with each agent following its rules. Modelers can then analyze group dynamics by observing the behavior of a collection of agents over many simulations.

This type of modeling follows an iterative development process—gather real-world data observations, define a model, run simulations with the model, compare results of the simulation to real-world data observations, revise the model, and repeat as necessary. While many different aspects of the political process can be modeled with agent-based simulations, in this article, I focus on two-candidate (or two-party) elections and a subset of the full modeling process—defining initial models, running the simulations, and making observations on simulation results.

Voting

How do people make their choices at election time? While there is no single answer to this question, one common hypothesis is that individuals' choices are influenced by the choices of people around them. This is a simple idea in response to a complicated question. Hence, it is the perfect starting point for a model.

The model takes place on a square grid. Cells on the grid represent voters. To begin, each cell on the grid has one of two preferences, which we visualize by coloring the cells blue or red (if you like, think Democrat and Republican). At each step of the simulation, an individual polls the preferences of his eight adjoining neighbors. If a majority of the individuals closest to him are blue, he becomes blue. Likewise, if the majority of the individuals closest to him are red, he becomes red. Does this sound like the behavior pattern of any voters you know?

Running this simulation many times shows us that the process eventually reaches equilibrium, where no cells change color from one iteration to the next. Because there are eight neighbors for every cell, ties can occur. In the basic model, if a four-to-four tie occurs, the center cell does not change his preference. Different options for handling ties and close votes result in different long-run behavior. In particular, letting cells have "sympathy for the underdog" by changing their vote to the loser in the case of a three-to-five poll, results in chaotic long-run behavior.

Figure 1 shows this voting model after the initial random selection of blue and red preferences for each cell. Figure 2 shows the resulting grid after running the simulation to equilibrium.

NetLogo & Repast

NetLogo is a multiagent, programmable modeling environment written in Java. Models are developed in the NetLogo programming language, which is based on MIT's Logo and StarLogo languages. Developed at the Center for Connected Learning and Computer-Based Modeling, Northwestern University, the NetLogo software package (http://ccl.northwestern.edu/netlogo/) also provides an easy-to-use interface designer and a large collection of sample models in a Models Library, including the Voting model just described.

RePast is another cross-platform, agent-based modeling system that is written in Java. RePast, short for the "REcursive Porous Agent Simulation Toolkit" and developed by the University of Chicago's Social Science Research Computing group (http://repast.sourceforge.net/index.php), requires modelers to program directly in Java.

One-Dimensional Election Model

One of the most annoying facts of two-party election politics is the tendency for both candidates to move their positions on policy issues to the center in order to win more votes. The Median Voter Theorem formalizes this notion and was proven under a set of reasonable assumptions by Duncan Black (see The Theory of Committees and Elections, Cambridge University Press, 1958).

Using NetLogo, I built a one-dimensional election model with two types of agents—voters and candidates. Agents are placed on a one-dimensional line (viewed as the x-axis of a coordinate system). An agent's placement on the line is defined as his "issue point." For this model, issue points lie in the interval [-50,50]. There are two candidates, one Democrat and one Republican. Democratic candidates are always represented as negative numbers ("left of center"), while Republican candidates are positive numbers ("right of center"). Voters come in three different varieties: Democrat, Republican, and Independent. Democratic voters' beliefs are represented as real numbers in the region [-50, ED], while Republican voters' beliefs are represented as real numbers in the region [-ER,50], where ED and ER are parameters. Hence, a basic assumption of the model is that Democratic candidates are never "right of center" and Republican candidates are never "left of center," but a small number of party-affiliated voters can cross over the central point.

Party loyalty is also examined in the model. If party loyalty is turned on, a parameter sets the weight voters give to their party affiliation versus their issue point. Independent voters never vote by party and only judge candidates on the issues.

In addition to party, voters have another property called "Information Level." A voter's Information Level is a number between 0 and 1, which represents the purity of information this voter receives about the relationship of his issue point to the candidate's issue points.

To initialize the model, users set the parameters including the total number of voters and the proportion of Democratic and Republican voters in the population. The initialization (setup) procedure randomly places the voters in their allowed region, based on party. Independent voters are randomly placed throughout the entire interval. The two candidates are also randomly placed on their side of the central point (Democrats to the left, Republicans to the right).

Figure 3 shows the NetLogo interface for this one-dimensional model after initial setup. Democratic voters are represented by blue dots, Republican voters by red dots, and independent voters by green dots. The Democratic candidate is the blue "person" and the Republican candidate is the red "person."

For each iteration of the simulation, the votes are counted based on the current position of the candidates (and voters). A voter casts his ballot for the closest candidate to him on the line. If variable information levels are present, a voter's distance to a candidate is calculated as a weighted average of the real distance and a random distance, using the information level as the weight of the real distance. So, if the voter has "pure" information, he perceives the correct distance between himself and each of the candidates. If the voter does not have pure information, the distance he perceives between himself and the candidates is garbled.

For each iteration, the results of the voting process are tallied and output into several graphs. Throughout the simulation, voters never move their issue points. The winning candidate also does not move, but the losing candidate randomly selects new positions until he finds one that will win him more votes. A threshold is set for the number of new positions the losing candidate will try before giving up. I used a small threshold (five), mainly for speed.

Figure 4 illustrates a run of this simulation without variable information or party loyalty. Notice the graph labeled "Candidate Platform Near Median," which reports the cumulative percentage of elections (iterations) in which the candidate was close to the center point. When voters receive pure information, the Median Voter Theorem holds and candidates always seek the central point to obtain the most votes. Also, when all voters receive pure information, there is usually one candidate that emerges as the winner of most of the iterations, even with a relatively even party split. This is because voters are not moving their positions so, given a particular configuration of voters, one candidate is likely to emerge victorious when placed at the central point.

Figure 5 illustrates a run of the model with variable information and party loyalty present. The variable information has an enormous impact on the simulation results and clearly gets closer to true voter behavior. In this case, the candidates no longer need to move to the center to win elections. Notice that even though there are more Democrats than Republicans, both parties have won a large number of elections. Voters that do not have pure information add a chaotic element to the election process. They don't vote consistently because they lack the information to make the "correct" choices. As a result, no single party or candidate wins consistently, even when they place their platform at the exact central point.

Listing One presents the NetLogo procedures for this model. To run this model, you'll also need to build the interface in the NetLogo system. If you're interested in doing this, it should be fairly easy using Figures 3-5, once you get familiar with NetLogo.

Electoral College Model

Like it or not, U.S. presidents are still elected via the electoral college. So, if you want to model U.S. presidential elections, you must include the mechanics and numerology of the electoral college. Here's how it works: Each state is allocated a number of electors in the electoral college equal to the number of its U.S. Senators (always two) plus the number of its U.S. Representatives. The number of U.S. Representatives for a state may change each decade according to the state's population as determined in the U.S. Census. The candidate that gets the largest popular vote in a state is awarded all of the electoral votes for that state. The candidate with the majority of electoral votes becomes president. For exceptions and other interesting facts about the electoral college, see http://www.fec.gov/pages/ecmenu2.htm. For the 2004 presidential election, there are 538 electoral votes in total; 270 are required to win the presidency. A table that breaks down the electoral votes by state is available electronically; see "Resource Center," page 5.

As a jumping off point for modeling U.S. presidential elections, I developed an electoral college model, which is a variation on the two-dimensional voting model. In this model, our agents are now states, not individuals. Generally speaking, states that are adjacent have a good chance of voting the same way. Those brightly colored maps of election results on TV never look like a checkerboard. The red states (those voting Republican) tend to clump together, as do the blue states (those going to the Democrats). So, in this initial model, at each iteration of the simulation, a state will poll its adjacent states on how they are voting, then change its own vote accordingly. To give more weight to heavily populated states, electoral vote counts are used when polling adjacent states.

To make the model more realistic, I initialize the choice of each state using historical electoral college results for the 10 presidential elections from 1964 through 2000; see Figure 6. States colored red in this map have voted Republican in 70 percent or more of those 10 elections. Likewise, the blue states voted Democrat 70 percent of the time or more. The yellow states are those with splits that were closer than 70/30.

One thing that makes presidential elections so interesting is the large number of electoral votes owned by the "battleground states." The yellow states in Figure 6 represent 266 electoral votes. Notice that Florida is red in Figure 6. In fact, Florida went to the Republicans in 7 out of the 10 elections. But, remember Florida in 2000? Depending on your point of view, you might argue that Florida, and its 27 electoral votes, should be in the yellow category, also. Nevertheless, I left Florida "red" for the purpose of this model. I explored two different initialization methods for this electoral college model.

At the end of each iteration of the simulation, a vote of the electoral college is taken and recorded. The emergent behavior of this model is either convergence to an equilibrium state, or altering between two different configurations. We really can't expect reasonable election predictions based on a model this simple. Nevertheless, here are the results over a large number of simulations: The Republican candidate was victorious 79 percent of the time using Method 1 and 84 percent of the time using Method 2.

Figures 7 and 8 show the results of one particular simulation using Method 1 initialization. This is an example of a case where the Democratic candidate does win. It is also an example where the simulation does not go to equilibrium, but instead alternates between two configurations, as in Figures 7 and 8. Figure 9 shows an example of a Republican win.

DDJ



Listing One
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; One-Dimensional Election Model
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

globals [ Prop_Indep NumDems NumReps NumIndep DemVotes RepVotes 
      DemCand RepCand Winner DemWins RepWins DemNear RepNear NumIter ]
breeds [ voters candidates centralpoint ]
turtles-own [ party ]
voters-own [ infolevel ]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to setup
  ca
  cct 1 [  ;; creates the central "neutral line"
    set breed centralpoint
    set color white
    set shape "line"
    set size 10.0
  ]
  set Prop_Indep 1 - Prop_Dem - Prop_Rep 
  if (Prop_Indep < 0)
    [ set Prop_Rep 1 - Prop_Dem 
      set Prop_Indep 0 ]
  setup-voters
  setup-candidates
  set DemWins 0
  set RepWins 0
  set DemNear 0
  set RepNear 0
  set NumIter 0
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to setup-voters
  set NumDems round NumberOfVoters * Prop_Dem
  set NumReps round NumberOfVoters * Prop_Rep
  set NumIndep round NumberOfVoters - NumDems - NumReps
  if NumIndep < 0 [ set NumIndep 0 ]
  foreach n-values NumDems [?] 
  [
    ask random-one-of patches with [pycor = 0 and pxcor <= Epsilon_D] [
      sprout 1 [
    set breed voters
    set color blue
    set size .6
    set shape "box"
    set infolevel random-float 1.0
      ]
    ]
  ]
  foreach n-values NumReps [?]
  [
    ask random-one-of patches with [pycor = 0 and pxcor >= 0 - Epsilon_R] [
      sprout 1 [
    set breed voters
    set color red
    set size .6
    set shape "box"
    set infolevel random-float 1.0
      ]
    ]
  ]
  foreach n-values NumIndep [?]
  [
    ask random-one-of patches with [pycor = 0] [
      sprout 1 [
    set breed voters
    set color green
    set size .6
    set shape "box"
    set infolevel random-float 1.0
      ]
    ]
   ]
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to setup-candidates
  sprout-RepCand
  sprout-DemCand
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to sprout-RepCand
  ask random-one-of patches with [pycor = 0 and pxcor >= 0] 
    [ sprout 1 
      [ ;; set up Republican Candidate
      set breed candidates
      set color red 
      set size 5.0
      set shape "person" 
      set RepCand who
      ]
    ]
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to sprout-DemCand
ask random-one-of patches with [pycor = 0 and pxcor <= 0] 
  [ sprout 1 
    [  ;; set up Democratic Candidate
    set breed candidates
    set color blue
    set size 5.0
    set shape "person"
    set DemCand who
    ]
  ]
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to count-votes
  locals [ dV rV distD distR r1 r2 ]
  set dV 0
  set rV 0
  ask voters 
    [
     set distD distance-nowrap turtle DemCand
     set distR distance-nowrap turtle RepCand
     if Variable_Information? [ 
       set r1 random-float 2 * screen-edge-x
       set r2 random-float 2 * screen-edge-x
       set distD distD * infolevel + r1 * (1 - infolevel)
       set distR distR * infolevel + r2 * (1 - infolevel)
     ]
     ifelse Party_Loyalty? [
       ifelse color != green ; if voter is Independent, no Party Loyalty
       [  set r1 random 100
      ifelse r1 < PartyPreferenceWeight ; if in "party loyalty region"
       [ ifelse color = blue
           [ set dV dV + 1 ]  ; if blue, vote Dem
           [ set rV rV + 1 ]  ; if red, vote Rep
       ]
       [ ifelse distD >= distR   ; outside the party loyalty region
           [ set rV rV + 1 ]     ; vote by distance to candidates
           [ set dV dV + 1 ]
       ]   
       ]
       [ ifelse distD >= distR ; if voter is Independent, no Party loyalty
     [ set rV rV + 1 ]
     [ set dV dV + 1 ]
       ]
      ]
      [  ifelse distD >= distR ;  in case No Party Loyalty
     [ set rV rV + 1 ]
     [ set dV dV + 1 ]
      ]
     ]
  set RepVotes rV
  set DemVotes dV
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to update-candidates
  locals [ dVorig rVorig iter ]
  ifelse DemVotes > RepVotes
    [ ;; Loser (Republican Candidate) Moves Platform To Get More Votes
    set rVorig RepVotes
    set iter 0
     while [ RepVotes <= rVorig and iter < 5 ]
     [
       ask turtle RepCand [ die ]
       sprout-RepCand
       count-votes
       set iter iter + 1
     ]
    ]
    [ ;; Loser (Democratic Candidate) Moves Platform To Get More Votes    
    set dVorig DemVotes
    set iter 0 
     while [ DemVotes <= dVorig and iter < 5 ] 
     [
       ask turtle DemCand [ die ]
       sprout-DemCand
       count-votes
       set iter iter + 1
     ]
    ] 
end  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to do-plots
  set-current-plot "Election Results"
  set-current-plot-pen "Dem"
  plot 100 * DemVotes / NumberOfVoters
  set-current-plot-pen "Rep"
  plot 100 * RepVotes / NumberOfVoters
  set-current-plot "Cumulative Wins"
  set-current-plot-pen "Dem"
  plot DemWins
  set-current-plot-pen "Rep"
  plot RepWins
  set-current-plot "Candidate Platform Near Median"
  set-current-plot-pen "Dem"
  plot 100 * DemNear / NumIter
  set-current-plot-pen "Rep"
  plot 100 * RepNear / NumIter
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to go
  count-votes
  set NumIter NumIter + 1
  ifelse DemVotes > RepVotes
  [ set Winner "Dem"
    set DemWins DemWins + 1 ]
  [ set Winner "Rep" 
    set RepWins RepWins + 1 ]
  ask turtle DemCand [ if xcor > -6  [ set DemNear DemNear + 1 ] ]
  ask turtle RepCand [ if xcor < 6 [set RepNear RepNear + 1 ] ]
  do-plots
  update-candidates
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Back to article