{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import csv\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "from sklearn import (\n", " linear_model, metrics, neural_network, pipeline, model_selection\n", ")\n", "from sklearn.linear_model import LogisticRegression\n", "\n", "import statsmodels.api as sm\n", "import linearmodels\n", "\n", "import seaborn as sns\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction\n", "\n", "In this project, I'm further developing my ECON 490 thesis paper, in which I found that centrist Democratic candidates to the House of Representatives were much more likely, and very liberal candidates were much less likely, to win their elections than the baseline group. \n", "\n", "What I'm interested in now is not statistical significance, but seeing if I can generalize the models, test for overfitting, and get a good balance of variables to include to balance the various prediction metrics.\n", "\n", "It will be structured in the following manner:\n", "\n", "\n", "1. Introducing the dataset\n", " - Discussion of variables\n", " \n", "2. Creating the initial models\n", " - Linear probability model\n", " - Logit probability model\n", " - The \"Unfrazzled no-hassle lasso progressive regression digression\"\n", " - Testing accuracy\n", " - Testing precision\n", " - Testing recall\n", " \n", "3. Improving the models\n", " - Region\n", " - Race\n", " - Candidate\n", " - Urbanization\n", " - Testing accuracy\n", " - Picking the best model\n", "\n", "4. Counterfactual Predictions\n", " - What if all Democrats ran as centrists?\n", " - What if all Democrats ran as liberals?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Phase 1: Introducing the Dataset" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The final dataset created for my paper was `a_m_d_11`, standing for \"aligned model dataset version 11.\" It included data from multiple sources, ranging from an MIT Election Data + Science Lab dataset (acting as the core), to economic and demographic data from the US Census, to political leaning data from the Cook Partisan Voter Index, urbanization data, and others. It is printed below, with a list of columns. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
statespodistcandcand_votestot_votesleaningmedian_incomemean_incomeunemployment_1...DICREXRICDINRICDEXDEXRINDINREXDEXREXDINRINmedian_income_stdtwo_party_votetwo_party_vote_share
0ALABAMAAL1ROBERT KENNEDY JR.892262426171547952660856.4...0100000-0.8975182424540.368012
1ALABAMAAL2TABITHA ISNER869312262301646817639397.0...0100000-0.9639252258100.384974
2ALABAMAAL3MALLORY HAGAN839962319151646576629546.9...0100000-0.9780262317660.362417
\n", "

3 rows × 62 columns

\n", "
" ], "text/plain": [ " states po dist cand cand_votes tot_votes leaning \\\n", "0 ALABAMA AL 1 ROBERT KENNEDY JR. 89226 242617 15 \n", "1 ALABAMA AL 2 TABITHA ISNER 86931 226230 16 \n", "2 ALABAMA AL 3 MALLORY HAGAN 83996 231915 16 \n", "\n", " median_income mean_income unemployment_1 ... DICREX RICDIN RICDEX \\\n", "0 47952 66085 6.4 ... 0 1 0 \n", "1 46817 63939 7.0 ... 0 1 0 \n", "2 46576 62954 6.9 ... 0 1 0 \n", "\n", " DEXRIN DINREX DEXREX DINRIN median_income_std two_party_vote \\\n", "0 0 0 0 0 -0.897518 242454 \n", "1 0 0 0 0 -0.963925 225810 \n", "2 0 0 0 0 -0.978026 231766 \n", "\n", " two_party_vote_share \n", "0 0.368012 \n", "1 0.384974 \n", "2 0.362417 \n", "\n", "[3 rows x 62 columns]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a_m_d_11 = pd.read_csv(\"https://docs.google.com/spreadsheets/d/e/2PACX-1vRy5Ir4TrmGh77L131Xhkb22GIVWVF-4PF1eNjPOcOOpgtKyfyDcp4P2d8X4olqfifyJqo4SwTqSdH1/pub?gid=422096178&single=true&output=csv\")\n", "\n", "a_m_d_11.head(3)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "win = a_m_d_11[\"win\"]" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Index(['states', 'po', 'dist', 'cand', 'cand_votes', 'tot_votes', 'leaning',\n", " 'median_income', 'mean_income', 'unemployment_1', 'unemployment_2',\n", " 'white_pct', 'black_pct', 'native_pct', 'asian_pct', 'hispanic_pct',\n", " 'blue_dog', 'justice_dem', 'dem_vote_pct', 'win', 'south', 'north_east',\n", " 'mid_west', 'west', 'Incumbent', 'Open_Seat', 'urb_cluster',\n", " 'Very low density', 'Low density', 'Medium density\\t', 'High density',\n", " 'pure_rural', 'rural_suburban_mix', 'sparse_suburban', 'dense_suburban',\n", " 'urban_suburban_mix', 'pure_urban', 'high_ed_pct', 'state_dist', 'stcd',\n", " 'inc', 'pwin', 'fr', 'po1', 'po2', 'redist', 'dexp', 'rexp',\n", " 'total_spending', 'dem_spending_share', 'abnormal', 'DICRIN', 'DICREX',\n", " 'RICDIN', 'RICDEX', 'DEXRIN', 'DINREX', 'DEXREX', 'DINRIN',\n", " 'median_income_std', 'two_party_vote', 'two_party_vote_share'],\n", " dtype='object')" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a_m_d_11.columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, much of the dataset is vestigial and not used in the actual model. Some features and variables are worth explaining:\n", "\n", "- The data collection level is at the district and candidate level. Most variables describe the congressional district, but some such as `Incumbent` and the set of onces like `DICRIN`, `DICREX`, etc, describe whether the Democrat in question is an incumbent representative, and the political experience level of them and their Republican opponent. \n", "\n", "- `blue_dog` and `justice_dem` are my indicators of political ideology. This was the main point of interest for my paper - did candidates' political ideology being extreme hurt or help them in the general election? `blue_dog` equalled 1 if a candidate was a member of the Blue Dog Coalition (a group of centrist Democrats) or 0 if they didn't, while `justice_dem` equalled 1 if they were a member of the Justice Democrats (a very liberal political organization) and 0 if not. None were members of both; those who were members of neither were assumed to lie in between. \n", "\n", "Some evidence of this lies below in a plot created for my paper: \n", "\n", "Party and Caucus on DW-NOMINATE.png\n", "\n", "![Party and Caucus](https://i.imgur.com/hDqMzie.png)\n", "\n", "The main separation between the Democratic and Republican parties is the horizontal axis, showing how liberal or conservative (ie. left or right wing) candidates are on issues of economic redistribution. As can be seen, Blue Dogs are the right-most Democrats, while Justice Democrat are among the left-most. \n", "\n", "Four Justice Democrats are actually assigned moderate positions, but this is due to them voting against the Democratic Party, from the left but with Republicans, making them get assigned moderate spaces. [The people who created DW-NOMINATE, the scaling system used here, consider it a limitation with the model.](https://voteview.com/articles/ocasio_cortez)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `leaning` is taken from the Cook Partisan Voting Index, which takes each district's average vote between the Democratic and Republican presidential candidates over the past two elections and averages it out, to give approximate partisan leaning. It controls for how liberal or conservative a district is on average. Positive values indicate a leaning towards Republicans, negative values indicate towards Democrats. \n", "\n", "- `median_income_std` is household median income by district, standardized. \n", "\n", "- `incumbent` equals 1 if the Democrat is an incumbent representative and 0 if not. Later, I will use the `DICREX`, `DICRIN` etc. variables instead, which control for every combination of Democrat or Republican incumbent, and the experience level of either or both challengers (if an open seat). \n", "\n", "- I will also introduce variables covering `white_pct`, `black_pct`, and `hispanic_pct`, which indicate the racial breakdown of a district\n", "\n", "- `west`, `south`, and `mid_west` indicate the federal region of a district. `north_east` is omitted to prevent perfect multicollinearity.\n", "\n", "- Lastly, the `density` variables indicate how much of a district is composed of different levels of den" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Phase 2: Creating the Initial Models\n", "\n", "In this project, I'm further developing my ECON 490 thesis paper, in which I found that centrist Democratic candidates to the House of Representatives were much more likely, and very liberal candidates were much less likely, to win their elections than the baseline group. \n", "\n", "What I'm interested in now is not statistical significance, but seeing if I can generalize the models, test for overfitting, and get a good balance of variables to include to balance the various prediction metrics." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating Train/Test subsets of data, testing for overfitting" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Making X with urban rates values\n", "X = pd.DataFrame({\"blue_dog\": a_m_d_11[\"blue_dog\"],\n", " \"justice_dem\": a_m_d_11[\"justice_dem\"],\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"incumbent\": a_m_d_11[\"Incumbent\"]\n", "})\n", "\n", "X = sm.add_constant(X)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, win, test_size=0.50)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I will be running a linear probability model (an LPM, using OLS), a logistic probability model (logit), and a linear probability model using Lasso regression.\n", "\n", "Note: The division between training and testing datasets is random every time. Your results may vary slightly from what is printed in the cells, though I have made an effort to insert the variable where possible. " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "const 0.000000\n", "blue_dog 0.284747\n", "justice_dem -0.179746\n", "leaning -0.017555\n", "median_income_std 0.085229\n", "incumbent 0.297261\n", "dtype: float64" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lpm_train = linear_model.LinearRegression()\n", "lpm_train.fit(X_train, Y_train)\n", "lpm_coefs_1 = pd.Series(dict(zip(list(X_train), lpm_train.coef_)))\n", "lpm_coefs_1" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.77021401e-05, 1.23859734e+00, -3.08421434e-01, -4.41878976e-01,\n", " 7.28653367e-01, 9.68214737e-01])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "logit_train = linear_model.LogisticRegression(solver=\"lbfgs\")\n", "logit_train.fit(X_train, Y_train)\n", "logit_coefs_1 = pd.Series(dict(zip(list(X_train), logit_train.coef_.round(3))))\n", "\n", "\n", "def ltc_returner(x):\n", " for number in x:\n", " return number\n", "\n", "\n", "logit_coef = ltc_returner(logit_train.coef_)\n", "logit_coef" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Unfrazzled, No-Hassle, Lasso Progressive Regression Digression\n", "\n", "In the interest of making one very simple model to compare the more elaborate specifications against, I've run a linear probability model using Lasso regression, which shrinks effect sizes and in practice sets many coefficients equal to zero. I run it below as `lasso_model_1`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "const 0.000000\n", "blue_dog 0.000000\n", "justice_dem -0.000000\n", "leaning -0.020769\n", "median_income_std 0.000000\n", "incumbent 0.000000\n", "dtype: float64" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lasso_model_1 = linear_model.Lasso()\n", "lasso_model_1.fit(X_train, Y_train)\n", "\n", "lasso_coefs_1 = pd.Series(dict(zip(list(X_train), lasso_model_1.coef_)))\n", "lasso_coefs_1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparing Results" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lpmlogitlasso
const0.0000000.0000180.000000
blue_dog0.2847471.2385970.000000
justice_dem-0.179746-0.308421-0.000000
leaning-0.017555-0.441879-0.020769
median_income_std0.0852290.7286530.000000
incumbent0.2972610.9682150.000000
\n", "
" ], "text/plain": [ " lpm logit lasso\n", "const 0.000000 0.000018 0.000000\n", "blue_dog 0.284747 1.238597 0.000000\n", "justice_dem -0.179746 -0.308421 -0.000000\n", "leaning -0.017555 -0.441879 -0.020769\n", "median_income_std 0.085229 0.728653 0.000000\n", "incumbent 0.297261 0.968215 0.000000" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "coefs = [\"const\", \"blue_dog\", \"justice_dem\", \"leaning\", \"median_income_std\", \"incumbent\"]\n", "\n", "coef_results = pd.DataFrame({#\"coefs\": coefs,\n", " \"lpm\": lpm_coefs_1,\n", " \"logit\": logit_coef,\n", " #\"logit\": [-1.0000e-04, 1.7362e+00, -3.2600e-01, -4.8070e-01, 6.8980e-01, 8.0640e-01],\n", " \"lasso\": lasso_coefs_1})\n", "coef_results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Results thus far?\n", "\n", "1. LPM and Logit models do show coefficient results on all but `const`\n", "2. BUT: Lasso shows only `leaning` as having any coefficient\n", "\n", "### How do their accuracies look?" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LPM training dataset accuracy is: 0.7120267695136987\n", "LPM testing dataset accuracy is: 0.6805910921563088\n" ] } ], "source": [ "lpm_train_accuracy = lpm_train.score(X_train, Y_train)\n", "lpm_test_accuracy = lpm_train.score(X_test, Y_test)\n", "\n", "print(f\"LPM training dataset accuracy is: {lpm_train_accuracy}\")\n", "print(f\"LPM testing dataset accuracy is: {lpm_test_accuracy}\")" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Logit training dataset accuracy is: 0.9489795918367347\n", "Logit testing dataset accuracy is: 0.9693877551020408\n" ] } ], "source": [ "logit_train_accuracy = logit_train.score(X_train, Y_train)\n", "logit_test_accuracy = logit_train.score(X_test, Y_test)\n", "\n", "print(f\"Logit training dataset accuracy is: {logit_train_accuracy}\")\n", "print(f\"Logit testing dataset accuracy is: {logit_test_accuracy}\")" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Lasso training dataset accuracy is: 0.6069187590068059\n", "Lasso testing dataset accuracy is: 0.5832168022216864\n" ] } ], "source": [ "lasso_train_accuracy = lasso_model_1.score(X_train, Y_train)\n", "lasso_test_acuracy = lasso_model_1.score(X_test, Y_test)\n", "\n", "\n", "print(f\"Lasso training dataset accuracy is: {lasso_train_accuracy}\")\n", "print(f\"Lasso testing dataset accuracy is: {lasso_test_acuracy}\")" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
LPMLogitLasso
Type
Training0.6670.9440.555
Testing0.7250.9690.636
\n", "
" ], "text/plain": [ " LPM Logit Lasso\n", "Type \n", "Training 0.667 0.944 0.555\n", "Testing 0.725 0.969 0.636" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "accuracy_df = pd.DataFrame({\"Type\": [\"Training\", \"Testing\"],\n", " \"LPM\": [0.667, 0.725],\n", " \"Logit\": [0.944, 0.969],\n", " \"Lasso\": [0.555, 0.636]})\n", "accuracy_df = accuracy_df.set_index(\"Type\")\n", "accuracy_df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Question: What is the accuracy of just guessing the most likely outcome for both datasets?\n", "\n", "Because this is a binary dependent variable, it's worth asking what your baseline accuracy is if you simply guess the more common outcome variable every single time." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Average value in the training dataset is: 0.5051020408163265\n", "Average value in the testing dataset is: 0.5051020408163265\n" ] } ], "source": [ "training_mean = Y_train.mean()\n", "testing_mean = Y_test.mean()\n", "\n", "print(f\"Average value in the training dataset is: {training_mean}\")\n", "print(f\"Average value in the testing dataset is: {testing_mean}\")" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# Set up so that if modal_training_value >= 0.5, go with it, if not, go with 1 - modal_training_value\n", "# likewise for modal_testing_value\n", "\n", "modal_training_value = Y_train.mean()\n", "modal_testing_value = Y_test.mean()\n", "\n", "\n", "if training_mean < 0.5:\n", " modal_training_value = 1 - modal_training_value\n", " \n", "if modal_testing_value < 0.5:\n", " modal_testing_value = 1 - modal_testing_value" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example, if 1 makes up 49.5% of the training results, guessing 0 every time will give you an accuracy of (1 - 0.495) = 0.505. Because we want to improve on just guessing the most common result every time, we need to get at least this accuracy value for a model to be any use. \n", "\n", "I'll plot the \"guess the same value every time\" accuracy levels and those of the models, and see what we get." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "Types = [\"LPM Train\", \"LPM Test\", \n", " \"Logit Train\", \"Logit Test\",\n", " \"Lasso Train\", \"Lasso Test\"]\n", "\n", "Accuracy = [lpm_train_accuracy, lpm_test_accuracy, logit_train_accuracy, logit_test_accuracy, lasso_train_accuracy, lasso_test_acuracy]" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "\n", "plt.stem(Accuracy)\n", "plt.xticks(ticks = range(len(Types)), \n", " labels = [\"LPM Train\", \"LPM Test\", \"Logit Train\", \"Logit Test\", \"Lasso Train\", \"Lasso Test\"], \n", " )\n", "plt.ylabel(\"Accuracy Rating\")\n", "plt.xlabel(\"Models\")\n", "plt.title(\"Accuracy Ratings of LPM, Logit, and Lasso models on Training, Testing Datasets\")\n", "plt.ylim([0.4, 1])\n", "\n", "# Green Line is accuracy of guessing most common result (0) in Training dataset\n", "plt.axhline(y=modal_training_value, color='g', linestyle='-')\n", "\n", "# Yellow line is accuracy of guessing most common result (1) in Testing dataset\n", "plt.axhline(y=modal_testing_value, color='y', linestyle='-')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Green Line is accuracy of guessing most common result in the Training dataset\n", "#### Yellow line is accuracy of guessing most common result in the Testing dataset\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A note on false positives versus false negatives\n", "\n", "Due to the nature of this experiment, we're wanting to predict if candidates are elected or not. A bit more than half were: `win.mean()` equals ~0.505. The breakdowns for the testing and training datasets will vary slightly, however. \n", "\n", "- A False Positive is when the model predicts 1 but the result is 0; ie. predicting a win but the candidate lost. \n", "- A False Negative is when the model predicts 0 but the result is 1; ie. predicting a loss but the candidate won.\n", "\n", "In my opinion, we aren't particularly concerned with one of these more than the other. We aren't trying to catch a small number of disease cases out of a large number of healthy subjects (in which case a False Negative could kill someone!) or, say, deciding where to invest a lot of money to excavate a valuable resource (where a false positive causes a large amount of waste). \n", "\n", "Because of this, I think a good way to approach this is to make as accurate a model as we can, without overfitting. As said in the Classification lecture (\\# 22), when testing accuracy is equivalent or greater to training accuracy, we may be underfitting, and can use a more powerful model. \n", "\n", "Because of this, the next thing we do will be developing the `LPM` and `Logit` models, adding some more variables to increase accuracy without overfitting. Our \"unfrazzled no-hassle lasso progressive regression digression\" was fun, but `Lasso` performed little better than just guessing the most common result. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Precision and Recall\n", "\n", "While I think Accuracy should be the main focus, there's no harm in seeing if there's any notable trend in other classification metrics.\n", "\n", "Precision: Number of true positive predictions divided by the total number of positive predictions. In other words, of the times the model guesses positive, how often was it correct?\n", "\n", "Recall: Number of true positives divided by number of actual positives. In other words, of all positive result cases, how many did we predict?\n", "\n", "\n", "I will assign \"Positive\" predictions as those with predicted probability equal to or greater than 0.5, and \"Negative\" predictions as those with predicted probability less than 0.5." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "pred_round = []\n", "\n", "\n", "def round_series(x):\n", " X_round = []\n", " for prediction in x:\n", " if float(prediction) < 0.5:\n", " X_round.append(0)\n", " elif float(prediction) >= 0.5:\n", " X_round.append(1)\n", " return X_round" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "lpm_train_round = []\n", "lpm_train_round = round_series(lpm_train.predict(X_train))\n", "lpm_test_round = round_series(lpm_train.predict(X_test))\n", "\n", "\n", "logit_train_round = []\n", "logit_train_round = round_series(logit_train.predict(X_train))\n", "logit_test_round = round_series(logit_train.predict(X_test))\n", "\n", "lasso_train_round = []\n", "lasso_train_round = round_series(lasso_model_1.predict(X_train))\n", "lasso_test_round = round_series(lasso_model_1.predict(X_test))" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Loss 0.89 0.96 0.93 97\n", " Win 0.96 0.89 0.92 99\n", "\n", " accuracy 0.92 196\n", " macro avg 0.93 0.92 0.92 196\n", "weighted avg 0.93 0.92 0.92 196\n", "\n" ] } ], "source": [ "report_lpm = metrics.classification_report(\n", " Y_train, lpm_train_round,\n", " target_names = [\"Loss\", \"Win\"])\n", "\n", "print(report_lpm)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Loss 0.94 0.96 0.95 97\n", " Win 0.96 0.94 0.95 99\n", "\n", " accuracy 0.95 196\n", " macro avg 0.95 0.95 0.95 196\n", "weighted avg 0.95 0.95 0.95 196\n", "\n" ] } ], "source": [ "report_log = metrics.classification_report(\n", " Y_train, logit_train_round,\n", " target_names = [\"Loss\", \"Win\"])\n", "\n", "print(report_log)\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Loss 0.86 0.98 0.92 97\n", " Win 0.98 0.85 0.91 99\n", "\n", " accuracy 0.91 196\n", " macro avg 0.92 0.91 0.91 196\n", "weighted avg 0.92 0.91 0.91 196\n", "\n" ] } ], "source": [ "report_lasso = metrics.classification_report(\n", " Y_train, lasso_train_round,\n", " target_names = [\"Loss\", \"Win\"])\n", "\n", "print(report_lasso)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### So, when we round our predictions, `lpm` and `lasso` both do a lot better. \n", "\n", "However, `logit` still gets the highest precision and recall values; therefore also the greateset f1-score. \n", "\n", "Due to the poor showings of the `lasso` and `lpm` models in un-rounded accuracy tests, I'm going to discard them for now and move forward with just the `logit` model. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conclusions from Phase 2:\n", "\n", "- Logit model is far more accurate than the LPM, which is more accurate than the Lasso model\n", "\n", "- All three have training accuracy values slightly lower than their testing dataset accuracy levels: this implies they could be slightly underfitted.\n", "\n", "- When un-rounded, the Lasso model is barely any more accurate than just guessing the most common outcome variable!\n", "\n", "- Rounding predictions to 0 or 1 improves results for `lpm` and `lasso`, but `logit` is still reliably the best." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Phase 3: Improving on `logit` performance\n", "\n", "\n", "In my project, I used a more extensive specification for my models, also counting a variety of democraphic controls. Including all of these would lead to problems with a singular matrix when splitting into testing and training datasets - while my sample includes nearly all House of Representatives elections in the 2018 Midterms, splitting it up makes the sample size too small. It also relies on a large number of dummy variables, which can become linearly dependent easily. \n", "\n", "So, I'm going to take the above specification, and add one set of controls at a time. These are:\n", "\n", "- Federal Region\n", "- Urbanization\n", "- Racial composition\n", "- An expanded set of candidate traits\n", "\n", "We're going to see how the additions impact prediction quality. I want to increase Accuracy on both the testing and training datasets, but not have testing accuracy significantly exceed training accuracy. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## First setting up the dataframes, splitting into training/testing sets" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "X_reg = pd.DataFrame({\"blue_dog\": a_m_d_11[\"blue_dog\"],\n", " \"justice_dem\": a_m_d_11[\"justice_dem\"],\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"incumbent\": a_m_d_11[\"Incumbent\"],\n", " \"west\": a_m_d_11[\"west\"],\n", " \"south\": a_m_d_11[\"south\"],\n", " \"mid_west\": a_m_d_11[\"mid_west\"]\n", "})\n", "\n", "X_reg = sm.add_constant(X_reg)\n", "\n", "X_race = pd.DataFrame({\"blue_dog\": a_m_d_11[\"blue_dog\"],\n", " \"justice_dem\": a_m_d_11[\"justice_dem\"],\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"incumbent\": a_m_d_11[\"Incumbent\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"white_pct\": a_m_d_11[\"white_pct\"],\n", " \"black_pct\": a_m_d_11[\"black_pct\"],\n", " \"hispanic_pct\": a_m_d_11[\"hispanic_pct\"]\n", "})\n", "\n", "X_race = sm.add_constant(X_race)\n", "\n", "X_inc = pd.DataFrame({\"blue_dog\": a_m_d_11[\"blue_dog\"],\n", " \"justice_dem\": a_m_d_11[\"justice_dem\"],\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"DICRIN\": a_m_d_11[\"DICRIN\"],\n", " \"DICREX\": a_m_d_11[\"DICREX\"],\n", " \"RICDIN\": a_m_d_11[\"RICDIN\"],\n", " \"RICDEX\": a_m_d_11[\"RICDEX\"],\n", " \"DEXRIN\": a_m_d_11[\"DEXRIN\"],\n", " \"DINREX\": a_m_d_11[\"DINREX\"],\n", " \"DEXREX\": a_m_d_11[\"DEXREX\"]\n", "})\n", "\n", "X_inc = sm.add_constant(X_inc)\n", "\n", "\n", "X_urb_rates = pd.DataFrame({\"blue_dog\": a_m_d_11[\"blue_dog\"],\n", " \"justice_dem\": a_m_d_11[\"justice_dem\"],\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"incumbent\": a_m_d_11[\"Incumbent\"],\n", " \"very_low_urb\": a_m_d_11[\"Very low density\"],\n", " \"low_urb\": a_m_d_11[\"Low density\"],\n", " \"medium_urb\": a_m_d_11[\"Medium density\\t\"],\n", "})\n", "\n", "X_urb_rates = sm.add_constant(X_urb_rates)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "X_reg_train, X_reg_test, Y_reg_train, Y_reg_test = model_selection.train_test_split(X_reg, win, test_size=0.50)\n", "X_race_train, X_race_test, Y_race_train, Y_race_test = model_selection.train_test_split(X_race, win, test_size=0.50)\n", "X_inc_train, X_inc_test, Y_inc_train, Y_inc_test = model_selection.train_test_split(X_inc, win, test_size=0.50)\n", "X_urb_train, X_urb_test, Y_urb_train, Y_urb_test = model_selection.train_test_split(X_urb_rates, win, test_size=0.50)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Next, running each model" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
constblue_dogjustice_demleaningmedian_income_stdincumbentwestsouthmid_west
3371.00033-0.6573410010
151.00017-1.3054390010
1951.00021-1.0042960010
\n", "
" ], "text/plain": [ " const blue_dog justice_dem leaning median_income_std incumbent \\\n", "337 1.0 0 0 33 -0.657341 0 \n", "15 1.0 0 0 17 -1.305439 0 \n", "195 1.0 0 0 21 -1.004296 0 \n", "\n", " west south mid_west \n", "337 0 1 0 \n", "15 0 1 0 \n", "195 0 1 0 " ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_reg_train.head(3)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.14732251e-05, 2.17198287e+00, -6.22078636e-01, -4.64422689e-01,\n", " 7.31777926e-01, 4.32037303e-01, 5.22654345e-01, -2.51564305e-01,\n", " -5.52370326e-02])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "logit_reg = linear_model.LogisticRegression(solver=\"lbfgs\", max_iter = 10000)\n", "logit_reg.fit(X_reg_train, Y_reg_train)\n", "logit_reg_coefs_1 = pd.Series(dict(zip(list(X_reg_train), logit_reg.coef_.round(3))))\n", "\n", "logit_reg_coef = ltc_returner(logit_reg.coef_)\n", "logit_reg_coef" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-2.23021598e-04, 1.66864934e+00, -1.91795510e-02, -7.36959710e-01,\n", " 1.21627510e-01, 8.73802471e-02, -2.08008741e-01, -3.18615176e-01,\n", " -6.70188931e-02])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "logit_race = linear_model.LogisticRegression(solver=\"lbfgs\", max_iter = 10000)\n", "logit_race.fit(X_race_train, Y_race_train)\n", "logit_race_coefs_1 = pd.Series(dict(zip(list(X_race_train), logit_race.coef_.round(3))))\n", "\n", "logit_race_coef = ltc_returner(logit_race.coef_)\n", "logit_race_coef" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-1.25785253e-05, 1.62711114e+00, -4.82173774e-01, -5.36744134e-01,\n", " 1.11570439e+00, 4.15048688e-01, 1.91961162e-02, -9.64318399e-01,\n", " 9.19636266e-02, 1.29191678e-01, 2.15100091e-01, -9.18830610e-03])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "logit_inc = linear_model.LogisticRegression(solver=\"lbfgs\", max_iter = 10000)\n", "logit_inc.fit(X_inc_train, Y_inc_train)\n", "logit_inc_coefs_1 = pd.Series(dict(zip(list(X_inc_train), logit_inc.coef_.round(3))))\n", "\n", "logit_inc_coef = ltc_returner(logit_inc.coef_)\n", "logit_inc_coef" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 4.08474405e-04, 2.06151737e+00, -6.03152616e-01, -3.83338636e-01,\n", " 7.36228519e-01, 7.10858951e-01, 9.76413930e-02, -5.84026819e-01,\n", " -3.70695454e-02])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "logit_urb = linear_model.LogisticRegression(solver=\"lbfgs\", max_iter = 10000)\n", "logit_urb.fit(X_urb_train, Y_urb_train)\n", "logit_urb_coefs_1 = pd.Series(dict(zip(list(X_urb_train), logit_urb.coef_.round(3))))\n", "\n", "logit_urb_coef = ltc_returner(logit_urb.coef_)\n", "logit_urb_coef" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## With models fitted, I find their accuracies." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Logit Region training dataset accuracy is: 0.9693877551020408\n", "Logit Region testing dataset accuracy is: 0.9489795918367347\n" ] } ], "source": [ "reg_train_accuracy = logit_reg.score(X_reg_train, Y_reg_train)\n", "reg_test_accuracy = logit_reg.score(X_reg_test, Y_reg_test)\n", "\n", "print(f\"Logit Region training dataset accuracy is: {reg_train_accuracy}\")\n", "print(f\"Logit Region testing dataset accuracy is: {reg_test_accuracy}\")" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Logit Race training dataset accuracy is: 0.9591836734693877\n", "Logit Race testing dataset accuracy is: 0.9489795918367347\n" ] } ], "source": [ "race_train_accuracy = logit_race.score(X_race_train, Y_race_train)\n", "race_test_accuracy = logit_race.score(X_race_test, Y_race_test)\n", "\n", "print(f\"Logit Race training dataset accuracy is: {race_train_accuracy}\")\n", "print(f\"Logit Race testing dataset accuracy is: {race_test_accuracy}\")" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Logit Incumbent training dataset accuracy is: 0.9693877551020408\n", "Logit Incumbent testing dataset accuracy is: 0.9591836734693877\n" ] } ], "source": [ "inc_train_accuracy = logit_inc.score(X_inc_train, Y_inc_train)\n", "inc_test_accuracy = logit_inc.score(X_inc_test, Y_inc_test)\n", "\n", "print(f\"Logit Incumbent training dataset accuracy is: {inc_train_accuracy}\")\n", "print(f\"Logit Incumbent testing dataset accuracy is: {inc_test_accuracy}\")" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Logit Urban training dataset accuracy is: 0.9336734693877551\n", "Logit Urban testing dataset accuracy is: 0.9744897959183674\n" ] } ], "source": [ "urb_train_accuracy = logit_urb.score(X_urb_train, Y_urb_train)\n", "urb_test_accuracy = logit_urb.score(X_urb_test, Y_urb_test)\n", "\n", "print(f\"Logit Urban training dataset accuracy is: {urb_train_accuracy}\")\n", "print(f\"Logit Urban testing dataset accuracy is: {urb_test_accuracy}\")" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "Types = [\"Region Tr.\", \"Region Test\", \n", " \"Race Tr.\", \"Race Test\",\n", " \"Candidate Tr.\", \"Candidate Test\",\n", " \"Urbanization Tr.\", \"Urbanization Test\"]\n", "\n", "Accuracy = [reg_train_accuracy, reg_test_accuracy, race_train_accuracy, race_test_accuracy, \n", " inc_train_accuracy, inc_test_accuracy, urb_train_accuracy, urb_test_accuracy]" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Text(0.5, 1.0, 'Accuracy Ratings of Regional, Race Proportion, Candidate Characteristics, and Urbanization \\n models on Training, Testing Datasets')" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.stem(Accuracy)\n", "plt.xticks(ticks = range(len(Types)), \n", " labels = Types, rotation = 45)\n", "\n", "plt.ylim([0.9, 1])\n", "plt.ylabel(\"Accuracy Rating\")\n", "plt.xlabel(\"Models\")\n", "plt.title(\"Accuracy Ratings of Regional, Race Proportion, Candidate Characteristics, and Urbanization \\n models on Training, Testing Datasets\")\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the axis is from 0.9 to 1: the accuracy ratings are all closer than they appear. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Results will not impress: accuracy values are likely slightly higher on average than the basic logit model, but not much, and many will likely have higher accuracy values in the training than testing case. This implies the extra variables are just causing the model to overfit to the variance in the training data. \n", "\n", "Most likely, there's just not much more accuracy to gain from adding more variables, as the variables already included in the basic logit function already have high predictive power. \n", "\n", "So, I'm going to just stick with the basic logit model from this point onwards." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Part Four: Counterfactuals\n", "\n", "\n", "A big motivator for the paper was seeing if there was a causal effect of candidate ideology (ie. if a Democratic candidate was very moderate and centrist, or very liberal, or in between) on election win probability. In my paper, I found large and significant coefficients on the `Blue_Dog` and `Justice_Democrat` variables (signifying if a candidate was a centrist or a liberal, respectively), and of comparable size to other results found in the literature. I will assume this change in win probability was causal.\n", "\n", "So, now I want to play around with it, and see what differences we might expect in the US House of Representatives if more candidate had run as liberals or centrists. " ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The number of Democrats who win in the real election was: 198\n" ] } ], "source": [ "print(\"The number of Democrats who win in the real election was:\", win.sum())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Prediction: If all Democrats ran as Blue Dogs or Justice Democrats\n", "\n", "First, I will take the full dataset for `X`, set all `blue_dog` variables to 1, and set all `justice_dem` variables to 0. This implies the whole Democratic Party running as centrists.\n", "\n", "In order for `predict` to work, there have to be some rows with different values in each colum. I set row 390's Blue Dog value to 0, and row 391's Blue Dog value to 0 and Justice Democrat value to 1, so that we don't have perfect multicollearity. Both of these were in fairly Republican-leaning districts, so I wouldn't expect either to be winnable. " ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "X_BD = pd.DataFrame({\"blue_dog\": 1,\n", " \"justice_dem\": 0,\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"incumbent\": a_m_d_11[\"Incumbent\"]\n", "})\n", "\n", "X_BD.at[391, \"blue_dog\"] = 0\n", "X_BD.at[390, \"blue_dog\"] = 0\n", "X_BD.at[390, \"justice_dem\"] = 1\n", "\n", "X_BD = sm.add_constant(X_BD)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
constblue_dogjustice_demleaningmedian_income_stdincumbent
3871.010130.4102610
3881.0108-0.2244960
3891.0108-0.4842150
3901.0017-0.1828970
3911.00025-0.0599120
\n", "
" ], "text/plain": [ " const blue_dog justice_dem leaning median_income_std incumbent\n", "387 1.0 1 0 13 0.410261 0\n", "388 1.0 1 0 8 -0.224496 0\n", "389 1.0 1 0 8 -0.484215 0\n", "390 1.0 0 1 7 -0.182897 0\n", "391 1.0 0 0 25 -0.059912 0" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_BD.tail()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "logit_bd_predictions = logit_train.predict(X_BD)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "logit_bd_predictions = logit_train.predict(X_BD)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "pred_bd_wins = logit_bd_predictions.mean() * 392" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "dem_wins = win.mean()*392" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, for the liberal case, I just do the inverse of the above, and set all candidates as Justice Democrats. The same candidates (index values 390 and 391) are changed again to make the prediction work." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "X_JD = pd.DataFrame({\"blue_dog\": 0,\n", " \"justice_dem\": 1,\n", " \"leaning\": a_m_d_11[\"leaning\"],\n", " \"median_income_std\": a_m_d_11[\"median_income_std\"],\n", " \"incumbent\": a_m_d_11[\"Incumbent\"]\n", "})\n", "\n", "X_JD.at[391, \"blue_dog\"] = 1\n", "X_JD.at[390, \"justice_dem\"] = 0\n", "X_JD.at[391, \"justice_dem\"] = 0\n", "\n", "X_JD = sm.add_constant(X_JD)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
constblue_dogjustice_demleaningmedian_income_stdincumbent
3871.001130.4102610
3881.0018-0.2244960
3891.0018-0.4842150
3901.0007-0.1828970
3911.01025-0.0599120
\n", "
" ], "text/plain": [ " const blue_dog justice_dem leaning median_income_std incumbent\n", "387 1.0 0 1 13 0.410261 0\n", "388 1.0 0 1 8 -0.224496 0\n", "389 1.0 0 1 8 -0.484215 0\n", "390 1.0 0 0 7 -0.182897 0\n", "391 1.0 1 0 25 -0.059912 0" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X_JD.tail()" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "logit_jd_predictions = logit_train.predict(X_JD)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "pred_jd_wins = logit_jd_predictions.mean() * 392" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The number of winning Democrats in the sample is: 198\n", "The number of predicted Democrat wins, if all ran as centrists, is 209.0\n", "The number of predicted Democrat wins, if all ran as liberals, is 182.0\n" ] } ], "source": [ "print(f\"The number of winning Democrats in the sample is: {round(dem_wins)}\")\n", "print(f\"The number of predicted Democrat wins, if all ran as centrists, is {pred_bd_wins}\")\n", "print(f\"The number of predicted Democrat wins, if all ran as liberals, is {pred_jd_wins}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The real-life outcome of the election was the Democrats winning 235 of 435 seats. The sample was reduced to 392 because of 43 seats with abnormal elections - candidates running unopposed, against a weak independent or third party, or with many candidates running under a [Jungle Primary ruleset](https://en.wikipedia.org/wiki/Nonpartisan_blanket_primary). These were removed; most had lopsided results and would likely not change.\n", "\n", "\n", "You can observe how many seats the Demcrats in the sample are expected to win. I'd expect that the centrist case increases their hold on the House, but doesn't reach a supermajority, while the liberal case weakens their hold but won't result in enough losses to lose them the chamber. Simply subtract 198 from the number of Centrist/Liberal case wins to see what the difference will be.\n", "\n", "Due to the heavily nationalized media environment, candidates often struggle to distinguish themselves from their party. I would expect that the whole Democratic Party moving towards the center to have a much larger effect due to this. The predictions here essentially take the effect for a candidate on the margin, if he changed from a normal Democrat to a centrist, and apply it to everyone. The party changing how it's perceived by voters would cause an additional increase in electability.\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }