{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "590963d6",
   "metadata": {},
   "source": [
    "# Geo-Memo Follow-Ups: Which Covariates Predict Regular Transit?\n",
    "\n",
    "### Head-to-head Random Forests for car access, employment, and ride-share\n",
    "\n",
    "**Course:** PSYCH 755 · University of Wisconsin–Madison  \n",
    "**Project:** CA persona / PRCA research framework  \n",
    "\n",
    "This notebook tests the candidate predictors named in [`memos/geo_predicts_transit.md`](../memos/geo_predicts_transit.md):\n",
    "\n",
    "1. Car license / access (`Q20` / `Q21`)\n",
    "2. Employment status\n",
    "3. Ride-share frequency (`Q28` / `Q29`)\n",
    "4. Joint mobility bundle (all of the above)\n",
    "\n",
    "Benchmarks from companion memos: **geo AUC ≈ 0.551**, **CA AUC ≈ 0.590**, chance = 0.500.\n",
    "\n",
    "Companion memo: [`memos/transit_covariate_followups.md`](../memos/transit_covariate_followups.md)  \n",
    "CLI: `ca-personas covariate-transit-rf --join inner --seed 42`\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d737b1c",
   "metadata": {},
   "source": [
    "## 1. Setup\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "6fb9eed7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-25T15:40:50.204144Z",
     "iopub.status.busy": "2026-07-25T15:40:50.204011Z",
     "iopub.status.idle": "2026-07-25T15:40:51.208836Z",
     "shell.execute_reply": "2026-07-25T15:40:51.207900Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data source: ../sibling_data File A/B/C\n",
      "Prolific: ['/tmp/sibling_data/PRCAProlificExport_FileA.csv', '/tmp/sibling_data/PRCAProlificExport_FileB.csv']\n",
      "Qualtrics: /tmp/sibling_data/PRCAQualtricsExport_FileC.csv\n"
     ]
    }
   ],
   "source": [
    "from __future__ import annotations\n",
    "\n",
    "from pathlib import Path\n",
    "import sys\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "ROOT = Path.cwd().resolve()\n",
    "if ROOT.name == \"notebooks\":\n",
    "    ROOT = ROOT.parent\n",
    "if str(ROOT / \"src\") not in sys.path:\n",
    "    sys.path.insert(0, str(ROOT / \"src\"))\n",
    "\n",
    "from ca_personas.load import load_full_cohort\n",
    "from ca_personas.paths import default_prolific_paths, default_qualtrics_path, sibling_data_available\n",
    "from ca_personas.transit_covariate_rf import (\n",
    "    FEATURE_SPECS,\n",
    "    plot_comparison_memo_figure,\n",
    "    plot_family_memo_figure,\n",
    "    run_all_followup_analyses,\n",
    "    run_feature_family_analysis,\n",
    "    save_feature_family_artifacts,\n",
    "    save_followup_bundle,\n",
    ")\n",
    "\n",
    "plt.rcParams.update({\"axes.grid\": True, \"grid.alpha\": 0.25})\n",
    "plt.rcParams[\"figure.dpi\"] = 120\n",
    "\n",
    "if sibling_data_available():\n",
    "    PROLIFIC = default_prolific_paths()\n",
    "    QUALTRICS = default_qualtrics_path()\n",
    "    source = \"../sibling_data File A/B/C\"\n",
    "else:\n",
    "    staged = Path(\"/tmp/sibling_data\")\n",
    "    PROLIFIC = [\n",
    "        staged / \"PRCAProlificExport_FileA.csv\",\n",
    "        staged / \"PRCAProlificExport_FileB.csv\",\n",
    "    ]\n",
    "    QUALTRICS = staged / \"PRCAQualtricsExport_FileC.csv\"\n",
    "    source = \"/tmp/sibling_data File A/B/C\"\n",
    "\n",
    "SEED = 42\n",
    "N_SPLITS = 5\n",
    "N_PERM = 30\n",
    "print(\"Data source:\", source)\n",
    "print(\"Prolific:\", [str(p) for p in PROLIFIC])\n",
    "print(\"Qualtrics:\", QUALTRICS)\n",
    "\n",
    "import json\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7417320f",
   "metadata": {},
   "source": [
    "## 2. Load cohort & run all families\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a902bcc1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-25T15:40:51.210592Z",
     "iopub.status.busy": "2026-07-25T15:40:51.210387Z",
     "iopub.status.idle": "2026-07-25T15:41:16.716697Z",
     "shell.execute_reply": "2026-07-25T15:41:16.715939Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Matched analytic rows: 241\n",
      "{'n_prolific_raw': 262, 'n_prolific_unique': 262, 'n_qualtrics_raw': 273, 'n_qualtrics_with_pid': 255, 'n_qualtrics_complete_ca': 260, 'n_joined': 252, 'n_matched_both': 252, 'n_analytic': 241, 'n_dropped_missing_pid': 0, 'n_dropped_incomplete_ca': 11, 'n_dropped_unscorable_ca': 0, 'n_dropped_unjoined': 31, 'n_prolific_only': 10, 'n_qualtrics_only': 21, 'n_qualtrics_missing_pid': 18, 'waves': {'B': 153, 'A': 99}, 'notes': ['Normalized 19 DATA_EXPIRED Student status values to missing.', 'Full Prolific waves (File A/B) omit Ethnicity / Nationality / Language; demos tier uses Age, Sex, Country of residence, and Student status.', 'Analytic sample = Prolific∩Qualtrics with complete scorable PRCA group + interpersonal items.', 'Merge coverage (pre-CA filter): 252 matched Prolific∩Qualtrics; 21 Qualtrics-only (incl. 18 blank Q0 test rows; disregard); 10 Prolific-only (disregard).']}\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>spec_key</th>\n",
       "      <th>label</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>prevalence</th>\n",
       "      <th>roc_auc</th>\n",
       "      <th>average_precision</th>\n",
       "      <th>balanced_accuracy</th>\n",
       "      <th>f1</th>\n",
       "      <th>brier</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>q28_days</td>\n",
       "      <td>Ride-share days (Q28)</td>\n",
       "      <td>241.0</td>\n",
       "      <td>101.0</td>\n",
       "      <td>0.419087</td>\n",
       "      <td>0.762093</td>\n",
       "      <td>0.688873</td>\n",
       "      <td>0.730375</td>\n",
       "      <td>0.702222</td>\n",
       "      <td>0.189406</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>q27_q28</td>\n",
       "      <td>Transit intensity + ride-share days (Q27/Q28)</td>\n",
       "      <td>239.0</td>\n",
       "      <td>101.0</td>\n",
       "      <td>0.422594</td>\n",
       "      <td>0.761264</td>\n",
       "      <td>0.689606</td>\n",
       "      <td>0.696047</td>\n",
       "      <td>0.666667</td>\n",
       "      <td>0.192595</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>mobility_bundle</td>\n",
       "      <td>Car + ride-share + employment bundle</td>\n",
       "      <td>143.0</td>\n",
       "      <td>56.0</td>\n",
       "      <td>0.391608</td>\n",
       "      <td>0.746716</td>\n",
       "      <td>0.605258</td>\n",
       "      <td>0.716646</td>\n",
       "      <td>0.666667</td>\n",
       "      <td>0.197594</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>rideshare</td>\n",
       "      <td>Ride-share frequency (Q28/Q29)</td>\n",
       "      <td>233.0</td>\n",
       "      <td>99.0</td>\n",
       "      <td>0.424893</td>\n",
       "      <td>0.745138</td>\n",
       "      <td>0.654822</td>\n",
       "      <td>0.731079</td>\n",
       "      <td>0.708520</td>\n",
       "      <td>0.197184</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>car_access</td>\n",
       "      <td>Car license &amp; access (Q20/Q21)</td>\n",
       "      <td>149.0</td>\n",
       "      <td>58.0</td>\n",
       "      <td>0.389262</td>\n",
       "      <td>0.607332</td>\n",
       "      <td>0.515021</td>\n",
       "      <td>0.639447</td>\n",
       "      <td>0.476190</td>\n",
       "      <td>0.226675</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>ca_benchmark</td>\n",
       "      <td>Group + interpersonal CA (CA memo benchmark)</td>\n",
       "      <td>241.0</td>\n",
       "      <td>101.0</td>\n",
       "      <td>0.419087</td>\n",
       "      <td>0.590000</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>q27_intensity</td>\n",
       "      <td>Transit intensity on use days (Q27)</td>\n",
       "      <td>239.0</td>\n",
       "      <td>101.0</td>\n",
       "      <td>0.422594</td>\n",
       "      <td>0.588571</td>\n",
       "      <td>0.513399</td>\n",
       "      <td>0.622543</td>\n",
       "      <td>0.466667</td>\n",
       "      <td>0.230955</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>geo_benchmark</td>\n",
       "      <td>Lat/long (geo memo benchmark)</td>\n",
       "      <td>241.0</td>\n",
       "      <td>101.0</td>\n",
       "      <td>0.419087</td>\n",
       "      <td>0.551000</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>employment</td>\n",
       "      <td>Employment status</td>\n",
       "      <td>241.0</td>\n",
       "      <td>101.0</td>\n",
       "      <td>0.419087</td>\n",
       "      <td>0.528076</td>\n",
       "      <td>0.424449</td>\n",
       "      <td>0.559512</td>\n",
       "      <td>0.585714</td>\n",
       "      <td>0.247240</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>chance</td>\n",
       "      <td>Chance / prevalence</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>0.500000</td>\n",
       "      <td>NaN</td>\n",
       "      <td>0.500000</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          spec_key                                          label      n  \\\n",
       "4         q28_days                          Ride-share days (Q28)  241.0   \n",
       "5          q27_q28  Transit intensity + ride-share days (Q27/Q28)  239.0   \n",
       "6  mobility_bundle           Car + ride-share + employment bundle  143.0   \n",
       "2        rideshare                 Ride-share frequency (Q28/Q29)  233.0   \n",
       "0       car_access                 Car license & access (Q20/Q21)  149.0   \n",
       "8     ca_benchmark   Group + interpersonal CA (CA memo benchmark)  241.0   \n",
       "3    q27_intensity            Transit intensity on use days (Q27)  239.0   \n",
       "7    geo_benchmark                  Lat/long (geo memo benchmark)  241.0   \n",
       "1       employment                              Employment status  241.0   \n",
       "9           chance                            Chance / prevalence    NaN   \n",
       "\n",
       "   n_regular  prevalence   roc_auc  average_precision  balanced_accuracy  \\\n",
       "4      101.0    0.419087  0.762093           0.688873           0.730375   \n",
       "5      101.0    0.422594  0.761264           0.689606           0.696047   \n",
       "6       56.0    0.391608  0.746716           0.605258           0.716646   \n",
       "2       99.0    0.424893  0.745138           0.654822           0.731079   \n",
       "0       58.0    0.389262  0.607332           0.515021           0.639447   \n",
       "8      101.0    0.419087  0.590000                NaN                NaN   \n",
       "3      101.0    0.422594  0.588571           0.513399           0.622543   \n",
       "7      101.0    0.419087  0.551000                NaN                NaN   \n",
       "1      101.0    0.419087  0.528076           0.424449           0.559512   \n",
       "9        NaN         NaN  0.500000                NaN           0.500000   \n",
       "\n",
       "         f1     brier  \n",
       "4  0.702222  0.189406  \n",
       "5  0.666667  0.192595  \n",
       "6  0.666667  0.197594  \n",
       "2  0.708520  0.197184  \n",
       "0  0.476190  0.226675  \n",
       "8       NaN       NaN  \n",
       "3  0.466667  0.230955  \n",
       "7       NaN       NaN  \n",
       "1  0.585714  0.247240  \n",
       "9       NaN       NaN  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "participants, report = load_full_cohort(\n",
    "    prolific_paths=PROLIFIC,\n",
    "    qualtrics_path=QUALTRICS,\n",
    "    join_how=\"inner\",\n",
    ")\n",
    "print(\"Matched analytic rows:\", len(participants))\n",
    "print(report)\n",
    "\n",
    "bundle = run_all_followup_analyses(\n",
    "    participants,\n",
    "    n_splits=N_SPLITS,\n",
    "    n_perm_repeats=N_PERM,\n",
    "    random_state=SEED,\n",
    ")\n",
    "comparison = bundle[\"comparison\"].copy()\n",
    "display(comparison)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "994c0c59",
   "metadata": {},
   "source": [
    "## 3. Comparison figure\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "949d8c20",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-25T15:41:16.718865Z",
     "iopub.status.busy": "2026-07-25T15:41:16.718706Z",
     "iopub.status.idle": "2026-07-25T15:41:18.164835Z",
     "shell.execute_reply": "2026-07-25T15:41:18.164219Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wrote /workspace/memos/figures/transit_covariate_followups_memo.png\n",
      "car_access AUC= 0.607 n= 149 → /workspace/memos/figures/car_access_predicts_transit_memo.png\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "employment AUC= 0.528 n= 241 → /workspace/memos/figures/employment_predicts_transit_memo.png\n",
      "rideshare AUC= 0.745 n= 233 → /workspace/memos/figures/rideshare_predicts_transit_memo.png\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "q27_intensity AUC= 0.589 n= 239 → /workspace/memos/figures/q27_intensity_predicts_transit_memo.png\n",
      "q28_days AUC= 0.762 n= 241 → /workspace/memos/figures/q28_days_predicts_transit_memo.png\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "q27_q28 AUC= 0.761 n= 239 → /workspace/memos/figures/q27_q28_predicts_transit_memo.png\n",
      "mobility_bundle AUC= 0.747 n= 143 → /workspace/memos/figures/mobility_bundle_predicts_transit_memo.png\n"
     ]
    }
   ],
   "source": [
    "fig_path = ROOT / \"memos\" / \"figures\" / \"transit_covariate_followups_memo.png\"\n",
    "plot_comparison_memo_figure(comparison, output_path=fig_path)\n",
    "print(\"Wrote\", fig_path)\n",
    "\n",
    "for key, analysis in bundle[\"analyses\"].items():\n",
    "    p = ROOT / \"memos\" / \"figures\" / f\"{key}_predicts_transit_memo.png\"\n",
    "    plot_family_memo_figure(analysis, output_path=p)\n",
    "    print(key, \"AUC=\", f\"{analysis['metrics']['roc_auc']:.3f}\", \"n=\", analysis[\"summary\"][\"sample\"][\"n\"], \"→\", p)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aeb1d0dd",
   "metadata": {},
   "source": [
    "## 4. Per-family association highlights\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a3bf8369",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-25T15:41:18.167004Z",
     "iopub.status.busy": "2026-07-25T15:41:18.166862Z",
     "iopub.status.idle": "2026-07-25T15:41:18.191587Z",
     "shell.execute_reply": "2026-07-25T15:41:18.191310Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Car license & access (Q20/Q21) ===\n",
      "Car license & access (Q20/Q21) Random Forest CV ROC-AUC = 0.607. Stronger discrimination than the geo benchmark (≈0.55). Exceeds the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Q20</td>\n",
       "      <td>Yes</td>\n",
       "      <td>129</td>\n",
       "      <td>47</td>\n",
       "      <td>82</td>\n",
       "      <td>0.364341</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Q20</td>\n",
       "      <td>No</td>\n",
       "      <td>20</td>\n",
       "      <td>11</td>\n",
       "      <td>9</td>\n",
       "      <td>0.550000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Q21</td>\n",
       "      <td>Yes</td>\n",
       "      <td>123</td>\n",
       "      <td>38</td>\n",
       "      <td>85</td>\n",
       "      <td>0.308943</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Q21</td>\n",
       "      <td>No</td>\n",
       "      <td>25</td>\n",
       "      <td>19</td>\n",
       "      <td>6</td>\n",
       "      <td>0.760000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Q21</td>\n",
       "      <td>Not Sure</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  feature     level    n  n_regular  n_not_regular  pct_regular\n",
       "1     Q20       Yes  129         47             82     0.364341\n",
       "0     Q20        No   20         11              9     0.550000\n",
       "4     Q21       Yes  123         38             85     0.308943\n",
       "2     Q21        No   25         19              6     0.760000\n",
       "3     Q21  Not Sure    1          1              0     1.000000"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Employment status ===\n",
      "Employment status Random Forest CV ROC-AUC = 0.528. Comparable to or weaker than the geo benchmark (≈0.55). Does not exceed the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Employment status</td>\n",
       "      <td>Full-Time</td>\n",
       "      <td>148</td>\n",
       "      <td>67</td>\n",
       "      <td>81</td>\n",
       "      <td>0.452703</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Employment status</td>\n",
       "      <td>Other</td>\n",
       "      <td>62</td>\n",
       "      <td>19</td>\n",
       "      <td>43</td>\n",
       "      <td>0.306452</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Employment status</td>\n",
       "      <td>Part-Time</td>\n",
       "      <td>31</td>\n",
       "      <td>15</td>\n",
       "      <td>16</td>\n",
       "      <td>0.483871</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             feature      level    n  n_regular  n_not_regular  pct_regular\n",
       "0  Employment status  Full-Time  148         67             81     0.452703\n",
       "1  Employment status      Other   62         19             43     0.306452\n",
       "2  Employment status  Part-Time   31         15             16     0.483871"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Ride-share frequency (Q28/Q29) ===\n",
      "Ride-share frequency (Q28/Q29) Random Forest CV ROC-AUC = 0.745. Stronger discrimination than the geo benchmark (≈0.55). Exceeds the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Q28</td>\n",
       "      <td>2-4 days a month</td>\n",
       "      <td>65</td>\n",
       "      <td>34</td>\n",
       "      <td>31</td>\n",
       "      <td>0.523077</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Q28</td>\n",
       "      <td>Never</td>\n",
       "      <td>62</td>\n",
       "      <td>9</td>\n",
       "      <td>53</td>\n",
       "      <td>0.145161</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Q28</td>\n",
       "      <td>0-1 days a month</td>\n",
       "      <td>47</td>\n",
       "      <td>11</td>\n",
       "      <td>36</td>\n",
       "      <td>0.234043</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Q28</td>\n",
       "      <td>4-8 days a month</td>\n",
       "      <td>42</td>\n",
       "      <td>29</td>\n",
       "      <td>13</td>\n",
       "      <td>0.690476</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Q28</td>\n",
       "      <td>8 or more days a month</td>\n",
       "      <td>17</td>\n",
       "      <td>16</td>\n",
       "      <td>1</td>\n",
       "      <td>0.941176</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Q29</td>\n",
       "      <td>1-2 rides in a typical day</td>\n",
       "      <td>206</td>\n",
       "      <td>82</td>\n",
       "      <td>124</td>\n",
       "      <td>0.398058</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>Q29</td>\n",
       "      <td>3-4 rides in a typical day</td>\n",
       "      <td>17</td>\n",
       "      <td>10</td>\n",
       "      <td>7</td>\n",
       "      <td>0.588235</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Q29</td>\n",
       "      <td>5-6 rides in a typical day</td>\n",
       "      <td>9</td>\n",
       "      <td>6</td>\n",
       "      <td>3</td>\n",
       "      <td>0.666667</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>Q29</td>\n",
       "      <td>7 or more rides in a typical day</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  feature                             level    n  n_regular  n_not_regular  \\\n",
       "1     Q28                  2-4 days a month   65         34             31   \n",
       "4     Q28                             Never   62          9             53   \n",
       "0     Q28                  0-1 days a month   47         11             36   \n",
       "2     Q28                  4-8 days a month   42         29             13   \n",
       "3     Q28            8 or more days a month   17         16              1   \n",
       "5     Q29        1-2 rides in a typical day  206         82            124   \n",
       "6     Q29        3-4 rides in a typical day   17         10              7   \n",
       "7     Q29        5-6 rides in a typical day    9          6              3   \n",
       "8     Q29  7 or more rides in a typical day    1          1              0   \n",
       "\n",
       "   pct_regular  \n",
       "1     0.523077  \n",
       "4     0.145161  \n",
       "0     0.234043  \n",
       "2     0.690476  \n",
       "3     0.941176  \n",
       "5     0.398058  \n",
       "6     0.588235  \n",
       "7     0.666667  \n",
       "8     1.000000  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Transit intensity on use days (Q27) ===\n",
      "Transit intensity on use days (Q27) Random Forest CV ROC-AUC = 0.589. Stronger discrimination than the geo benchmark (≈0.55). Does not exceed the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Q27</td>\n",
       "      <td>1-2 rides in a typical day</td>\n",
       "      <td>190</td>\n",
       "      <td>66</td>\n",
       "      <td>124</td>\n",
       "      <td>0.347368</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Q27</td>\n",
       "      <td>3-4 rides in a typical day</td>\n",
       "      <td>45</td>\n",
       "      <td>31</td>\n",
       "      <td>14</td>\n",
       "      <td>0.688889</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Q27</td>\n",
       "      <td>5-6 rides in a typical day</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Q27</td>\n",
       "      <td>7 or more rides in a typical day</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  feature                             level    n  n_regular  n_not_regular  \\\n",
       "0     Q27        1-2 rides in a typical day  190         66            124   \n",
       "1     Q27        3-4 rides in a typical day   45         31             14   \n",
       "2     Q27        5-6 rides in a typical day    3          3              0   \n",
       "3     Q27  7 or more rides in a typical day    1          1              0   \n",
       "\n",
       "   pct_regular  \n",
       "0     0.347368  \n",
       "1     0.688889  \n",
       "2     1.000000  \n",
       "3     1.000000  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Ride-share days (Q28) ===\n",
      "Ride-share days (Q28) Random Forest CV ROC-AUC = 0.762. Stronger discrimination than the geo benchmark (≈0.55). Exceeds the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Q28</td>\n",
       "      <td>Never</td>\n",
       "      <td>70</td>\n",
       "      <td>11</td>\n",
       "      <td>59</td>\n",
       "      <td>0.157143</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Q28</td>\n",
       "      <td>2-4 days a month</td>\n",
       "      <td>65</td>\n",
       "      <td>34</td>\n",
       "      <td>31</td>\n",
       "      <td>0.523077</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Q28</td>\n",
       "      <td>0-1 days a month</td>\n",
       "      <td>47</td>\n",
       "      <td>11</td>\n",
       "      <td>36</td>\n",
       "      <td>0.234043</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Q28</td>\n",
       "      <td>4-8 days a month</td>\n",
       "      <td>42</td>\n",
       "      <td>29</td>\n",
       "      <td>13</td>\n",
       "      <td>0.690476</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Q28</td>\n",
       "      <td>8 or more days a month</td>\n",
       "      <td>17</td>\n",
       "      <td>16</td>\n",
       "      <td>1</td>\n",
       "      <td>0.941176</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  feature                   level   n  n_regular  n_not_regular  pct_regular\n",
       "4     Q28                   Never  70         11             59     0.157143\n",
       "1     Q28        2-4 days a month  65         34             31     0.523077\n",
       "0     Q28        0-1 days a month  47         11             36     0.234043\n",
       "2     Q28        4-8 days a month  42         29             13     0.690476\n",
       "3     Q28  8 or more days a month  17         16              1     0.941176"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Transit intensity + ride-share days (Q27/Q28) ===\n",
      "Transit intensity + ride-share days (Q27/Q28) Random Forest CV ROC-AUC = 0.761. Stronger discrimination than the geo benchmark (≈0.55). Exceeds the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Q27</td>\n",
       "      <td>1-2 rides in a typical day</td>\n",
       "      <td>190</td>\n",
       "      <td>66</td>\n",
       "      <td>124</td>\n",
       "      <td>0.347368</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Q27</td>\n",
       "      <td>3-4 rides in a typical day</td>\n",
       "      <td>45</td>\n",
       "      <td>31</td>\n",
       "      <td>14</td>\n",
       "      <td>0.688889</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Q27</td>\n",
       "      <td>5-6 rides in a typical day</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Q27</td>\n",
       "      <td>7 or more rides in a typical day</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>Q28</td>\n",
       "      <td>Never</td>\n",
       "      <td>69</td>\n",
       "      <td>11</td>\n",
       "      <td>58</td>\n",
       "      <td>0.159420</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Q28</td>\n",
       "      <td>2-4 days a month</td>\n",
       "      <td>65</td>\n",
       "      <td>34</td>\n",
       "      <td>31</td>\n",
       "      <td>0.523077</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Q28</td>\n",
       "      <td>0-1 days a month</td>\n",
       "      <td>46</td>\n",
       "      <td>11</td>\n",
       "      <td>35</td>\n",
       "      <td>0.239130</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>Q28</td>\n",
       "      <td>4-8 days a month</td>\n",
       "      <td>42</td>\n",
       "      <td>29</td>\n",
       "      <td>13</td>\n",
       "      <td>0.690476</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Q28</td>\n",
       "      <td>8 or more days a month</td>\n",
       "      <td>17</td>\n",
       "      <td>16</td>\n",
       "      <td>1</td>\n",
       "      <td>0.941176</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  feature                             level    n  n_regular  n_not_regular  \\\n",
       "0     Q27        1-2 rides in a typical day  190         66            124   \n",
       "1     Q27        3-4 rides in a typical day   45         31             14   \n",
       "2     Q27        5-6 rides in a typical day    3          3              0   \n",
       "3     Q27  7 or more rides in a typical day    1          1              0   \n",
       "8     Q28                             Never   69         11             58   \n",
       "5     Q28                  2-4 days a month   65         34             31   \n",
       "4     Q28                  0-1 days a month   46         11             35   \n",
       "6     Q28                  4-8 days a month   42         29             13   \n",
       "7     Q28            8 or more days a month   17         16              1   \n",
       "\n",
       "   pct_regular  \n",
       "0     0.347368  \n",
       "1     0.688889  \n",
       "2     1.000000  \n",
       "3     1.000000  \n",
       "8     0.159420  \n",
       "5     0.523077  \n",
       "4     0.239130  \n",
       "6     0.690476  \n",
       "7     0.941176  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Car + ride-share + employment bundle ===\n",
      "Car + ride-share + employment bundle Random Forest CV ROC-AUC = 0.747. Stronger discrimination than the geo benchmark (≈0.55). Exceeds the CA-score benchmark (≈0.59).\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>feature</th>\n",
       "      <th>level</th>\n",
       "      <th>n</th>\n",
       "      <th>n_regular</th>\n",
       "      <th>n_not_regular</th>\n",
       "      <th>pct_regular</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>Employment status</td>\n",
       "      <td>Full-Time</td>\n",
       "      <td>81</td>\n",
       "      <td>37</td>\n",
       "      <td>44</td>\n",
       "      <td>0.456790</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>Employment status</td>\n",
       "      <td>Other</td>\n",
       "      <td>45</td>\n",
       "      <td>14</td>\n",
       "      <td>31</td>\n",
       "      <td>0.311111</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>Employment status</td>\n",
       "      <td>Part-Time</td>\n",
       "      <td>17</td>\n",
       "      <td>5</td>\n",
       "      <td>12</td>\n",
       "      <td>0.294118</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Q20</td>\n",
       "      <td>Yes</td>\n",
       "      <td>123</td>\n",
       "      <td>45</td>\n",
       "      <td>78</td>\n",
       "      <td>0.365854</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Q20</td>\n",
       "      <td>No</td>\n",
       "      <td>20</td>\n",
       "      <td>11</td>\n",
       "      <td>9</td>\n",
       "      <td>0.550000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Q21</td>\n",
       "      <td>Yes</td>\n",
       "      <td>118</td>\n",
       "      <td>37</td>\n",
       "      <td>81</td>\n",
       "      <td>0.313559</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Q21</td>\n",
       "      <td>No</td>\n",
       "      <td>24</td>\n",
       "      <td>18</td>\n",
       "      <td>6</td>\n",
       "      <td>0.750000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Q21</td>\n",
       "      <td>Not Sure</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>Q28</td>\n",
       "      <td>Never</td>\n",
       "      <td>48</td>\n",
       "      <td>9</td>\n",
       "      <td>39</td>\n",
       "      <td>0.187500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>Q28</td>\n",
       "      <td>2-4 days a month</td>\n",
       "      <td>42</td>\n",
       "      <td>24</td>\n",
       "      <td>18</td>\n",
       "      <td>0.571429</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Q28</td>\n",
       "      <td>0-1 days a month</td>\n",
       "      <td>32</td>\n",
       "      <td>9</td>\n",
       "      <td>23</td>\n",
       "      <td>0.281250</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Q28</td>\n",
       "      <td>4-8 days a month</td>\n",
       "      <td>14</td>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "      <td>0.571429</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>Q28</td>\n",
       "      <td>8 or more days a month</td>\n",
       "      <td>7</td>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>0.857143</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>Q29</td>\n",
       "      <td>1-2 rides in a typical day</td>\n",
       "      <td>133</td>\n",
       "      <td>50</td>\n",
       "      <td>83</td>\n",
       "      <td>0.375940</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>Q29</td>\n",
       "      <td>3-4 rides in a typical day</td>\n",
       "      <td>7</td>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "      <td>0.428571</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>Q29</td>\n",
       "      <td>5-6 rides in a typical day</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              feature                       level    n  n_regular  \\\n",
       "13  Employment status                   Full-Time   81         37   \n",
       "14  Employment status                       Other   45         14   \n",
       "15  Employment status                   Part-Time   17          5   \n",
       "1                 Q20                         Yes  123         45   \n",
       "0                 Q20                          No   20         11   \n",
       "4                 Q21                         Yes  118         37   \n",
       "2                 Q21                          No   24         18   \n",
       "3                 Q21                    Not Sure    1          1   \n",
       "9                 Q28                       Never   48          9   \n",
       "6                 Q28            2-4 days a month   42         24   \n",
       "5                 Q28            0-1 days a month   32          9   \n",
       "7                 Q28            4-8 days a month   14          8   \n",
       "8                 Q28      8 or more days a month    7          6   \n",
       "10                Q29  1-2 rides in a typical day  133         50   \n",
       "11                Q29  3-4 rides in a typical day    7          3   \n",
       "12                Q29  5-6 rides in a typical day    3          3   \n",
       "\n",
       "    n_not_regular  pct_regular  \n",
       "13             44     0.456790  \n",
       "14             31     0.311111  \n",
       "15             12     0.294118  \n",
       "1              78     0.365854  \n",
       "0               9     0.550000  \n",
       "4              81     0.313559  \n",
       "2               6     0.750000  \n",
       "3               0     1.000000  \n",
       "9              39     0.187500  \n",
       "6              18     0.571429  \n",
       "5              23     0.281250  \n",
       "7               6     0.571429  \n",
       "8               1     0.857143  \n",
       "10             83     0.375940  \n",
       "11              4     0.428571  \n",
       "12              0     1.000000  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "for key, analysis in bundle[\"analyses\"].items():\n",
    "    print(\"\\n===\", FEATURE_SPECS[key][\"label\"], \"===\")\n",
    "    print(analysis[\"summary\"][\"verdict\"][\"interpretation\"])\n",
    "    display(analysis[\"associations\"])\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a95c9b6a",
   "metadata": {},
   "source": [
    "## 5. Export artifacts\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d99dc4fa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-25T15:41:18.192977Z",
     "iopub.status.busy": "2026-07-25T15:41:18.192871Z",
     "iopub.status.idle": "2026-07-25T15:41:18.235690Z",
     "shell.execute_reply": "2026-07-25T15:41:18.235373Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Results card: /workspace/outputs/transit_covariate_rf/followup_results_card.json\n",
      "{\n",
      "  \"secondary_rq\": \"Among the geo-memo follow-up candidates (car access/license, employment, ride-share frequency), which features best predict regular public-transit use?\",\n",
      "  \"benchmarks\": {\n",
      "    \"geo_auc\": 0.551,\n",
      "    \"ca_auc\": 0.59,\n",
      "    \"chance_auc\": 0.5\n",
      "  },\n",
      "  \"best_spec\": \"q28_days\",\n",
      "  \"best_auc\": 0.7620933521923621,\n",
      "  \"comparison\": [\n",
      "    {\n",
      "      \"spec_key\": \"q28_days\",\n",
      "      \"label\": \"Ride-share days (Q28)\",\n",
      "      \"n\": 241.0,\n",
      "      \"n_regular\": 101.0,\n",
      "      \"prevalence\": 0.4190871369294606,\n",
      "      \"roc_auc\": 0.7620933521923621,\n",
      "      \"average_precision\": 0.688872869993286,\n",
      "      \"balanced_accuracy\": 0.7303748231966054,\n",
      "      \"f1\": 0.7022222222222222,\n",
      "      \"brier\": 0.18940626566184446\n",
      "    },\n",
      "    {\n",
      "      \"spec_key\": \"q27_q28\",\n",
      "      \"label\": \"Transit intensity + ride-share days (Q27/Q28)\",\n",
      "      \"n\": 239.0,\n",
      "      \"n_regular\": 101.0,\n",
      "      \"prevalence\": 0.4225941422594142,\n",
      "      \"roc_auc\": 0.7612641698952504,\n",
      "      \"average_precision\": 0.689606135030495,\n",
      "      \"balanced_accuracy\": 0.6960467785909026,\n",
      "      \"f1\": 0.6666666666666666,\n",
      "      \"brier\": 0.19259516438231897\n",
      "    },\n",
      "    {\n",
      "      \"spec_key\": \"mobility_bundle\",\n",
      "      \"label\": \"Car + ride-share + employment bundle\",\n",
      "      \"n\": 143.0,\n",
      "      \"n_regular\": 56.0,\n",
      "      \"prevalence\": 0.3916083916083916,\n",
      "      \"roc_auc\": 0.7467159277504106,\n",
      "      \"average_precision\": 0.6052583001385728,\n",
      "      \"balanced_accuracy\": 0.7166461412151067,\n",
      "      \"f1\": 0.6666666666666666,\n",
      "      \"brier\": 0.19759361412167553\n",
      "    },\n",
      "    {\n",
      "      \"spec_key\"\n"
     ]
    }
   ],
   "source": [
    "out = ROOT / \"outputs\" / \"transit_covariate_rf\"\n",
    "paths = save_followup_bundle(bundle, out)\n",
    "print(\"Results card:\", paths[\"results_card\"])\n",
    "print(json.dumps(bundle[\"results_card\"], indent=2)[:1500])\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee47e973",
   "metadata": {},
   "source": [
    "## 6. Interpretation notes\n",
    "\n",
    "- Ride-share days (`Q28`) carries the strongest single-family signal among the geo-memo candidates.\n",
    "- The joint bundle is essentially ride-share-dominated on the complete-case subset that also has car items.\n",
    "- Car access improves on geography/CA but is limited by missingness on `Q20`/`Q21`.\n",
    "- Employment status alone is near chance and weaker than the geo RF.\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.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
