{"id":2359,"date":"2020-11-07T18:23:02","date_gmt":"2020-11-08T02:23:02","guid":{"rendered":"http:\/\/zackmdavis.net\/blog\/?p=2359"},"modified":"2020-12-13T17:18:25","modified_gmt":"2020-12-14T01:18:25","slug":"scoring-2020-us-presidential-election-predictions","status":"publish","type":"post","link":"http:\/\/zackmdavis.net\/blog\/2020\/11\/scoring-2020-us-presidential-election-predictions\/","title":{"rendered":"Scoring 2020 U.S. Presidential Election Predictions"},"content":{"rendered":"<p>I was curious to see how various prognosticators\u2014specifically, <a href=\"https:\/\/projects.fivethirtyeight.com\/2020-election-forecast\/\"><em>FiveThirtyEight<\/em><\/a> and <a href=\"https:\/\/projects.economist.com\/us-2020-forecast\/president\"><em>The Economist<\/em><\/a>'s models, and the <a href=\"https:\/\/www.predictit.org\/markets\/13\/Prez-Election\">PredictIt prediction markets<\/a>\u2014did on predicting the state-by-state <a href=\"https:\/\/twitter.com\/zackmdavis\/status\/1323492262198718464\">(plus the District of Columbia)<\/a> results of the recent U.S. presidential election.<br \/>\n<!--more--><\/p>\n<h3 id=\"mathematical-sidebar\">Mathematical Sidebar<\/h3>\n<p>There are various ways to evaluate probabilistic predictions, but my favorite is to use the <em>logarithmic score<\/em>: the logarithm of the probability assigned to the right answer. (Logs of probabilities are negative numbers, but negating everything to get positive numbers doesn't change anything interesting\u2014you just minimize instead of maximizing\u2014such that I tend to mentally conflate the log and the negative-log.)<\/p>\n<p>The reason I think the logarithmic score is best is because it has one essential property, one cool property, and a meaningful interpretation.<\/p>\n<p>The essential property is that it <a href=\"https:\/\/en.wikipedia.org\/wiki\/Scoring_rule#Proper_scoring_rules\">incentivizes you to report your actual probabilities<\/a>: if something actually happens 80% of the time, you get the best expected score by giving it probability 0.8.<\/p>\n<p>The cool property is that <a href=\"https:\/\/www.readthesequences.com\/A-Technical-Explanation-Of-Technical-Explanation\">it doesn't matter how you chop up your observations<\/a>: because conjunction of probabilities is multiplication and the logarithm maps multiplication to addition, we get the same score whether we consider \"A&amp;B\" as one event, or separately add up the scores of \"A\" and \"B, given A\".<\/p>\n<p>(Although as <a href=\"https:\/\/twitter.com\/TheDavidSJ\/status\/1325561155524288514\">David Schneider-Joseph<\/a> and <a href=\"https:\/\/www.lesswrong.com\/posts\/muEjyyYbSMx23e2ga\/scoring-2020-u-s-presidential-election-predictions?commentId=iibA9SicAbufWE6q5\">Oscar Cunningham<\/a> pointed out in response to the originally published version of this post, my calculations later in this post add up scores of state-by-state predictions as if the state results were independent events, but this independence assumption is not realistic. Sorry.)<\/p>\n<p>The interpretation is that the logarithmic score represents <a href=\"https:\/\/www.lesswrong.com\/posts\/mB95aqTSJLNR9YyjH\/message-length\">the length of the message you would need to encode the actual outcome using a code optimized for your model<\/a>. (Er, the negation of the score represents the length\u2014there's that conflation.)<\/p>\n<h3 id=\"methodology\">Methodology<\/h3>\n<p>So, the election results aren't <em>really<\/em> final until all the states certify their results\u2014or perhaps, when the Electoral College meets. The Trump campaign <a href=\"https:\/\/archive.is\/GhkyS\">has filed lawsuits disputing results in a number of states<\/a>, and at time of writing, <a href=\"https:\/\/abcnews.go.com\/Elections\/2020-us-presidential-election-results-live-map\/\">ABC News's map<\/a> has no call for Alaska, Arizona, North Carolina, and Georgia. But for the purposes of this blog post, I'm just going to go with the current colors on <a href=\"https:\/\/www.politico.com\/2020-election\/results\/president\/\">Politico's map<\/a>, and assume that Biden wins Arizona and Georgia and that Trump wins Alaska and North Carolina.<\/p>\n<p>At around 20:10 Pacific time on 2 November, Election Day Eve, I downloaded the model-output ZIP files from <a href=\"https:\/\/projects.fivethirtyeight.com\/data-webpage-data\/datasets\/election-forecasts-2020.zip\"><em>FiveThirtyEight<\/em><\/a> and <a href=\"https:\/\/cdn.economistdatateam.com\/us-2020-forecast\/data\/president\/economist_model_output.zip\"><em>The Economist<\/em><\/a>. Then today, I looked up 2 November prices for the Democrat-wins contracts in the line-graphs on the pages for the PredictIt \"Which party will win this-and-such-state in the 2020 presidential election?\" markets. (Both <em>FiveThirtyEight<\/em> and <em>The Economist<\/em> would later issue final updates on Election Day, but I'm assuming it couldn't have changed much, and it's a fairer comparison to the PredictIt bucketed-by-day line graphs to use the model outputs from Election Day Eve.)<\/p>\n<p>I got <em>The Economist<\/em>'s per-state Biden-victory probabilities from the <code>projected_win_prob<\/code> column in <code>\/output\/site_data\/\/state_averages_and_predictions_topline.csv<\/code> in <em>The Economist<\/em>'s zipfile, and <em>FiveThirtyEight<\/em>'s per-state Biden-victory probabilities from the <code>winstate_chal<\/code> column in <code>\/election-forecasts-2020\/presidential_state_toplines_2020.csv<\/code> in <em>FiveThirtyEight<\/em>'s zipfile.<\/p>\n<p>I'm only using the states' at-large results and ignoring the thing where Nebraska and Maine do some of their electoral votes by Congressional district.<\/p>\n<p>I'm using the convention of giving probabilities in terms of the event of interest being \"Biden\/Democrat wins\" rather than \"Trump\/Republican wins\", because that's what <em>The Economist<\/em> seems to be giving me, but I appreciate that the <em>FiveThirtyEight<\/em> spreadsheet has separate <code>winstate_inc<\/code> (incumbent), <code>winstate_chal<\/code> (challenger), and <code>winstate_3rd<\/code> (thirty-party) columns. (Although the <code>winstate_3rd<\/code> column is blank!!) Using \"incumbent wins\" as the event actually seems like a more natural Schelling-point convention to me?\u2014but it doesn't matter.<\/p>\n<p>I wrote a Python script to calculate the scores. The main function looks like this:<\/p>\n<pre><code>def score():\n    scores = {\"fivethirtyeight\": 0, \"economist\": 0, \"predictit\": 0}\n    swinglike_only_scores = {\n        \"fivethirtyeight\": 0,\n        \"economist\": 0,\n        \"predictit\": 0,\n    }\n    losses = {}\n\n    swinglikes = [sr for sr in state_results if is_swinglike(sr)]\n    print(\n        \"{} states ({}) are swinglike\".format(\n            len(swinglikes),\n            ','.join(sr.state for sr in swinglikes)\n        )\n    )\n\n    for state_result in state_results:\n        if state_result.actual is None:\n            continue\n\n        for predictor in scores.keys():\n\n            if state_result.actual:  # Biden win\n                probability = getattr(state_result, predictor)\n            else:\n                probability = 1 - getattr(state_result, predictor)\n\n            subscore = log2(probability)\n\n            scores[predictor] += subscore\n\n            if is_swinglike(state_result):\n                swinglike_only_scores[predictor] += subscore\n\n            losses[(predictor, state_result.state)] = subscore\n\n    return scores, swinglike_only_scores, losses<\/code><\/pre>\n<p><a href=\"https:\/\/gist.github.com\/zackmdavis\/623e15a3cdab66d3eaecf2a6f8b6169a\">(Full source code, including inline data.)<\/a><\/p>\n<p>Getting the numbers from both spreadsheets and the browser line graphs into my script involved a lot of copy-pasting\/Emacs-keyboard-macros\/typing, and I didn't exhaustively double-check everything, so <strong>it's possible I made some mistakes, but I hope that I didn't, because that would be embarrassing.<\/strong><\/p>\n<h3 id=\"results\">Results<\/h3>\n<p>Scoring over all the states, <em>The Economist<\/em> did the best, with a score of about \u22127.51 bits, followed by <em>FiveThirtyEight<\/em> at \u22129.24 bits, followed by PredictIt at \u221212.14.<\/p>\n<p>But I was worried that this methodology might privilege the statistical models over the markets, because the models (particularly <em>The Economist<\/em>, which was the most confident across the board) might be eking out more points by assigning very low\/high probabilities to \"safe\" states in ways that the PredictIt markets won't: intuitively, I suspect that the fact that someone is willing to scoop up Biden-takes-Alabama contracts at 2\u00a2 each may not be capturing the full power of what the market can do on harder questions. So I also calculated the scores on just the 12 \"swing-like\" states (Alaska, Arizona, Florida, Georgia, Iowa, Montana, North Carolina, New Hampshire, Nevada, Ohio, Pennsylvania, and Texas) where at least two of our three predictors gave a probability between 0.1 and 0.9.<\/p>\n<p>On just the \"swing-like\" states, the results are a lot more even, with <em>The Economist<\/em> at \u22127.36 bits, PredictIt at \u22127.40, and <em>FiveThirtyEight<\/em> at \u22127.89.<\/p>\n<p>The five largest predictive \"misses\" were <em>The Economist<\/em> and <em>FiveThirtyEight<\/em> on Florida (the models leaned Biden but the voters said Trump, giving the models log scores of \u22122.22 and \u22121.66, respectively), <em>The Economist<\/em> and <em>FiveThirtyEight<\/em> on North Carolina (same story for scores of \u22121.60 and \u22121.46), and PredictIt on Georgia (the market leaned Trump, but we think the voters are saying Biden for a score of \u22121.32).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was curious to see how various prognosticators\u2014specifically, FiveThirtyEight and The Economist's models, and the PredictIt prediction markets\u2014did on predicting the state-by-state (plus the District of Columbia) results of the recent U.S. presidential election.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[13],"tags":[50],"_links":{"self":[{"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/posts\/2359"}],"collection":[{"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/comments?post=2359"}],"version-history":[{"count":11,"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/posts\/2359\/revisions"}],"predecessor-version":[{"id":2371,"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/posts\/2359\/revisions\/2371"}],"wp:attachment":[{"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/media?parent=2359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/categories?post=2359"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/zackmdavis.net\/blog\/wp-json\/wp\/v2\/tags?post=2359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}