In the 2016 election, says Bloomberg.com, Donald Trump “defied conventional wisdom, besting better financed candidates.” In doing so, he became the first presidential candidate since 1976 to defeat an opponent who raised more money. Such a rare event prompted my colleagues (Neal Vaidya, Pauline Emerald Ranjan, @joburn) and I to wonder if the Democratic campaign failed to make optimal use of their funds.
This begs the question: Can we optimize how campaigns allocate their funds?
Our team specifically wanted to know how a campaign can maximize the number of electoral votes won with a restricted budget. We took on the challenge to build an application to solve this problem during the SAS AI Hackathon, an internal competition in which we competed against other customer advisory teams. With the hackathon time constraint of 12 hours, our team created a basic optimization model to distribute campaign funds by state in order to maximize the number of electoral votes.
Below is the SAS® Visual Analytics dashboard we created, which depicts the optimal allocation of a candidate’s campaign funds by state. On the right is a breakdown of the allocation determined by our optimization model. As you can tell, some states in white do not have any campaign funding allocated to them. These states are strongly partisan in favor of the opposing candidate and thus viewed as a poor use of campaign funding or considered states where winning the popular vote is nearly guaranteed.
Elections and campaigns are very complicated, so explaining them in terms of linear relationships is not simple nor comprehensive. However, linear programming is a great method for gaining a better understanding of a complex problem. Our model can have much more depth, but for a quick summary, this simplification gives an easily digestible view of where campaign funding would be best utilized for a Democratic candidate.
In order to explain the campaign funding allocation problem, some assumptions had to be made. It was also necessary to quantify everything, even aspects that are not traditionally quantified, such as the cost to win a vote and a state overall.
There are many different forms of optimization models. One of the more basic models is linear programming. The goal of linear programming is to maximize or minimize an objective function based on specified constraints. These two ingredients, the objective function and constraints, are linear functions. Each linear function consists of decision variables. The decision variables in our case are the states—specifically whether the state was won or lost. Since all electoral votes of a state are awarded to the winning candidate of the popular vote, this becomes a zero-one integer linear programming model.
The goal is to maximize the number of states won in the election—the objective function. The objective function is represented by the following function:
The constraint for our optimization model is a budget of $1 billion, which is based on the budgets from the 2016 election. The other constraint represents that this is a zero-one integer linear program.
Our team decided to integrate SAS and Python to run the optimization model. We were able to write our model in native Python code, our preferred programming language, but then run the optimization model on the powerful SAS® Viya Cloud Analytic Services (CAS) analytics engine.
SAS has a few Python packages for optimization. We used sasoptpy, which is a Python package providing a modeling interface to SAS Viya and SAS/OR Optimization solvers. It provides a quick way for users to deploy optimization models and solve them using CAS actions. The sasoptpy package uses the swat package to communicate with SAS Viya. It also uses pandas structures extensively.
We ran the optimization 10 times with some variance to the party lean in each iteration because there will be some variance as the election moves along. Running the model 10 times and averaging the results also yields a more comprehensive answer because there is not one single way to distribute campaign funds.
Below is the Python code.
# Connect to CAS
s = swat.CAS("server.company.com", 5570, 'user', 'password')
# Simulate model 10 times
recommendation = np.repeat(0.0,51)
iterations = 10
for i in range(iterations):
sim_Data = SWV
# Sample from vote probability distribution
newlean = sim_Data.lean + np.random.normal(0, 5, 51)
costs = (newlean/100 * SWV.voters) ** 1.5 # cost per vote curve
costs[np.isnan(costs)] = 0
sim_Data['cost'] = costs
# Set objective function and constraint
m.set_objective(so.quick_sum(variables[state]*SWV.loc[SWV['state']==state,'votes'].iloc[0] for state in states), sense = so.MAX, name = 'objective')
con_1 = m.add_constraints(so.quick_sum( variables[state]*SWV.loc[SWV['state']==state,'cost'].iloc[0] for state in states ) <= 1000000000)
# Calculate results
result = m.solve()
m.get_solution_summary()
out = so.get_solution_table(variables).reset_index()
out['cost'] = out.iloc[:,1] * SWV.cost
recommendation += out.cost
# Output results
rec_df = pd.DataFrame({'cost': recommendation/iterations})
rec_df['state'] = SWV['state']
rec_df.to_csv('C:/Users/spniem/Desktop/sas_campaign_opt_results_2.csv')
SAS makes it very easy to connect to the CAS server from Python. All you need is the swat package, the host name, port, username, and password.
The results from the optimization model are output in a pandas data frame. We converted the pandas output to a CSV file, which we uploaded to SAS Viya. The Visual Analytics dashboard (seen at the beginning of the blog) displays the allocation of campaign funds by state on the map. There is also a breakdown by state in the table on the right. The total funding is shown in the bottom right corner of the dashboard. A total of $966 Million was distributed out of the $1 Billion budget constraint.
Below is the CSV version of the results. This gives a full breakdown of the distribution of campaign funds by state. One of the key benefits of the model is highlighting which states are worth investment and which are not, so that funds can be invested in a more optimal way towards other states. For example, no money was allocated to Texas because it was deemed too expensive to win over enough of the voting population to ultimately win the 38 electoral votes. This is because it leans so heavily Republican. As you can see, no money was allocated to California either. California leans so strongly Democratic that the party is highly likely to win the popular vote without further investment.
As part of the AI Hackathon, our team turned an abstract, complex problem into a quantifiable solution. We produced the results in an easily consumable and shareable medium in the form of a visually appealing dashboard. All this was accomplished in just 12 hours thanks to the power and seamless integration that the SAS Viya platform provides with open source programming languages.
Plus, it was a lot of fun to investigate a problem that interested all of us!
If you enjoyed this article, here is an article about how optimization can improve our daily lives from better cancer treatment to reduced contamination risks....
Texas doesn't lean so heavily as it once did. Problem is that 50.00001%=38, so everybody else gets no representation at all.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning and boost your career prospects.