{ "cells": [ { "cell_type": "markdown", "id": "4abf3658-bcf9-4ada-a9b6-4fcd10660f20", "metadata": {}, "source": [ "### Project Assignment 3: Analysis, Modeling, and Simulation" ] }, { "cell_type": "markdown", "id": "e53cc23c-2b46-41e8-a178-65e5e8088ea5", "metadata": {}, "source": [ "# Covid-19, Population Migration, & Electoral Outcomes" ] }, { "cell_type": "markdown", "id": "1c34004f-ca8f-47a6-80f4-35d829f497a8", "metadata": {}, "source": [ "The Covid-19 pandemic reshaped population patterns across the United States, as millions of residents relocated from dense urban centers to suburban and rural communities. These demographic shifts have not only redefined the spatial distribution of people across the U.S., but may have also influenced the political landscape of the nation.\n", "\n", "In this analysis, I examine changes in population density at the county level from April 2020 to July 2024 using official estimates from the [U.S. Census Bureau](https://www.census.gov/data/datasets/time-series/demo/popest/2020s-counties-total.html). Through the use of choropleth maps and datatables, I visualize percent change in population densities at the county and state levels, highlighting regions that experienced the most significant growth or decline.\n", "\n", "To explore how these demographic movements may intersect with political realignment, I analyze county-level voting data from the 2020 and 2024 U.S. Presidential Elections, obtained from [MIT's Election Data and Science Lab](https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/VOQCHQ). By comparing shifts in voter preferences with changes in population density, this study aims to identify potential correlations between post-pandemic migration trends and partisan outcomes - particularly within key swing states that often determine the overall election result.\n", "\n", "Ultimately, this analysis seeks to provide a data-driven perspective on how population mobility in the wake of Covid-19 may have reshaped the political geography of the United States, revealing broader relationships between demographic change, density, and electoral behavior." ] }, { "cell_type": "markdown", "id": "4f1b45cc-b78b-4424-8585-0336d23d78bb", "metadata": {}, "source": [ "## Part 1: Covid-19 & Population Migration" ] }, { "cell_type": "markdown", "id": "e37dcbd2-9e8a-4ccb-a381-f7c3eb316e57", "metadata": {}, "source": [ "In this section, I examine how population density changed across the United States between 2020 and 2024, highlighting the demographic shifts brought on by the Covid-19 pandemic. At the county level, I focus on percent changes in population density within key swing states to identify regions that experienced the most significant growth or decline. At the broader scale, I analyze state-level density changes for all 50 states to understand how these swing states compare nationally and whether similar migration patterns emerged across the country." ] }, { "cell_type": "code", "execution_count": 1, "id": "bec0e15f-da0b-4a10-b886-3bded2ffe592", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import folium, requests\n", "from branca.element import Element" ] }, { "cell_type": "code", "execution_count": 2, "id": "bfadaebc-b45e-445d-abd9-85fb74b4f6e0", "metadata": {}, "outputs": [], "source": [ "# Load population data\n", "pop = pd.read_csv(\"2020_vs_2024_pop_density_by_county.csv\")\n", "\n", "# Clean columns\n", "pop = pop.rename(columns={\"County\":\"county_name\",\"2020\":\"pop_2020\",\"2024\":\"pop_2024\"})\n", "pop[\"county_name\"] = pop[\"county_name\"].str.strip().str.replace(\"^\\.\", \"\", regex=True)\n", "\n", "# Split into county + state\n", "pop[[\"county_part\",\"state_full\"]] = pop[\"county_name\"].str.split(\", \", n=1, expand=True)\n", "\n", "# Map state full names → abbreviations\n", "state_map = {\n", " 'Alabama':'AL','Alaska':'AK','Arizona':'AZ','Arkansas':'AR','California':'CA','Colorado':'CO',\n", " 'Connecticut':'CT','Delaware':'DE','District of Columbia':'DC','Florida':'FL','Georgia':'GA',\n", " 'Hawaii':'HI','Idaho':'ID','Illinois':'IL','Indiana':'IN','Iowa':'IA','Kansas':'KS','Kentucky':'KY',\n", " 'Louisiana':'LA','Maine':'ME','Maryland':'MD','Massachusetts':'MA','Michigan':'MI','Minnesota':'MN',\n", " 'Mississippi':'MS','Missouri':'MO','Montana':'MT','Nebraska':'NE','Nevada':'NV','New Hampshire':'NH',\n", " 'New Jersey':'NJ','New Mexico':'NM','New York':'NY','North Carolina':'NC','North Dakota':'ND',\n", " 'Ohio':'OH','Oklahoma':'OK','Oregon':'OR','Pennsylvania':'PA','Rhode Island':'RI',\n", " 'South Carolina':'SC','South Dakota':'SD','Tennessee':'TN','Texas':'TX','Utah':'UT','Vermont':'VT',\n", " 'Virginia':'VA','Washington':'WA','West Virginia':'WV','Wisconsin':'WI','Wyoming':'WY'\n", "}\n", "pop[\"state_abbr\"] = pop[\"state_full\"].map(state_map)\n", "\n", "# Clean county names\n", "pop[\"county_name_clean\"] = (\n", " pop[\"county_part\"]\n", " .str.replace(\" County\",\"\",regex=False)\n", " .str.replace(\" Parish\",\"\",regex=False)\n", " .str.replace(\" Borough\",\"\",regex=False)\n", " .str.replace(\" Census Area\",\"\",regex=False)\n", " .str.strip()\n", " + \", \" + pop[\"state_abbr\"]\n", ")\n", "\n", "# Convert pop columns to numeric\n", "pop[\"pop_2020\"] = pd.to_numeric(pop[\"pop_2020\"].replace(\",\",\"\",regex=True), errors=\"coerce\")\n", "pop[\"pop_2024\"] = pd.to_numeric(pop[\"pop_2024\"].replace(\",\",\"\",regex=True), errors=\"coerce\")\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "a1f8df17-8420-41a3-a5af-a9a76bcd4a6f", "metadata": {}, "outputs": [], "source": [ "# FIPS reference\n", "fips = pd.read_csv(\"https://raw.githubusercontent.com/kjhealy/fips-codes/master/state_and_county_fips_master.csv\")\n", "fips[\"county_name_clean\"] = (\n", " fips[\"name\"]\n", " .str.replace(\" County\",\"\",regex=False)\n", " .str.replace(\" Parish\",\"\",regex=False)\n", " .str.replace(\" Borough\",\"\",regex=False)\n", " .str.replace(\" Census Area\",\"\",regex=False)\n", " .str.strip()\n", " + \", \" + fips[\"state\"]\n", ")\n", "fips[\"county_fips\"] = fips[\"fips\"].astype(str).str.zfill(5)\n", "\n", "merged = pop.merge(fips[[\"county_name_clean\",\"county_fips\"]], on=\"county_name_clean\", how=\"left\")\n", "\n", "# Land area\n", "area = pd.read_csv(\"GEOINFO2023.GEOINFO-Data.csv\", dtype=str)\n", "area[\"county_fips\"] = area[\"GEO_ID\"].str[-5:]\n", "area[\"land_area_sqmi\"] = pd.to_numeric(area[\"AREALAND_SQMI\"], errors=\"coerce\")\n", "\n", "merged = merged.merge(area[[\"county_fips\",\"land_area_sqmi\"]], on=\"county_fips\", how=\"left\")\n", "\n", "# Compute true densities and % change\n", "merged[\"pop_density_2020_true\"] = merged[\"pop_2020\"] / merged[\"land_area_sqmi\"]\n", "merged[\"pop_density_2024_true\"] = merged[\"pop_2024\"] / merged[\"land_area_sqmi\"]\n", "merged[\"density_change_pct\"] = (\n", " (merged[\"pop_density_2024_true\"] - merged[\"pop_density_2020_true\"])\n", " / merged[\"pop_density_2020_true\"]\n", ") * 100\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "912057e2-bdb1-45f4-aaf0-6ce2b1d4eece", "metadata": {}, "outputs": [], "source": [ "elec = pd.read_csv(\"county_election_results_2020_2024.csv\")\n", "elec = elec[elec[\"office\"] == \"US PRESIDENT\"].copy()\n", "\n", "def rep_share(df, year):\n", " d = df[df[\"year\"] == year]\n", " pivot = d.pivot_table(index=\"county_fips\", columns=\"party\", values=\"candidatevotes\", aggfunc=\"sum\", fill_value=0).reset_index()\n", " pivot[\"rep_share_\" + str(year)] = pivot.get(\"REPUBLICAN\", 0) / (pivot.get(\"REPUBLICAN\", 0) + pivot.get(\"DEMOCRAT\", 0))\n", " pivot[\"county_fips\"] = pivot[\"county_fips\"].astype(str).str.strip().apply(lambda x: str(int(float(x))).zfill(5))\n", " return pivot[[\"county_fips\",\"rep_share_\" + str(year)]]\n", "\n", "rep2020 = rep_share(elec, 2020)\n", "rep2024 = rep_share(elec, 2024)\n", "\n", "vote = rep2020.merge(rep2024, on=\"county_fips\", how=\"inner\")\n", "vote[\"vote_shift_pct\"] = (vote[\"rep_share_2024\"] - vote[\"rep_share_2020\"]) * 100" ] }, { "cell_type": "code", "execution_count": 5, "id": "f971c4d1-e7a1-435b-a9f3-41a8399a32ce", "metadata": {}, "outputs": [], "source": [ "merged_all = merged.merge(vote, on=\"county_fips\", how=\"inner\")\n", "\n", "swing_states = ['AZ','GA','MI','NV','NC','PA','WI']\n", "merged_all = merged_all[merged_all[\"state_abbr\"].isin(swing_states)].copy()" ] }, { "cell_type": "code", "execution_count": 6, "id": "39863373-a7cb-4640-89fc-9061fca395bf", "metadata": {}, "outputs": [ { "data": { "text/html": [ "