From 1e61347fe2a93267bd11bde48e714f38c4d3df1c Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:04:59 +0100 Subject: [PATCH 1/8] add person attributes --- notebooks/6_acbm_to_matsim_xml.ipynb | 1025 +++++++++++++++++++++++++- scripts/5_acbm_to_matsim_xml.py | 42 ++ src/acbm/config.py | 4 + src/acbm/postprocessing/matsim.py | 120 +++ 4 files changed, 1187 insertions(+), 4 deletions(-) diff --git a/notebooks/6_acbm_to_matsim_xml.ipynb b/notebooks/6_acbm_to_matsim_xml.ipynb index 7e3f2c0..c2d8bd9 100644 --- a/notebooks/6_acbm_to_matsim_xml.ipynb +++ b/notebooks/6_acbm_to_matsim_xml.ipynb @@ -11,8 +11,21 @@ "import acbm\n", "from pam.read import load_travel_diary\n", "from pam import write\n", + "from typing import Optional\n", "\n", - "from shapely import wkt, Point\n" + "\n", + "from shapely import wkt, Point\n", + "\n", + "from acbm.postprocessing.matsim import (\n", + " # add_home_location_to_individuals,\n", + " # calculate_percentage_remaining,\n", + " # filter_by_pid,\n", + " # filter_no_location,\n", + " # log_row_count,\n", + " get_passengers,\n", + " get_pt_subscription,\n", + " get_students,\n", + ")\n" ] }, { @@ -32,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "metadata": {}, "outputs": [], "source": [ @@ -44,13 +57,299 @@ "legs_geo = pd.read_parquet(acbm.root_path / \"data/processed/activities_pam/legs_with_locations.parquet\")" ] }, + { + "cell_type": "code", + "execution_count": 15, + "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", + "
pidhidfreqhzoneage_years
019989NaNE0200233039
120089NaNE0200233038
2312139NaNE0200233064
3610283NaNE0200233067
4611283NaNE0200233064
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age_years\n", + "0 199 89 NaN E02002330 39\n", + "1 200 89 NaN E02002330 38\n", + "2 312 139 NaN E02002330 64\n", + "3 610 283 NaN E02002330 67\n", + "4 611 283 NaN E02002330 64" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals.head(5)" + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "activities.head(5)" + " # rename age_years to age in individuals\n", + "individuals.rename(columns={\"age_years\": \"age\"}, inplace=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "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", + " \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", + "
idhouseholdage_yearsOA11CDnts_hh_idnts_ind_ideducation_typeTripIDTravDayseqmodeoactdacttsttetTripDisIncSWTripTotalTimeIndividualID
01998939E000590312.019001e+092019001326education_university2.019018e+093.01.0carhomeshop540.0555.02.015.02.019001e+09
11998939E000590312.019001e+092019001326education_university2.019018e+094.01.0car_passengerhomeother450.0480.020.030.02.019001e+09
21998939E000590312.019001e+092019001326education_university2.019018e+092.02.0carworkhome960.01020.025.060.02.019001e+09
31998939E000590312.019001e+092019001326education_university2.019018e+094.03.0carhomeshop960.0975.02.015.02.019001e+09
41998939E000590312.019001e+092019001326education_university2.019018e+097.02.0carworkhome1005.01065.025.060.02.019001e+09
\n", + "
" + ], + "text/plain": [ + " id household age_years OA11CD nts_hh_id nts_ind_id \\\n", + "0 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "1 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "2 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "3 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "4 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "\n", + " education_type TripID TravDay seq mode oact \\\n", + "0 education_university 2.019018e+09 3.0 1.0 car home \n", + "1 education_university 2.019018e+09 4.0 1.0 car_passenger home \n", + "2 education_university 2.019018e+09 2.0 2.0 car work \n", + "3 education_university 2.019018e+09 4.0 3.0 car home \n", + "4 education_university 2.019018e+09 7.0 2.0 car work \n", + "\n", + " dact tst tet TripDisIncSW TripTotalTime IndividualID \n", + "0 shop 540.0 555.0 2.0 15.0 2.019001e+09 \n", + "1 other 450.0 480.0 20.0 30.0 2.019001e+09 \n", + "2 home 960.0 1020.0 25.0 60.0 2.019001e+09 \n", + "3 shop 960.0 975.0 2.0 15.0 2.019001e+09 \n", + "4 home 1005.0 1065.0 25.0 60.0 2.019001e+09 " + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "spc_with_nts = pd.read_parquet(acbm.root_path / \"data/interim/matching/spc_with_nts_trips.parquet\")\n", + "spc_with_nts.head(5)" ] }, { @@ -58,8 +357,726 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "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", + "
idsex
00male
11female
22male
33male
44female
\n", + "
" + ], + "text/plain": [ + " id sex\n", + "0 0 male\n", + "1 1 female\n", + "2 2 male\n", + "3 3 male\n", + "4 4 female" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# add sex column to individuals\n", + "\n", + "spc = pd.read_parquet(acbm.root_path / \"data/external/spc_output/leeds_people_hh.parquet\", \n", + " columns=[\"id\", \"sex\"])\n", + "spc.head(5)\n", + "\n", + "# change spc[\"sex\"] column: 1 = male, 2 = female\n", + "\n", + "spc[\"sex\"] = spc[\"sex\"].map({1:'male',\n", + " 2: 'female'})\n", + "\n", + "spc.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "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", + "
pidhidfreqhzoneage_yearsisStudentsex
019989NaNE0200233039Falsemale
120089NaNE0200233038Falsefemale
2312139NaNE0200233064Falsefemale
3610283NaNE0200233067Falsefemale
4611283NaNE0200233064Falsemale
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age_years isStudent sex\n", + "0 199 89 NaN E02002330 39 False male\n", + "1 200 89 NaN E02002330 38 False female\n", + "2 312 139 NaN E02002330 64 False female\n", + "3 610 283 NaN E02002330 67 False female\n", + "4 611 283 NaN E02002330 64 False male" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals = individuals.merge(spc, left_on=\"pid\", right_on=\"id\", how=\"left\")\n", + "individuals = individuals.drop(columns=\"id\")\n", + "individuals.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "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", + " \n", + " \n", + " \n", + "
pidhidfreqhzoneage_yearsisPassenger
019989NaNE0200233039False
120089NaNE0200233038True
2312139NaNE0200233064False
3610283NaNE0200233067True
4611283NaNE0200233064False
5612283NaNE020023308True
6613283NaNE020023302True
72016892NaNE0200233049True
82017892NaNE0200233048False
92018892NaNE020023309True
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age_years isPassenger\n", + "0 199 89 NaN E02002330 39 False\n", + "1 200 89 NaN E02002330 38 True\n", + "2 312 139 NaN E02002330 64 False\n", + "3 610 283 NaN E02002330 67 True\n", + "4 611 283 NaN E02002330 64 False\n", + "5 612 283 NaN E02002330 8 True\n", + "6 613 283 NaN E02002330 2 True\n", + "7 2016 892 NaN E02002330 49 True\n", + "8 2017 892 NaN E02002330 48 False\n", + "9 2018 892 NaN E02002330 9 True" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals = get_passengers(\n", + " legs = legs, \n", + " individuals = individuals, \n", + " modes = ['car_passenger', 'taxi'])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
pidhidfreqhzoneage_yearsisPassengerhasPTSubscription
019989NaNE0200233039FalseFalse
120089NaNE0200233038TrueFalse
2312139NaNE0200233064FalseTrue
3610283NaNE0200233067TrueTrue
4611283NaNE0200233064FalseTrue
5612283NaNE020023308TrueFalse
6613283NaNE020023302TrueFalse
72016892NaNE0200233049TrueFalse
82017892NaNE0200233048FalseFalse
92018892NaNE020023309TrueFalse
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age_years isPassenger hasPTSubscription\n", + "0 199 89 NaN E02002330 39 False False\n", + "1 200 89 NaN E02002330 38 True False\n", + "2 312 139 NaN E02002330 64 False True\n", + "3 610 283 NaN E02002330 67 True True\n", + "4 611 283 NaN E02002330 64 False True\n", + "5 612 283 NaN E02002330 8 True False\n", + "6 613 283 NaN E02002330 2 True False\n", + "7 2016 892 NaN E02002330 49 True False\n", + "8 2017 892 NaN E02002330 48 False False\n", + "9 2018 892 NaN E02002330 9 True False" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals = get_pt_subscription(individuals = individuals, age_threshold = 66)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
pidhidfreqhzoneage_yearsisStudent
019989NaNE0200233039False
120089NaNE0200233038False
2312139NaNE0200233064False
3610283NaNE0200233067False
4611283NaNE0200233064False
.....................
952340710597NaNE0200233313True
962484411334NaNE0200233316False
972543211574NaNE0200233360False
982547411594NaNE0200233330False
992547511594NaNE0200233320False
\n", + "

100 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age_years isStudent\n", + "0 199 89 NaN E02002330 39 False\n", + "1 200 89 NaN E02002330 38 False\n", + "2 312 139 NaN E02002330 64 False\n", + "3 610 283 NaN E02002330 67 False\n", + "4 611 283 NaN E02002330 64 False\n", + ".. ... ... ... ... ... ...\n", + "95 23407 10597 NaN E02002333 13 True\n", + "96 24844 11334 NaN E02002333 16 False\n", + "97 25432 11574 NaN E02002333 60 False\n", + "98 25474 11594 NaN E02002333 30 False\n", + "99 25475 11594 NaN E02002333 20 False\n", + "\n", + "[100 rows x 6 columns]" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals = get_students(\n", + " individuals = individuals,\n", + " activities = activities,\n", + " age_base_threshold = 16,\n", + " #age_upper_threshold = 30,\n", + " activity = 'education')\n", + "\n", + "individuals.head(10)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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fBCHDh1Sb3PmzMH333+Phx56CPXr14ezszOGDBmCixcv4vr162W2MW7cODzzzDOIiIjAzJkzcfr0afW+5ORkLFq0yCLwREZGori4GKmpqXfraQKwMowUFxejTZs2mDFjBkJDQ/Hss89i+PDhiIuLq3AHYmJikJ2drd7OnTtX4baIiIhqCicnJzRq1Ei95efno0+fPggJCcGKFSuQmJiIuXPnAgAKCgrKbGPq1Kk4duwYevfuja1bt6JFixb49ttvAQC5ubl47rnnLAJPcnIyUlJS1OkXd4tVl/b6+PigRYsWFmXNmzfHihUrAADe3t4AgKysLPj4+Kh1srKycO+995bZpsFggMFgsKYbREREtU5iYiKKi4vx7rvvQqf781zCX31EU6JJkyZo0qQJxo4di8cffxzx8fEYMGAA2rRpg+PHj1eJS4WtOjPSuXNnnDhxwqLs5MmTCAgIAAAEBQXB29sbW7ZsUe/PycnBvn37EB4eboPuEhER1U6NGjVCYWEhPvzwQ5w5cwZLliz5y08m/vjjD4waNQoJCQn45ZdfsGvXLhw4cADNmzcHALzyyivYvXs3Ro0ahUOHDiElJQWrV6+u+hNYx44di71792LGjBk4deoUli1bhk8++QQjR44EACiKgjFjxuDNN9/EmjVrcOTIEURHR8PX1xf9+/evjP4TERHVCq1bt8bs2bMxa9YstGzZEp9//jliY2PLra/X63Hx4kVER0ejSZMmGDRoEHr16oVp06YBAEJCQrBt2zacPHkS9913H0JDQzF58mT4+vreraekUkRErHnAunXrEBMTg5SUFAQFBWHcuHEYPny4er+IYMqUKfjkk09w5coVdOnSBfPmzUOTJk1uq/2cnBy4uLggOzsbZrPZumdDRH+p9KqT1q4ISVQd5eXlITU1FUFBQXB0dNS6O9XeX+3POzl+W70cfJ8+fdCnT59y71cUBdOnT8f06dOtbZqIiIhqIX5RHhEREWmKYYSIiIg0xTBCREREmmIYISIiIk0xjBAREZGmGEaIiIhIUwwjREREpCmGESIiItIUwwgRERFpyuoVWInINrg0O5GGprrc5e1l33ZVRVH+8v4pU6Zg6tSpd9ihqoVhhIiIqArJyMhQf/7yyy8xefJknDhxQi0zmUzqzyKCoqIi2NlV78M5P6YhIiKqQry9vdWbi4sLFEVRf//555/h7OyMDRs2ICwsDAaDATt37sTQoUPRv39/i3bGjBmDrl27qr8XFxcjNjYWQUFBMBqNaN26Nb755pu7++TKUb2jFBERUS00ceJEvPPOOwgODkbdunVv6zGxsbFYunQp4uLi0LhxY2zfvh1PPvkkPDw88MADD1Ryj/8awwgREVE1M336dHTv3v226+fn52PGjBn4/vvvER4eDgAIDg7Gzp078fHHHzOMEBERkXXatm1rVf1Tp07h+vXrtwSYgoIChIaG2rJrFcIwQlTN8aocotrHycnJ4nedTgcRsSgrLCxUf87NzQUArF+/HvXr17eoZzAYKqmXt49hhIiIqJrz8PDA0aNHLcoOHToEe3t7AECLFi1gMBiQlpam+UcyZWEYISIiqua6deuGf//731i8eDHCw8OxdOlSHD16VP0IxtnZGePHj8fYsWNRXFyMLl26IDs7G7t27YLZbMZTTz2laf8ZRoiIiKq5yMhIvP7665gwYQLy8vLwz3/+E9HR0Thy5Iha54033oCHhwdiY2Nx5swZuLq6ok2bNpg0aZKGPf+TIjd/yKSxnJwcuLi4IDs7G2azWevuEFUaW831sKYdzi+h2iYvLw+pqakICgqCo6Oj1t2p9v5qf97J8ZuLnhEREZGmGEaIiIhIUwwjREREpCmGESIiItIUwwgRERFpimGEiIhqvCp24Wi1VVn7keuMEBEv+aUay97eHoqi4MKFC/Dw8ICiKFp3qdoSEVy4cAGKoqgru9oKwwgREdVYer0efn5++PXXX3H27Fmtu1PtKYoCPz8/6PV6m7bLMEJERDWayWRC48aNLb44jirG3t7e5kEEYBghIqJaQK/XV8pBlGyDE1iJiIhIUzwzcrOpLqV+ztauH0RERLUEz4wQERGRphhGiIiISFMMI0RERKQphhEiIiLSFMMIERERaYphhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYYRoiIiEhTXA6eiMoVOHG9+vPZmb017AkRVUWl3yMOT7qvwu3wzAgRERFpyqowMnXqVCiKYnFr1qyZen9eXh5GjhwJd3d3mEwmREVFISsry+adJiIioprD6jMj99xzDzIyMtTbzp071fvGjh2LtWvX4uuvv8a2bduQnp6ORx991KYdJiIioprF6jkjdnZ28Pb2vqU8OzsbCxcuxLJly9CtWzcAQHx8PJo3b469e/ei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kaYYRoiIiEhTDCNERESkKYYRIiIi0hTDCBEREWmKYYSIiIg0xeXgyaa0WkqYiIjKVh3el3lmhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYYRqjiprr8eSMiIroDDCNERESkKYYRIiIi0hTDCBEREWmKYYSIiIg0xTBCREREmuJy8FRhgXnLAABnte0GERFVQFVaJp5nRoiIiEhTDCNERESkKYYRIiIi0hTDCBEREWmKE1iJiIjoL1X2ZFeeGSEiIiJNWR1Gtm/fjr59+8LX1xeKomDVqlUW94sIJk+eDB8fHxiNRkRERCAlJcVW/SUiIqIaxuowcu3aNbRu3Rpz584t8/63334bc+bMQVxcHPbt2wcnJydERkYiLy/vjjtLRERENY/Vc0Z69eqFXr16lXmfiOD999/Ha6+9hn79+gEAFi9eDC8vL6xatQqDBw++s94SERFRjWPTOSOpqanIzMxERESEWubi4oIOHTpgz549ZT4mPz8fOTk5FjciIiKqPWx6NU1mZiYAwMvLy6Lcy8tLve9msbGxmDZtmi27QRVUlZYGJiKi2kPzq2liYmKQnZ2t3s6dO6d1l4iIiOgusmkY8fb2BgBkZWVZlGdlZan33cxgMMBsNlvciIiIqPawaRgJCgqCt7c3tmzZopbl5ORg3759CA8Pt+WmiIiIqIawes5Ibm4uTp06pf6empqKQ4cOwc3NDQ0aNMCYMWPw5ptvonHjxggKCsLrr78OX19f9O/f35b9JiIiohrC6jBy8OBBPPjgg+rv48aNAwA89dRTWLRoESZMmIBr167h2WefxZUrV9ClSxds3LgRjo6Otus1ERER1RhWh5GuXbtCRMq9X1EUTJ8+HdOnT7+jjhEREVHtoPnVNERERFS7MYwQERGRphhGiIiISFMMI0RERKQpmy4HTzUTl4knIqLKxDMjREREpCmGESIiItIUwwgRERFpimGEiIiINMUwQkRERJpiGCEiIiJNMYwQERGRphhGiIiISFMMI0RERKQphhEiIiLSFMMIERERaYphhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYYRoiIiEhTDCNERESkKYYRIiIi0hTDCBEREWmKYYSIiIg0xTBCREREmmIYISIiIk0xjBAREZGmGEaIiIhIUwwjREREpCmGESIiItIUwwgRERFpimGEiIiINMUwQkRERJpiGCEiIiJNMYwQERGRphhGiIiISFMMI0RERKQphhEiIiLSFMMIERERaYphhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYqLYzMnTsXgYGBcHR0RIcOHbB///7K2hQRERFVY5USRr788kuMGzcOU6ZMQVJSElq3bo3IyEj89ttvlbE5IiIiqsYqJYzMnj0bw4cPx9NPP40WLVogLi4OderUwaeffloZmyMiIqJqzM7WDRYUFCAxMRExMTFqmU6nQ0REBPbs2XNL/fz8fOTn56u/Z2dnAwBycnJQnH9dLc/JyVF/Likvq6wyyqtr26XLq2vbpcu5r6rGvqoJ43C3nk9N2Fc1YRzu1vOpCfvKFm2ICKwmNnb+/HkBILt377Yof/nll6V9+/a31J8yZYoA4I033njjjTfeasDt3LlzVmcHm58ZsVZMTAzGjRun/l5cXIxLly7B3d0dV69ehb+/P86dOwez2azWycnJueNyW7RR09quac+nurZd054P91XVaLumPZ/q2nZNez6ly5ydnXH16lX4+vrCWjYPI/Xq1YNer0dWVpZFeVZWFry9vW+pbzAYYDAYLMpcXV0BAIqiAADMZrPFDilhi3K2XTW2ybarxjara9s17flwX9X8tmva8ykpc3FxuaX+7bD5BFYHBweEhYVhy5YtallxcTG2bNmC8PBwW2+OiIiIqrlK+Zhm3LhxeOqpp9C2bVu0b98e77//Pq5du4ann366MjZHRERE1VilhJHHHnsMFy5cwOTJk5GZmYl7770XGzduhJeXl1XtGAwGTJky5ZaPcWxRzrarxjbZdtXYZnVtu6Y9H+6rmt92TXs+5dW1liJSkWtwiIiIiGyD301DREREmmIYISIiIk0xjBAREZGmGEaIiIhIU7UijHCOLhERUdWl+XLwd4PBYEBycjKaN29eKe1nZGRg/vz52LlzJzIyMqDT6RAcHIz+/ftj6NCh0Ov1lbJdIiKimqBaXNr7xx9/IDExEfn5+fj888/x6aefAgB++ukn7NixA5cuXcLEiRMxdOhQ/PjjjygqKkKzZs3QoEEDAMAHH3yAJ598Eu7u7gCAN954A1999RV27twJf39/vPjii3B3d8eSJUsQFxeH5ORkBAUF4dVXX8XgwYMt+vLRRx9h//79ePjhhzF48GBMmzYN06dPh729PTw8PJCRkYF//OMfKCgowKZNm9CiRQts3LgRzs7Od3en3WX79+/Hnj17kJmZCQDw9vZGeHg42rdvf0vd4uJiZGdnY+3atYiOjgbw59mrM2fOQFEUBAcHo6CgAN9++y3y8/Px8MMPo169eurju3Xrhvj4eAQEBKhlP//8M1JTU+Hv74+WLVvi9OnT+PTTT7Fz50507NgRzz//PIKCgiz6kZycjMTERHTt2hXBwcE4duwY5s6di+LiYgQFBSE/P98iXD7yyCNo3LhxZey+KoVjWXMUFBRg1apVt4xnp06d0K9fPzg4OFjU//HHH/HNN9/grbfeUssuXryIpKQk5Ofno0+fPvj999+xcOFC5OfnY+DAgRb/5AUHB2PTpk1o3LgxRAQJCQk4cOAA6tevj0GDBsHe3h47duxAXFwcdu/ejdatW+OVV165ZXXudevWYf/+/YiMjETnzp2xdetWzJo1C+fPn4eLiwvMZrPFP30PPfRQJe7FqsHasfz1119RUFCApUuXYvLkyQAqPpbAn6/rr7/+Gr/++iuaNGmCyMhI7N27F3FxcUhLS0NAQABGjhxZ4ZXWq3wYOXnyJHr06IG0tDQoioLi4mKkp6cjOTkZ/fr1g5OTEy5fvowNGzagV69eMJlMsLOzw5UrV9C6dWvUrVsXCQkJCA0NhYuLi/qmdPnyZRQUFMDOzg5GoxFjx47F9OnTMXz4cHz44Yfq9h999FF89NFH8Pb2xptvvom3334bPXr0wK5duzBmzBi89tpruP/++xEREYH33nsPnTt3RkZGBvbu3YvLly+ja9eu8PX1RbNmze76mwHw139A1r4ZvPPOOygsLISvry/0ej0yMjJQWFiI48ePIzMzEw0aNFAXtsvKykJaWho6d+6MFStWwNPTEzk5OXjmmWewdu1a1KlTB5cuXcKNGzdw6tQpREZG4ty5cyguLsaZM2cwcOBAHD16FCICg8GAt99+W/3ypf79++Odd95Bo0aNkJ+fjy+//BIrVqwAAOh0OrRu3RrHjx9H06ZNcfjwYeh0OiiKgri4ODzzzDMAgJUrV2LQoEFwdXVFfn4+vv32WwwcOBAhISFITk5GdnY29Ho9RAShoaE4f/48Lly4gMcffxxt27a9rQP1xYsXsX79evUgXTIeFT1Qp6am4vjx4/D19UVoaCgA3NGB+ty5c6hbty6cnJyg0+ng4eGBdevWISkpiWN5k8oIXeWN54QJE+Dg4ICGDRti2LBhFuNpTegym834/PPPceHCBXTo0MFiPPft2wc/Pz9s2LABjRo1QkZGBvr164fExEQUFxdjyJAhmDdvHo4fP44ePXogJycHIoKDBw9i4MCByM3NRXFxMXJycvDSSy/B398fcXFxOHHiBF555RU4Ozvj448/RlpaGvR6PYqKitC0aVPExMTg6aefRp8+fbBmzRr1+8defvllvPHGG3BwcMDHH3+MUaNGoXXr1khJScHcuXPx/PPPQ1EUFBUVIS8vDwDw8MMP4/fff8fBgwfRtWtXPPzww7hw4cLfjuWdvjatGcu/em3ejbEs2WdXr161aiwB4KWXXsLYsWMRGBiIa9euYfXq1di3bx/MZjNyc3Ph4+ODjIwM9OnTB82bN8fJkyexbt06rFy5En369Clzv/8lq7/ntxKtXr36lluHDh2kbdu2smTJEpk0aZIAkKCgIGnTpo28+uqrkpmZKYqiSN26daVr164SFBQkW7ZskYkTJ0r37t1FRASAbN++XUREnnjiCenUqZNcuXJFjEajHDt2TCIiIqRu3bryySefiIiIoijy/fffS8+ePUWv14u9vb088sgj4uPjI19//bWIiBw6dEj0er04ODjI6dOnRURk5cqV0rBhQ7G3t5fMzExJSUkRHx8fASAPPPCADBo0SAYNGiQPPPCAODo6SqNGjSQlJUVERNLT06Vdu3ai0+kEgAwZMkSuXr0q+/btExcXF1EURQDIwYMHJSgoSDw8PMTd3V3s7e1l/Pjx8sEHH8gHH3wgAGTs2LHywQcfyIwZM6RDhw4CQMxms+h0Oqlfv77odDp55JFHBIAoiiKKosiECRMkPz9fRETi4uLEzs5OwsLCxGw2y5IlS8TZ2VkGDhwoJpNJAIirq6soiiLe3t5iMplEp9PJwIEDpbCwUEREsrOz5eDBg9K+fXvp16+fZGdny/PPPy+NGjWSzz77TCZMmCAApHfv3tK3b1955JFH5IcffhAA0rx5c+nXr58oiqLuj9J9Lf07APHz8xMnJydJTk6WnTt3iqOjo7Rr104dy+nTp4u3t7cAkHvuuUfee+89CQkJkTfffFNERJYvXy6urq4yffp0eeyxx6R///7y5ptvSkhIiIwaNUqio6MlKytLWrZsKQCkbt260r59e2nfvr0EBASIoijSpUsXycrKUp/7wIED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uXVvVt5Y/vHHH7eMpVYBWuTW8Sw9EbT0eFoTukoOkCIi8fHx8vzzz8vu3btl9+7d6pnb0goLC28Z45vvP3v27C3l165dU/fVwYMH5f3335dLly6V2UZubq5cv35dMjMzJT09XQoKCsrdXln++OMPSUpKsjgLXtbrsryxFBEZNWpUhV6b06dPF39/f6vHsrzXprUBukRVGUuRP6dDnD17tkJjWZYqf2lvTZGammpxCeHNl1/euHED169fh9lsLvPxN27cwPnz5y0uJwOA69evQ6/Xw2AwIDExETt37kR0dDTq1q1bZju5ubm4ePEiHBwcUK9ePdjb29/2c8jLy0NhYSEyMzORn5+PZs2awc6uVqybp8rJyUFiYqLFWIaFhVmM2+XLl5Geno577rmnzDauXr2KpKQkPPDAAxblqampcHR0hI+PD9asWYMffvgBMTEx8PT0vKWNM2fO4OrVq8jLy0NxcTGKiorQuXNn9VLJv3Ps2DHs2rULXl5e6Ny5s8VlqDdzcHAoc9HAssqtqat12/Xr178rY7l27Vps3bq13LEELMfz/PnzCA0NveU9ojxnzpzBxYsXcfHiRdy4cQMdO3b8y/GsiXJycnDw4EFkZWUBKHssgTsfzwMHDvzl6xK4s9dmyVj+/vvvKCoqql1jecdxhiosLS1Nnn766b8tq+zyO23j+vXrsmPHDvn+++9vKf/+++9lxowZt9RNSkpSP1Mtr6615ZXZtsifn31//PHHEhsbKyIiP/30kzz22GPSpUsX9WOun376SZ5//nkZMGCAvPzyy+pVIRUpHzRokHTp0kU9U3Zz3Z9//tmqtkvXL6vfISEhcs8990hUVJSMHTtWveH/X13Qpk0badOmjYwdO1batGlTZnlZZdaWV2bbY8eOFZ1OJ9HR0ervubm58umnn8qkSZPko48+kt9//11ExKL8ww8/lN9//73MsvLq3ml5SV+sqVu6/J///KdMmTJFLV+8eLGEhISIt7e3dO7cWZYvXy6LFy+WTp06iaenp4SFhcny5cvVutaWa9G2k5OTtGzZUq1bYtSoUeok04qW26INW7Ut8udls0OGDLHYL82bNxdPT09p2bKlLF26VC338vISs9ks/fr1k8LCwr+sa215eW03bdpUYmJiLOZuWoNhREOHDh265ZRgWWWVXX4nbZw4ccLi6iIAcv78eYty/P95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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "legs_geo.head(5)\n" + "# histogram of x by age and isStudent \n", + "individuals.groupby(['age', 'isStudent']).size().unstack().plot(kind='bar', stacked=True)\n" ] }, { diff --git a/scripts/5_acbm_to_matsim_xml.py b/scripts/5_acbm_to_matsim_xml.py index 2c63170..3c96e20 100644 --- a/scripts/5_acbm_to_matsim_xml.py +++ b/scripts/5_acbm_to_matsim_xml.py @@ -16,6 +16,9 @@ calculate_percentage_remaining, filter_by_pid, filter_no_location, + get_passengers, + get_pt_subscription, + get_students, log_row_count, ) @@ -50,6 +53,45 @@ def main(config_file): # rename age_years to age in individuals individuals.rename(columns={"age_years": "age"}, inplace=True) + # ----- Add some person attributes to the individuals dataframe + + # sex + + # get sex column from spc + # TODO: add sex column upstream in the beginning of the pipeline + spc = pd.read_parquet( + acbm.root_path / f"data/external/spc_output/{config.region}_people_hh.parquet", + columns=["id", "sex"], + ) + spc.head(5) + + # change spc["sex"] column: 1 = male, 2 = female + spc["sex"] = spc["sex"].map({1: "male", 2: "female"}) + # merge it on + individuals = individuals.merge(spc, left_on="pid", right_on="id", how="left") + individuals = individuals.drop(columns="id") + + # isStudent + + individuals = get_students( + individuals=individuals, + activities=activities, + age_base_threshold=config.postprocessing.student_age_base, + # age_upper_threshold = config.postprocessing.student_age_upper,, + activity="education", + ) + + # isPassenger + individuals = get_passengers( + legs=legs, individuals=individuals, modes=config.postprocessing.modes_passenger + ) + + # hasPTsubscription + + individuals = get_pt_subscription( + individuals=individuals, age_threshold=config.postprocessing.pt_subscription_age + ) + # We will be removing some rows in each planning operation. This function helps keep a # record of the number of rows in each table after each operation. diff --git a/src/acbm/config.py b/src/acbm/config.py index bcb8bee..980e881 100644 --- a/src/acbm/config.py +++ b/src/acbm/config.py @@ -42,6 +42,10 @@ class WorkAssignmentParams(BaseModel): class Postprocessing(BaseModel): pam_jitter: int pam_min_duration: int + student_age_base: int + student_age_upper: int + modes_passenger: list[str] + pt_subscription_age: int class Config(BaseModel): diff --git a/src/acbm/postprocessing/matsim.py b/src/acbm/postprocessing/matsim.py index cd414a0..458d7aa 100644 --- a/src/acbm/postprocessing/matsim.py +++ b/src/acbm/postprocessing/matsim.py @@ -1,3 +1,5 @@ +from typing import Optional + import pandas as pd @@ -220,3 +222,121 @@ def calculate_percentage_remaining( percentage_remaining.sort(key=lambda x: x[1]) return percentage_remaining + + +# FUNCTIONS TO ADD ATTRIBUTES TO INDIVIDUALS + + +def get_passengers( + legs: pd.DataFrame, individuals: pd.DataFrame, modes: list +) -> pd.DataFrame: + """ + Marks individuals as (car) passengers based on the mode of transportation in the legs DataFrame. + + Parameters + ---------- + legs : pd.DataFrame + DataFrame containing legs data with info on an activity leg. Needs a 'mode' column and a 'pid' column. + individuals : pd.DataFrame + DataFrame containing individual data with a 'pid' column. + modes : list + List of passenger modes. + + Returns + ------- + pd.DataFrame + Updated individuals DataFrame with an 'isPassenger' boolean column. + """ + # Get a list of unique pids where mode matches the chosen list of modes + passenger_pids = legs[legs["mode"].isin(modes)]["pid"].unique() + + # Add a boolean column 'isPassenger' to the individuals DataFrame + individuals["isPassenger"] = individuals["pid"].isin(passenger_pids) + + return individuals + + +def get_pt_subscription(individuals: pd.DataFrame, age_threshold=60): + """ + Marks individuals as having a public transport subscription based on their age. + + Parameters + ---------- + individuals : pd.DataFrame + DataFrame containing individual data with an 'age' column. + age_threshold : int + Age threshold for public transport subscription. (normally the pension age) + + Returns + ------- + pd.DataFrame + Updated individuals DataFrame with an 'hasPTSubscription' boolean column. + """ + # Add a boolean column 'hasPTSubscription' to the individuals DataFrame + individuals["hasPTSubscription"] = individuals["age"] >= age_threshold + + return individuals + + +def get_students( + individuals: pd.DataFrame, + activities: pd.DataFrame, + age_base_threshold: Optional[int] = None, + age_upper_threshold: Optional[int] = None, + activity: str = "education", +) -> pd.DataFrame: + """ + Marks individuals as students based on whether they have an education activity, + and optionally whether they are also below certain age thresholds. + + Parameters + ---------- + individuals : pd.DataFrame + DataFrame containing individual data with a 'pid' column. + activities : pd.DataFrame + DataFrame containing activity data with a 'pid' column. + age_base_threshold : Optional[int] + If specified, anyone below this age is automatically a student + age_upper_threshold : Optional[int] + If specified, this is the age limit for people to be a student. If someone has an education + trip but is above this threshold, they are not a student + activity : str, optional + Activity type to consider for being a student. Default is 'education'. + + Returns + ------- + pd.DataFrame + Updated individuals DataFrame with an 'isStudent' boolean column. + """ + + # Get a list of unique pids where the activity is 'education' + education_pids = activities[activities["activity"] == activity]["pid"].unique() + + if age_base_threshold is not None: + # Everyone below age_base_threshold should be assigned to student + base_students = individuals[individuals["age"] < age_base_threshold][ + "pid" + ].unique() + # Everyone below age_upper_threshold who has an education trip should also be a student + if age_upper_threshold is not None: + upper_students = individuals[ + (individuals["age"] < age_upper_threshold) + & (individuals["pid"].isin(education_pids)) + ]["pid"].unique() + student_pids = set(base_students).union(set(upper_students)) + else: + student_pids = set(base_students) + elif age_upper_threshold is not None: + # Everyone below age_upper_threshold who has an education trip should be a student + student_pids = individuals[ + (individuals["age"] < age_upper_threshold) + & (individuals["pid"].isin(education_pids)) + ]["pid"].unique() + else: + # Only people with an education trip should be students + student_pids = education_pids + + # Add a boolean column 'isStudent' to the individuals DataFrame + individuals["isStudent"] = individuals["pid"].isin(student_pids) + + return individuals From b497521ab4f3bb5b22c7abacd7982b58b87908b3 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:30:11 +0100 Subject: [PATCH 2/8] add household income --- notebooks/6_acbm_to_matsim_xml.ipynb | 1278 ++++++++------------------ scripts/5_acbm_to_matsim_xml.py | 19 +- src/acbm/config.py | 1 + src/acbm/postprocessing/matsim.py | 63 ++ 4 files changed, 484 insertions(+), 877 deletions(-) diff --git a/notebooks/6_acbm_to_matsim_xml.ipynb b/notebooks/6_acbm_to_matsim_xml.ipynb index c2d8bd9..47c2f8b 100644 --- a/notebooks/6_acbm_to_matsim_xml.ipynb +++ b/notebooks/6_acbm_to_matsim_xml.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -11,8 +11,6 @@ "import acbm\n", "from pam.read import load_travel_diary\n", "from pam import write\n", - "from typing import Optional\n", - "\n", "\n", "from shapely import wkt, Point\n", "\n", @@ -25,6 +23,7 @@ " get_passengers,\n", " get_pt_subscription,\n", " get_students,\n", + " get_hhlIncome,\n", ")\n" ] }, @@ -45,7 +44,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -59,92 +58,16 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "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", - "
pidhidfreqhzoneage_years
019989NaNE0200233039
120089NaNE0200233038
2312139NaNE0200233064
3610283NaNE0200233067
4611283NaNE0200233064
\n", - "
" - ], "text/plain": [ - " pid hid freq hzone age_years\n", - "0 199 89 NaN E02002330 39\n", - "1 200 89 NaN E02002330 38\n", - "2 312 139 NaN E02002330 64\n", - "3 610 283 NaN E02002330 67\n", - "4 611 283 NaN E02002330 64" + "1709" ] }, - "execution_count": 15, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -165,7 +88,17 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "spc_with_nts = pd.read_parquet(acbm.root_path / \"data/interim/matching/spc_with_nts_trips.parquet\")\n", + "spc_with_nts.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -191,165 +124,400 @@ " \n", " id\n", " household\n", + " workplace\n", + " events\n", + " weekday_diaries\n", + " weekend_diaries\n", + " orig_pid\n", + " id_tus_hh\n", + " id_tus_p\n", + " pid_hs\n", + " ...\n", + " accommodation_type\n", + " communal_type\n", + " num_rooms\n", + " central_heat\n", + " tenure\n", + " num_cars\n", + " sex\n", " age_years\n", - " OA11CD\n", - " nts_hh_id\n", - " nts_ind_id\n", - " education_type\n", - " TripID\n", - " TravDay\n", - " seq\n", - " mode\n", - " oact\n", - " dact\n", - " tst\n", - " tet\n", - " TripDisIncSW\n", - " TripTotalTime\n", - " IndividualID\n", + " ethnicity\n", + " nssec8_household\n", " \n", " \n", " \n", " \n", " 0\n", - " 199\n", - " 89\n", - " 39\n", - " E00059031\n", - " 2.019001e+09\n", - " 2019001326\n", - " education_university\n", - " 2.019018e+09\n", - " 3.0\n", - " 1.0\n", - " car\n", - " home\n", - " shop\n", - " 540.0\n", - " 555.0\n", + " 0\n", + " 0\n", + " NaN\n", + " {'concert_f': 3.6287833784528047e-16, 'concert...\n", + " [954, 1037, 1234, 2981, 6290, 9535, 10385, 106...\n", + " [955, 1036, 1235, 2980, 6291, 9536, 10384, 106...\n", + " E02002330_0001_001\n", + " 34051017\n", + " 1\n", + " 2911721\n", + " ...\n", + " 2.0\n", + " NaN\n", + " 6.0\n", + " True\n", " 2.0\n", - " 15.0\n", - " 2.019001e+09\n", + " 2\n", + " 1\n", + " 68\n", + " 1\n", + " 1.0\n", " \n", " \n", " 1\n", - " 199\n", - " 89\n", - " 39\n", - " E00059031\n", - " 2.019001e+09\n", - " 2019001326\n", - " education_university\n", - " 2.019018e+09\n", + " 1\n", + " 0\n", + " NaN\n", + " {'concert_f': 9.903925281880971e-14, 'concert_...\n", + " [3435, 6069, 13203, 14704]\n", + " [3436, 6068, 13202, 14703]\n", + " E02002330_0001_002\n", + " 21040818\n", + " 1\n", + " 2904618\n", + " ...\n", + " 2.0\n", + " NaN\n", + " 6.0\n", + " True\n", + " 2.0\n", + " 2\n", + " 2\n", + " 65\n", + " 1\n", + " 6.0\n", + " \n", + " \n", + " 2\n", + " 2\n", + " 1\n", + " NaN\n", + " {'concert_f': 1.2791347489984115e-31, 'concert...\n", + " [762, 5168, 6201, 8977]\n", + " [761, 5169, 6200, 8976]\n", + " E02002330_0002_001\n", + " 11131017\n", + " 1\n", + " 2902311\n", + " ...\n", + " 1.0\n", + " NaN\n", + " 5.0\n", + " True\n", + " 1.0\n", + " 2\n", + " 1\n", + " 86\n", + " 1\n", + " 2.0\n", + " \n", + " \n", + " 3\n", + " 3\n", + " 2\n", + " NaN\n", + " {'concert_f': 7.754311082130982e-10, 'concert_...\n", + " [1580, 5417, 5956, 12901]\n", + " [1581, 5416, 5957, 12900]\n", + " E02002330_0003_001\n", + " 15020311\n", + " 1\n", + " 2911131\n", + " ...\n", + " 1.0\n", + " NaN\n", + " 6.0\n", + " True\n", + " 2.0\n", + " 1\n", + " 1\n", + " 58\n", + " 1\n", " 4.0\n", + " \n", + " \n", + " 4\n", + " 4\n", + " 2\n", + " 508.0\n", + " {'concert_f': 2.1388457227544677e-08, 'concert...\n", + " [318, 3145, 10496, 12819, 13943]\n", + " [319, 3144, 10495, 12818, 13942]\n", + " E02002330_0003_002\n", + " 20090607\n", + " 1\n", + " 2909582\n", + " ...\n", + " 1.0\n", + " NaN\n", + " 6.0\n", + " True\n", + " 2.0\n", + " 1\n", + " 2\n", + " 56\n", + " 1\n", " 1.0\n", - " car_passenger\n", - " home\n", - " other\n", - " 450.0\n", - " 480.0\n", - " 20.0\n", - " 30.0\n", - " 2.019001e+09\n", " \n", " \n", - " 2\n", - " 199\n", - " 89\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", + " 794634\n", + " 794634\n", + " 334848\n", + " NaN\n", + " {'concert_f': 0.030085181817412376, 'concert_f...\n", + " [253, 904, 960, 1258, 1666, 1827, 2990, 3158, ...\n", + " [252, 903, 961, 1259, 1667, 1826, 2991, 3159, ...\n", + " E02006876_3658_001\n", + " 15171109\n", + " 2\n", + " 2910202\n", + " ...\n", + " 3.0\n", + " NaN\n", + " 6.0\n", + " True\n", + " 1.0\n", + " 1\n", + " 1\n", " 39\n", - " E00059031\n", - " 2.019001e+09\n", - " 2019001326\n", - " education_university\n", - " 2.019018e+09\n", + " 1\n", + " 3.0\n", + " \n", + " \n", + " 794635\n", + " 794635\n", + " 334849\n", + " NaN\n", + " {'concert_f': 5.36953439222998e-06, 'concert_f...\n", + " [1611, 2074, 3331, 3973, 5305, 7241, 9500, 10413]\n", + " [1610, 2075, 3330, 3974, 5304, 7240, 9499, 10412]\n", + " E02006876_3659_001\n", + " 12080913\n", + " 2\n", + " 2903691\n", + " ...\n", " 2.0\n", + " NaN\n", + " 5.0\n", + " False\n", + " 1.0\n", + " 0\n", + " 2\n", + " 51\n", + " 1\n", + " 7.0\n", + " \n", + " \n", + " 794636\n", + " 794636\n", + " 334850\n", + " NaN\n", + " {'concert_f': 9.81540181321244e-28, 'concert_f...\n", + " [1768, 1833, 2004, 3538, 5690, 5693, 9177, 112...\n", + " [1767, 1832, 2005, 3537, 5691, 5692, 9176, 112...\n", + " E02006876_3660_001\n", + " 15291209\n", + " 1\n", + " 2905917\n", + " ...\n", + " 4.0\n", + " NaN\n", " 2.0\n", - " car\n", - " work\n", - " home\n", - " 960.0\n", - " 1020.0\n", - " 25.0\n", - " 60.0\n", - " 2.019001e+09\n", + " True\n", + " 5.0\n", + " 0\n", + " 1\n", + " 82\n", + " 1\n", + " NaN\n", " \n", " \n", - " 3\n", - " 199\n", - " 89\n", - " 39\n", - " E00059031\n", - " 2.019001e+09\n", - " 2019001326\n", - " education_university\n", - " 2.019018e+09\n", + " 794637\n", + " 794637\n", + " 334851\n", + " NaN\n", + " {'concert_f': 0.05208142101764679, 'concert_fs...\n", + " [2173, 14404, 15340, 16376]\n", + " [2174, 14403, 15339, 16377]\n", + " E02006876_3661_001\n", + " 20280416\n", + " 1\n", + " 2907191\n", + " ...\n", " 4.0\n", + " NaN\n", " 3.0\n", - " car\n", - " home\n", - " shop\n", - " 960.0\n", - " 975.0\n", + " True\n", + " 5.0\n", + " 0\n", + " 1\n", + " 38\n", + " 1\n", " 2.0\n", - " 15.0\n", - " 2.019001e+09\n", " \n", " \n", - " 4\n", - " 199\n", - " 89\n", - " 39\n", - " E00059031\n", - " 2.019001e+09\n", - " 2019001326\n", - " education_university\n", - " 2.019018e+09\n", - " 7.0\n", + " 794638\n", + " 794638\n", + " 334851\n", + " 31329.0\n", + " {'concert_f': 5.096165657043457, 'concert_fs':...\n", + " [3393, 3729, 4300, 5119, 10052, 15867, 15970]\n", + " [3392, 3730, 4299, 5118, 10051, 15866, 15969]\n", + " E02006876_3661_002\n", + " 13031119\n", + " 1\n", + " 2907075\n", + " ...\n", + " 4.0\n", + " NaN\n", + " 3.0\n", + " True\n", + " 5.0\n", + " 0\n", + " 2\n", + " 22\n", + " 2\n", " 2.0\n", - " car\n", - " work\n", - " home\n", - " 1005.0\n", - " 1065.0\n", - " 25.0\n", - " 60.0\n", - " 2.019001e+09\n", " \n", " \n", "\n", + "

794639 rows × 38 columns

\n", "" ], "text/plain": [ - " id household age_years OA11CD nts_hh_id nts_ind_id \\\n", - "0 199 89 39 E00059031 2.019001e+09 2019001326 \n", - "1 199 89 39 E00059031 2.019001e+09 2019001326 \n", - "2 199 89 39 E00059031 2.019001e+09 2019001326 \n", - "3 199 89 39 E00059031 2.019001e+09 2019001326 \n", - "4 199 89 39 E00059031 2.019001e+09 2019001326 \n", + " id household workplace \\\n", + "0 0 0 NaN \n", + "1 1 0 NaN \n", + "2 2 1 NaN \n", + "3 3 2 NaN \n", + "4 4 2 508.0 \n", + "... ... ... ... \n", + "794634 794634 334848 NaN \n", + "794635 794635 334849 NaN \n", + "794636 794636 334850 NaN \n", + "794637 794637 334851 NaN \n", + "794638 794638 334851 31329.0 \n", + "\n", + " events \\\n", + "0 {'concert_f': 3.6287833784528047e-16, 'concert... \n", + "1 {'concert_f': 9.903925281880971e-14, 'concert_... \n", + "2 {'concert_f': 1.2791347489984115e-31, 'concert... \n", + "3 {'concert_f': 7.754311082130982e-10, 'concert_... \n", + "4 {'concert_f': 2.1388457227544677e-08, 'concert... \n", + "... ... \n", + "794634 {'concert_f': 0.030085181817412376, 'concert_f... \n", + "794635 {'concert_f': 5.36953439222998e-06, 'concert_f... \n", + "794636 {'concert_f': 9.81540181321244e-28, 'concert_f... \n", + "794637 {'concert_f': 0.05208142101764679, 'concert_fs... \n", + "794638 {'concert_f': 5.096165657043457, 'concert_fs':... \n", + "\n", + " weekday_diaries \\\n", + "0 [954, 1037, 1234, 2981, 6290, 9535, 10385, 106... \n", + "1 [3435, 6069, 13203, 14704] \n", + "2 [762, 5168, 6201, 8977] \n", + "3 [1580, 5417, 5956, 12901] \n", + "4 [318, 3145, 10496, 12819, 13943] \n", + "... ... \n", + "794634 [253, 904, 960, 1258, 1666, 1827, 2990, 3158, ... \n", + "794635 [1611, 2074, 3331, 3973, 5305, 7241, 9500, 10413] \n", + "794636 [1768, 1833, 2004, 3538, 5690, 5693, 9177, 112... \n", + "794637 [2173, 14404, 15340, 16376] \n", + "794638 [3393, 3729, 4300, 5119, 10052, 15867, 15970] \n", "\n", - " education_type TripID TravDay seq mode oact \\\n", - "0 education_university 2.019018e+09 3.0 1.0 car home \n", - "1 education_university 2.019018e+09 4.0 1.0 car_passenger home \n", - "2 education_university 2.019018e+09 2.0 2.0 car work \n", - "3 education_university 2.019018e+09 4.0 3.0 car home \n", - "4 education_university 2.019018e+09 7.0 2.0 car work \n", + " weekend_diaries orig_pid \\\n", + "0 [955, 1036, 1235, 2980, 6291, 9536, 10384, 106... E02002330_0001_001 \n", + "1 [3436, 6068, 13202, 14703] E02002330_0001_002 \n", + "2 [761, 5169, 6200, 8976] E02002330_0002_001 \n", + "3 [1581, 5416, 5957, 12900] E02002330_0003_001 \n", + "4 [319, 3144, 10495, 12818, 13942] E02002330_0003_002 \n", + "... ... ... \n", + "794634 [252, 903, 961, 1259, 1667, 1826, 2991, 3159, ... E02006876_3658_001 \n", + "794635 [1610, 2075, 3330, 3974, 5304, 7240, 9499, 10412] E02006876_3659_001 \n", + "794636 [1767, 1832, 2005, 3537, 5691, 5692, 9176, 112... E02006876_3660_001 \n", + "794637 [2174, 14403, 15339, 16377] E02006876_3661_001 \n", + "794638 [3392, 3730, 4299, 5118, 10051, 15866, 15969] E02006876_3661_002 \n", "\n", - " dact tst tet TripDisIncSW TripTotalTime IndividualID \n", - "0 shop 540.0 555.0 2.0 15.0 2.019001e+09 \n", - "1 other 450.0 480.0 20.0 30.0 2.019001e+09 \n", - "2 home 960.0 1020.0 25.0 60.0 2.019001e+09 \n", - "3 shop 960.0 975.0 2.0 15.0 2.019001e+09 \n", - "4 home 1005.0 1065.0 25.0 60.0 2.019001e+09 " + " id_tus_hh id_tus_p pid_hs ... accommodation_type communal_type \\\n", + "0 34051017 1 2911721 ... 2.0 NaN \n", + "1 21040818 1 2904618 ... 2.0 NaN \n", + "2 11131017 1 2902311 ... 1.0 NaN \n", + "3 15020311 1 2911131 ... 1.0 NaN \n", + "4 20090607 1 2909582 ... 1.0 NaN \n", + "... ... ... ... ... ... ... \n", + "794634 15171109 2 2910202 ... 3.0 NaN \n", + "794635 12080913 2 2903691 ... 2.0 NaN \n", + "794636 15291209 1 2905917 ... 4.0 NaN \n", + "794637 20280416 1 2907191 ... 4.0 NaN \n", + "794638 13031119 1 2907075 ... 4.0 NaN \n", + "\n", + " num_rooms central_heat tenure num_cars sex age_years ethnicity \\\n", + "0 6.0 True 2.0 2 1 68 1 \n", + "1 6.0 True 2.0 2 2 65 1 \n", + "2 5.0 True 1.0 2 1 86 1 \n", + "3 6.0 True 2.0 1 1 58 1 \n", + "4 6.0 True 2.0 1 2 56 1 \n", + "... ... ... ... ... ... ... ... \n", + "794634 6.0 True 1.0 1 1 39 1 \n", + "794635 5.0 False 1.0 0 2 51 1 \n", + "794636 2.0 True 5.0 0 1 82 1 \n", + "794637 3.0 True 5.0 0 1 38 1 \n", + "794638 3.0 True 5.0 0 2 22 2 \n", + "\n", + " nssec8_household \n", + "0 1.0 \n", + "1 6.0 \n", + "2 2.0 \n", + "3 4.0 \n", + "4 1.0 \n", + "... ... \n", + "794634 3.0 \n", + "794635 7.0 \n", + "794636 NaN \n", + "794637 2.0 \n", + "794638 2.0 \n", + "\n", + "[794639 rows x 38 columns]" ] }, - "execution_count": 16, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "spc_with_nts = pd.read_parquet(acbm.root_path / \"data/interim/matching/spc_with_nts_trips.parquet\")\n", - "spc_with_nts.head(5)" + "spc = pd.read_parquet(acbm.root_path / \"data/external/spc_output/leeds_people_hh.parquet\")\n", + "spc" ] }, { @@ -357,203 +525,28 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "# add sex column to individuals\n", + "\n", + "spc = pd.read_parquet(acbm.root_path / \"data/external/spc_output/leeds_people_hh.parquet\", \n", + " columns=[\"id\", \"household\", \"age_years\", \"sex\", \"salary_yearly\"])\n", + "spc.head(5)\n", + "\n", + "# change spc[\"sex\"] column: 1 = male, 2 = female\n", + "\n", + "spc[\"sex\"] = spc[\"sex\"].map({1:'male',\n", + " 2: 'female'})\n", + "\n", + "spc.head(5)" + ] }, { "cell_type": "code", "execution_count": null, "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", - "
idsex
00male
11female
22male
33male
44female
\n", - "
" - ], - "text/plain": [ - " id sex\n", - "0 0 male\n", - "1 1 female\n", - "2 2 male\n", - "3 3 male\n", - "4 4 female" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# add sex column to individuals\n", - "\n", - "spc = pd.read_parquet(acbm.root_path / \"data/external/spc_output/leeds_people_hh.parquet\", \n", - " columns=[\"id\", \"sex\"])\n", - "spc.head(5)\n", - "\n", - "# change spc[\"sex\"] column: 1 = male, 2 = female\n", - "\n", - "spc[\"sex\"] = spc[\"sex\"].map({1:'male',\n", - " 2: 'female'})\n", - "\n", - "spc.head(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "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", - "
pidhidfreqhzoneage_yearsisStudentsex
019989NaNE0200233039Falsemale
120089NaNE0200233038Falsefemale
2312139NaNE0200233064Falsefemale
3610283NaNE0200233067Falsefemale
4611283NaNE0200233064Falsemale
\n", - "
" - ], - "text/plain": [ - " pid hid freq hzone age_years isStudent sex\n", - "0 199 89 NaN E02002330 39 False male\n", - "1 200 89 NaN E02002330 38 False female\n", - "2 312 139 NaN E02002330 64 False female\n", - "3 610 283 NaN E02002330 67 False female\n", - "4 611 283 NaN E02002330 64 False male" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "individuals = individuals.merge(spc, left_on=\"pid\", right_on=\"id\", how=\"left\")\n", + "individuals = individuals.merge(spc[[\"id\", \"sex\"]], left_on=\"pid\", right_on=\"id\", how=\"left\")\n", "individuals = individuals.drop(columns=\"id\")\n", "individuals.head(5)" ] @@ -562,150 +555,7 @@ "cell_type": "code", "execution_count": null, "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", - " \n", - " \n", - " \n", - "
pidhidfreqhzoneage_yearsisPassenger
019989NaNE0200233039False
120089NaNE0200233038True
2312139NaNE0200233064False
3610283NaNE0200233067True
4611283NaNE0200233064False
5612283NaNE020023308True
6613283NaNE020023302True
72016892NaNE0200233049True
82017892NaNE0200233048False
92018892NaNE020023309True
\n", - "
" - ], - "text/plain": [ - " pid hid freq hzone age_years isPassenger\n", - "0 199 89 NaN E02002330 39 False\n", - "1 200 89 NaN E02002330 38 True\n", - "2 312 139 NaN E02002330 64 False\n", - "3 610 283 NaN E02002330 67 True\n", - "4 611 283 NaN E02002330 64 False\n", - "5 612 283 NaN E02002330 8 True\n", - "6 613 283 NaN E02002330 2 True\n", - "7 2016 892 NaN E02002330 49 True\n", - "8 2017 892 NaN E02002330 48 False\n", - "9 2018 892 NaN E02002330 9 True" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "individuals = get_passengers(\n", " legs = legs, \n", @@ -717,161 +567,7 @@ "cell_type": "code", "execution_count": null, "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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pidhidfreqhzoneage_yearsisPassengerhasPTSubscription
019989NaNE0200233039FalseFalse
120089NaNE0200233038TrueFalse
2312139NaNE0200233064FalseTrue
3610283NaNE0200233067TrueTrue
4611283NaNE0200233064FalseTrue
5612283NaNE020023308TrueFalse
6613283NaNE020023302TrueFalse
72016892NaNE0200233049TrueFalse
82017892NaNE0200233048FalseFalse
92018892NaNE020023309TrueFalse
\n", - "
" - ], - "text/plain": [ - " pid hid freq hzone age_years isPassenger hasPTSubscription\n", - "0 199 89 NaN E02002330 39 False False\n", - "1 200 89 NaN E02002330 38 True False\n", - "2 312 139 NaN E02002330 64 False True\n", - "3 610 283 NaN E02002330 67 True True\n", - "4 611 283 NaN E02002330 64 False True\n", - "5 612 283 NaN E02002330 8 True False\n", - "6 613 283 NaN E02002330 2 True False\n", - "7 2016 892 NaN E02002330 49 True False\n", - "8 2017 892 NaN E02002330 48 False False\n", - "9 2018 892 NaN E02002330 9 True False" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "individuals = get_pt_subscription(individuals = individuals, age_threshold = 66)" ] @@ -880,163 +576,7 @@ "cell_type": "code", "execution_count": null, "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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pidhidfreqhzoneage_yearsisStudent
019989NaNE0200233039False
120089NaNE0200233038False
2312139NaNE0200233064False
3610283NaNE0200233067False
4611283NaNE0200233064False
.....................
952340710597NaNE0200233313True
962484411334NaNE0200233316False
972543211574NaNE0200233360False
982547411594NaNE0200233330False
992547511594NaNE0200233320False
\n", - "

100 rows × 6 columns

\n", - "
" - ], - "text/plain": [ - " pid hid freq hzone age_years isStudent\n", - "0 199 89 NaN E02002330 39 False\n", - "1 200 89 NaN E02002330 38 False\n", - "2 312 139 NaN E02002330 64 False\n", - "3 610 283 NaN E02002330 67 False\n", - "4 611 283 NaN E02002330 64 False\n", - ".. ... ... ... ... ... ...\n", - "95 23407 10597 NaN E02002333 13 True\n", - "96 24844 11334 NaN E02002333 16 False\n", - "97 25432 11574 NaN E02002333 60 False\n", - "98 25474 11594 NaN E02002333 30 False\n", - "99 25475 11594 NaN E02002333 20 False\n", - "\n", - "[100 rows x 6 columns]" - ] - }, - "execution_count": 58, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "individuals = get_students(\n", " individuals = individuals,\n", @@ -1052,33 +592,27 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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fBCHDh1Sb3PmzMH333+Phx56CPXr14ezszOGDBmCixcv4vr162W2MW7cODzzzDOIiIjAzJkzcfr0afW+5ORkLFq0yCLwREZGori4GKmpqXfraQKwMowUFxejTZs2mDFjBkJDQ/Hss89i+PDhiIuLq3AHYmJikJ2drd7OnTtX4baIiIhqCicnJzRq1Ei95efno0+fPggJCcGKFSuQmJiIuXPnAgAKCgrKbGPq1Kk4duwYevfuja1bt6JFixb49ttvAQC5ubl47rnnLAJPcnIyUlJS1OkXd4tVl/b6+PigRYsWFmXNmzfHihUrAADe3t4AgKysLPj4+Kh1srKycO+995bZpsFggMFgsKYbREREtU5iYiKKi4vx7rvvQqf781zCX31EU6JJkyZo0qQJxo4di8cffxzx8fEYMGAA2rRpg+PHj1eJS4WtOjPSuXNnnDhxwqLs5MmTCAgIAAAEBQXB29sbW7ZsUe/PycnBvn37EB4eboPuEhER1U6NGjVCYWEhPvzwQ5w5cwZLliz5y08m/vjjD4waNQoJCQn45ZdfsGvXLhw4cADNmzcHALzyyivYvXs3Ro0ahUOHDiElJQWrV6+u+hNYx44di71792LGjBk4deoUli1bhk8++QQjR44EACiKgjFjxuDNN9/EmjVrcOTIEURHR8PX1xf9+/evjP4TERHVCq1bt8bs2bMxa9YstGzZEp9//jliY2PLra/X63Hx4kVER0ejSZMmGDRoEHr16oVp06YBAEJCQrBt2zacPHkS9913H0JDQzF58mT4+vreraekUkRErHnAunXrEBMTg5SUFAQFBWHcuHEYPny4er+IYMqUKfjkk09w5coVdOnSBfPmzUOTJk1uq/2cnBy4uLggOzsbZrPZumdDRH+p9KqT1q4ISVQd5eXlITU1FUFBQXB0dNS6O9XeX+3POzl+W70cfJ8+fdCnT59y71cUBdOnT8f06dOtbZqIiIhqIX5RHhEREWmKYYSIiIg0xTBCREREmmIYISIiIk0xjBAREZGmGEaIiIhIUwwjREREpCmGESIiItIUwwgRERFpyuoVWInINrg0O5GGprrc5e1l33ZVRVH+8v4pU6Zg6tSpd9ihqoVhhIiIqArJyMhQf/7yyy8xefJknDhxQi0zmUzqzyKCoqIi2NlV78M5P6YhIiKqQry9vdWbi4sLFEVRf//555/h7OyMDRs2ICwsDAaDATt37sTQoUPRv39/i3bGjBmDrl27qr8XFxcjNjYWQUFBMBqNaN26Nb755pu7++TKUb2jFBERUS00ceJEvPPOOwgODkbdunVv6zGxsbFYunQp4uLi0LhxY2zfvh1PPvkkPDw88MADD1Ryj/8awwgREVE1M336dHTv3v226+fn52PGjBn4/vvvER4eDgAIDg7Gzp078fHHHzOMEBERkXXatm1rVf1Tp07h+vXrtwSYgoIChIaG2rJrFcIwQlTN8aocotrHycnJ4nedTgcRsSgrLCxUf87NzQUArF+/HvXr17eoZzAYKqmXt49hhIiIqJrz8PDA0aNHLcoOHToEe3t7AECLFi1gMBiQlpam+UcyZWEYISIiqua6deuGf//731i8eDHCw8OxdOlSHD16VP0IxtnZGePHj8fYsWNRXFyMLl26IDs7G7t27YLZbMZTTz2laf8ZRoiIiKq5yMhIvP7665gwYQLy8vLwz3/+E9HR0Thy5Iha54033oCHhwdiY2Nx5swZuLq6ok2bNpg0aZKGPf+TIjd/yKSxnJwcuLi4IDs7G2azWevuEFUaW831sKYdzi+h2iYvLw+pqakICgqCo6Oj1t2p9v5qf97J8ZuLnhEREZGmGEaIiIhIUwwjREREpCmGESIiItIUwwgRERFpimGEiIhqvCp24Wi1VVn7keuMEBEv+aUay97eHoqi4MKFC/Dw8ICiKFp3qdoSEVy4cAGKoqgru9oKwwgREdVYer0efn5++PXXX3H27Fmtu1PtKYoCPz8/6PV6m7bLMEJERDWayWRC48aNLb44jirG3t7e5kEEYBghIqJaQK/XV8pBlGyDE1iJiIhIUzwzcrOpLqV+ztauH0RERLUEz4wQERGRphhGiIiISFMMI0RERKQphhEiIiLSFMMIERERaYphhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYYRoiIiEhTXA6eiMoVOHG9+vPZmb017AkRVUWl3yMOT7qvwu3wzAgRERFpyqowMnXqVCiKYnFr1qyZen9eXh5GjhwJd3d3mEwmREVFISsry+adJiIioprD6jMj99xzDzIyMtTbzp071fvGjh2LtWvX4uuvv8a2bduQnp6ORx991KYdJiIioprF6jkjdnZ28Pb2vqU8OzsbCxcuxLJly9CtWzcAQHx8PJo3b469e/ei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kaYYRoiIiEhTDCNERESkKYYRIiIi0hTDCBEREWmKYYSIiIg0xeXgyaa0WkqYiIjKVh3el3lmhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYYRqjiprr8eSMiIroDDCNERESkKYYRIiIi0hTDCBEREWmKYYSIiIg0xTBCREREmuJy8FRhgXnLAABnte0GERFVQFVaJp5nRoiIiEhTDCNERESkKYYRIiIi0hTDCBEREWmKE1iJiIjoL1X2ZFeeGSEiIiJNWR1Gtm/fjr59+8LX1xeKomDVqlUW94sIJk+eDB8fHxiNRkRERCAlJcVW/SUiIqIaxuowcu3aNbRu3Rpz584t8/63334bc+bMQVxcHPbt2wcnJydERkYiLy/vjjtLRERENY/Vc0Z69eqFXr16lXmfiOD999/Ha6+9hn79+gEAFi9eDC8vL6xatQqDBw++s94SERFRjWPTOSOpqanIzMxERESEWubi4oIOHTpgz549ZT4mPz8fOTk5FjciIiKqPWx6NU1mZiYAwMvLy6Lcy8tLve9msbGxmDZtmi27QRVUlZYGJiKi2kPzq2liYmKQnZ2t3s6dO6d1l4iIiOgusmkY8fb2BgBkZWVZlGdlZan33cxgMMBsNlvciIiIqPawaRgJCgqCt7c3tmzZopbl5ORg3759CA8Pt+WmiIiIqIawes5Ibm4uTp06pf6empqKQ4cOwc3NDQ0aNMCYMWPw5ptvonHjxggKCsLrr78OX19f9O/f35b9JiIiohrC6jBy8OBBPPjgg+rv48aNAwA89dRTWLRoESZMmIBr167h2WefxZUrV9ClSxds3LgRjo6Otus1ERER1RhWh5GuXbtCRMq9X1EUTJ8+HdOnT7+jjhEREVHtoPnVNERERFS7MYwQERGRphhGiIiISFMMI0RERKQpmy4HTzUTl4knIqLKxDMjREREpCmGESIiItIUwwgRERFpimGEiIiINMUwQkRERJpiGCEiIiJNMYwQERGRphhGiIiISFMMI0RERKQphhEiIiLSFMMIERERaYphhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYYRoiIiEhTDCNERESkKYYRIiIi0hTDCBEREWmKYYSIiIg0xTBCREREmmIYISIiIk0xjBAREZGmGEaIiIhIUwwjREREpCmGESIiItIUwwgRERFpimGEiIiINMUwQkRERJpiGCEiIiJNMYwQERGRphhGiIiISFMMI0RERKQphhEiIiLSFMMIERERaYphhIiIiDTFMEJERESaYhghIiIiTTGMEBERkaYqLYzMnTsXgYGBcHR0RIcOHbB///7K2hQRERFVY5USRr788kuMGzcOU6ZMQVJSElq3bo3IyEj89ttvlbE5IiIiqsYqJYzMnj0bw4cPx9NPP40WLVogLi4OderUwaeffloZmyMiIqJqzM7WDRYUFCAxMRExMTFqmU6nQ0REBPbs2XNL/fz8fOTn56u/Z2dnAwBycnJQnH9dLc/JyVF/Likvq6wyyqtr26XLq2vbpcu5r6rGvqoJ43C3nk9N2Fc1YRzu1vOpCfvKFm2ICKwmNnb+/HkBILt377Yof/nll6V9+/a31J8yZYoA4I033njjjTfeasDt3LlzVmcHm58ZsVZMTAzGjRun/l5cXIxLly7B3d0dV69ehb+/P86dOwez2azWycnJueNyW7RR09quac+nurZd054P91XVaLumPZ/q2nZNez6ly5ydnXH16lX4+vrCWjYPI/Xq1YNer0dWVpZFeVZWFry9vW+pbzAYYDAYLMpcXV0BAIqiAADMZrPFDilhi3K2XTW2ybarxjara9s17flwX9X8tmva8ykpc3FxuaX+7bD5BFYHBweEhYVhy5YtallxcTG2bNmC8PBwW2+OiIiIqrlK+Zhm3LhxeOqpp9C2bVu0b98e77//Pq5du4ann366MjZHRERE1VilhJHHHnsMFy5cwOTJk5GZmYl7770XGzduhJeXl1XtGAwGTJky5ZaPcWxRzrarxjbZdtXYZnVtu6Y9H+6rmt92TXs+5dW1liJSkWtwiIiIiGyD301DREREmmIYISIiIk0xjBAREZGmGEaIiIhIU7UijHCOLhERUdWl+XLwd4PBYEBycjKaN29eKe1nZGRg/vz52LlzJzIyMqDT6RAcHIz+/ftj6NCh0Ov1lbJdIiKimqBaXNr7xx9/IDExEfn5+fj888/x6aefAgB++ukn7NixA5cuXcLEiRMxdOhQ/PjjjygqKkKzZs3QoEEDAMAHH3yAJ598Eu7u7gCAN954A1999RV27twJf39/vPjii3B3d8eSJUsQFxeH5ORkBAUF4dVXX8XgwYMt+vLRRx9h//79ePjhhzF48GBMmzYN06dPh729PTw8PJCRkYF//OMfKCgowKZNm9CiRQts3LgRzs7Od3en3WX79+/Hnj17kJmZCQDw9vZGeHg42rdvf0vd4uJiZGdnY+3atYiOjgbw59mrM2fOQFEUBAcHo6CgAN9++y3y8/Px8MMPo169eurju3Xrhvj4eAQEBKhlP//8M1JTU+Hv74+WLVvi9OnT+PTTT7Fz50507NgRzz//PIKCgiz6kZycjMTERHTt2hXBwcE4duwY5s6di+LiYgQFBSE/P98iXD7yyCNo3LhxZey+KoVjWXMUFBRg1apVt4xnp06d0K9fPzg4OFjU//HHH/HNN9/grbfeUssuXryIpKQk5Ofno0+fPvj999+xcOFC5OfnY+DAgRb/5AUHB2PTpk1o3LgxRAQJCQk4cOAA6tevj0GDBsHe3h47duxAXFwcdu/ejdatW+OVV165ZXXudevWYf/+/YiMjETnzp2xdetWzJo1C+fPn4eLiwvMZrPFP30PPfRQJe7FqsHasfz1119RUFCApUuXYvLkyQAqPpbAn6/rr7/+Gr/++iuaNGmCyMhI7N27F3FxcUhLS0NAQABGjhxZ4ZXWq3wYOXnyJHr06IG0tDQoioLi4mKkp6cjOTkZ/fr1g5OTEy5fvowNGzagV69eMJlMsLOzw5UrV9C6dWvUrVsXCQkJCA0NhYuLi/qmdPnyZRQUFMDOzg5GoxFjx47F9OnTMXz4cHz44Yfq9h999FF89NFH8Pb2xptvvom3334bPXr0wK5duzBmzBi89tpruP/++xEREYH33nsPnTt3RkZGBvbu3YvLly+ja9eu8PX1RbNmze76mwHw139A1r4ZvPPOOygsLISvry/0ej0yMjJQWFiI48ePIzMzEw0aNFAXtsvKykJaWho6d+6MFStWwNPTEzk5OXjmmWewdu1a1KlTB5cuXcKNGzdw6tQpREZG4ty5cyguLsaZM2cwcOBAHD16FCICg8GAt99+W/3ypf79++Odd95Bo0aNkJ+fjy+//BIrVqwAAOh0OrRu3RrHjx9H06ZNcfjwYeh0OiiKgri4ODzzzDMAgJUrV2LQoEFwdXVFfn4+vv32WwwcOBAhISFITk5GdnY29Ho9RAShoaE4f/48Lly4gMcffxxt27a9rQP1xYsXsX79evUgXTIeFT1Qp6am4vjx4/D19UVoaCgA3NGB+ty5c6hbty6cnJyg0+ng4eGBdevWISkpiWN5k8oIXeWN54QJE+Dg4ICGDRti2LBhFuNpTegym834/PPPceHCBXTo0MFiPPft2wc/Pz9s2LABjRo1QkZGBvr164fExEQUFxdjyJAhmDdvHo4fP44ePXogJycHIoKDBw9i4MCByM3NRXFxMXJycvDSSy/B398fcXFxOHHiBF555RU4Ozvj448/RlpaGvR6PYqKitC0aVPExMTg6aefRp8+fbBmzRr1+8defvllvPHGG3BwcMDHH3+MUaNGoXXr1khJScHcuXPx/PPPQ1EUFBUVIS8vDwDw8MMP4/fff8fBgwfRtWtXPPzww7hw4cLfjuWdvjatGcu/em3ejbEs2WdXr161aiwB4KWXXsLYsWMRGBiIa9euYfXq1di3bx/MZjNyc3Ph4+ODjIwM9OnTB82bN8fJkyexbt06rFy5En369Clzv/8lq7/ntxKtXr36lluHDh2kbdu2smTJEpk0aZIAkKCgIGnTpo28+uqrkpmZKYqiSN26daVr164SFBQkW7ZskYkTJ0r37t1FRASAbN++XUREnnjiCenUqZNcuXJFjEajHDt2TCIiIqRu3bryySefiIiIoijy/fffS8+ePUWv14u9vb088sgj4uPjI19//bWIiBw6dEj0er04ODjI6dOnRURk5cqV0rBhQ7G3t5fMzExJSUkRHx8fASAPPPCADBo0SAYNGiQPPPCAODo6SqNGjSQlJUVERNLT06Vdu3ai0+kEgAwZMkSuXr0q+/btExcXF1EURQDIwYMHJSgoSDw8PMTd3V3s7e1l/Pjx8sEHH8gHH3wgAGTs2LHywQcfyIwZM6RDhw4CQMxms+h0Oqlfv77odDp55JFHBIAoiiKKosiECRMkPz9fRETi4uLEzs5OwsLCxGw2y5IlS8TZ2VkGDhwoJpNJAIirq6soiiLe3t5iMplEp9PJwIEDpbCwUEREsrOz5eDBg9K+fXvp16+fZGdny/PPPy+NGjWSzz77TCZMmCAApHfv3tK3b1955JFH5IcffhAA0rx5c+nXr58oiqLuj9J9Lf07APHz8xMnJydJTk6WnTt3iqOjo7Rr104dy+nTp4u3t7cAkHvuuUfee+89CQkJkTfffFNERJYvXy6urq4yffp0eeyxx6R///7y5ptvSkhIiIwaNUqio6MlKytLWrZsKQCkbt260r59e2nfvr0EBASIoijSpUsXycrKUp/7wIED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uXVvVt5Y/vHHH7eMpVYBWuTW8Sw9EbT0eFoTukoOkCIi8fHx8vzzz8vu3btl9+7d6pnb0goLC28Z45vvP3v27C3l165dU/fVwYMH5f3335dLly6V2UZubq5cv35dMjMzJT09XQoKCsrdXln++OMPSUpKsjgLXtbrsryxFBEZNWpUhV6b06dPF39/f6vHsrzXprUBukRVGUuRP6dDnD17tkJjWZYqf2lvTZGammpxCeHNl1/euHED169fh9lsLvPxN27cwPnz5y0uJwOA69evQ6/Xw2AwIDExETt37kR0dDTq1q1bZju5ubm4ePEiHBwcUK9ePdjb29/2c8jLy0NhYSEyMzORn5+PZs2awc6uVqybp8rJyUFiYqLFWIaFhVmM2+XLl5Geno577rmnzDauXr2KpKQkPPDAAxblqampcHR0hI+PD9asWYMffvgBMTEx8PT0vKWNM2fO4OrVq8jLy0NxcTGKiorQuXNn9VLJv3Ps2DHs2rULXl5e6Ny5s8VlqDdzcHAoc9HAssqtqat12/Xr178rY7l27Vps3bq13LEELMfz/PnzCA0NveU9ojxnzpzBxYsXcfHiRdy4cQMdO3b8y/GsiXJycnDw4EFkZWUBKHssgTsfzwMHDvzl6xK4s9dmyVj+/vvvKCoqql1jecdxhiosLS1Nnn766b8tq+zyO23j+vXrsmPHDvn+++9vKf/+++9lxowZt9RNSkpSP1Mtr6615ZXZtsifn31//PHHEhsbKyIiP/30kzz22GPSpUsX9WOun376SZ5//nkZMGCAvPzyy+pVIRUpHzRokHTp0kU9U3Zz3Z9//tmqtkvXL6vfISEhcs8990hUVJSMHTtWveH/X13Qpk0badOmjYwdO1batGlTZnlZZdaWV2bbY8eOFZ1OJ9HR0ervubm58umnn8qkSZPko48+kt9//11ExKL8ww8/lN9//73MsvLq3ml5SV+sqVu6/J///KdMmTJFLV+8eLGEhISIt7e3dO7cWZYvXy6LFy+WTp06iaenp4SFhcny5cvVutaWa9G2k5OTtGzZUq1bYtSoUeok04qW26INW7Ut8udls0OGDLHYL82bNxdPT09p2bKlLF26VC338vISs9ks/fr1k8LCwr+sa215eW03bdpUYmJiLOZuWoNhREOHDh265ZRgWWWVXX4nbZw4ccLi6iIAcv78eYty/P95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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# histogram of x by age and isStudent \n", "individuals.groupby(['age', 'isStudent']).size().unstack().plot(kind='bar', stacked=True)\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "individuals = get_hhlIncome(\n", + " individuals = individuals,\n", + " individuals_with_salary = spc,\n", + " pension_age = 66,\n", + " pension = 13000)\n", + "\n", + "individuals.head(10)" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/scripts/5_acbm_to_matsim_xml.py b/scripts/5_acbm_to_matsim_xml.py index 3c96e20..a4807ea 100644 --- a/scripts/5_acbm_to_matsim_xml.py +++ b/scripts/5_acbm_to_matsim_xml.py @@ -16,6 +16,7 @@ calculate_percentage_remaining, filter_by_pid, filter_no_location, + get_hhlIncome, get_passengers, get_pt_subscription, get_students, @@ -61,23 +62,23 @@ def main(config_file): # TODO: add sex column upstream in the beginning of the pipeline spc = pd.read_parquet( acbm.root_path / f"data/external/spc_output/{config.region}_people_hh.parquet", - columns=["id", "sex"], + columns=["id", "household", "age_years", "sex", "salary_yearly"], ) - spc.head(5) # change spc["sex"] column: 1 = male, 2 = female spc["sex"] = spc["sex"].map({1: "male", 2: "female"}) # merge it on - individuals = individuals.merge(spc, left_on="pid", right_on="id", how="left") + individuals = individuals.merge( + spc[["id", "sex"]], left_on="pid", right_on="id", how="left" + ) individuals = individuals.drop(columns="id") # isStudent - individuals = get_students( individuals=individuals, activities=activities, age_base_threshold=config.postprocessing.student_age_base, - # age_upper_threshold = config.postprocessing.student_age_upper,, + # age_upper_threshold = config.postprocessing.student_age_upper, activity="education", ) @@ -92,6 +93,14 @@ def main(config_file): individuals=individuals, age_threshold=config.postprocessing.pt_subscription_age ) + ## hhlIncome + individuals = get_hhlIncome( + individuals=individuals, + individuals_with_salary=spc, + pension_age=config.postprocessing.pt_subscription_age, + pension=config.postprocessing.state_pension, + ) + # We will be removing some rows in each planning operation. This function helps keep a # record of the number of rows in each table after each operation. diff --git a/src/acbm/config.py b/src/acbm/config.py index 980e881..eaca0d6 100644 --- a/src/acbm/config.py +++ b/src/acbm/config.py @@ -46,6 +46,7 @@ class Postprocessing(BaseModel): student_age_upper: int modes_passenger: list[str] pt_subscription_age: int + state_pension: int class Config(BaseModel): diff --git a/src/acbm/postprocessing/matsim.py b/src/acbm/postprocessing/matsim.py index 458d7aa..b8d67c2 100644 --- a/src/acbm/postprocessing/matsim.py +++ b/src/acbm/postprocessing/matsim.py @@ -1,5 +1,6 @@ from typing import Optional +import numpy as np import pandas as pd @@ -340,3 +341,65 @@ def get_students( individuals["isStudent"] = individuals["pid"].isin(student_pids) return individuals + + +def get_hhlIncome( + individuals: pd.DataFrame, + individuals_with_salary: pd.DataFrame, + pension_age: int = 66, + pension: int = 13000, +) -> pd.DataFrame: + """ + Function to calculate the household level income from the individual level income data in the SPC + dataset. The function groups salary data by household and then merges the household level income + data back onto the individual level data. + + The salary data is missing for many individuals in the SPC dataset. It also does not include pension + We add the state pension if the person has reached the state pension age (66 years) and has no salary data. + + TODO: add student maintenance loan? + + Parameters + ---------- + individuals : pd.DataFrame + The individual level data output from acbm + individuals_with_salary : pd.DataFrame + The original SPC dataset with the salary_yearly column + + Returns + ------- + pd.DataFrame + The individual level data with the hhlIncome column added + """ + individuals_income = individuals.copy() + + # If person is a pensioner, add pension, otherwise keep salary + individuals_with_salary["income_modeled"] = np.where( + (individuals_with_salary["salary_yearly"] == 0) + | (individuals_with_salary["salary_yearly"].isna()), + np.where(individuals_with_salary["age_years"] >= pension_age, pension, 0), + individuals_with_salary["salary_yearly"], + ) + + # Summarize the data by household to create the hhlIncome column + household_income = ( + individuals_with_salary.groupby("household")["income_modeled"] + .sum() + .reset_index() + ) + household_income.rename(columns={"income_modeled": "hhlIncome"}, inplace=True) + # round hhlIncome to the nearest whole number + household_income["hhlIncome"] = household_income["hhlIncome"].round() + + # Merge the household_income data onto the individuals data + individuals_income = pd.merge( + individuals_income, + household_income, + how="left", + left_on="hid", + right_on="household", + ) + + individuals_income.drop(columns="household", inplace=True) + + return individuals_income From 3fe1494fe9e67bcd1f0286eb04d0585d707b9339 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:59:36 +0100 Subject: [PATCH 3/8] get correct cycle ownership column --- notebooks/2_match_households_and_individuals.ipynb | 4 ++-- scripts/2_match_households_and_individuals.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/notebooks/2_match_households_and_individuals.ipynb b/notebooks/2_match_households_and_individuals.ipynb index 871225b..94d53a1 100644 --- a/notebooks/2_match_households_and_individuals.ipynb +++ b/notebooks/2_match_households_and_individuals.ipynb @@ -487,7 +487,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -505,7 +505,7 @@ " 'EdAttn1_B01ID',\n", " 'EdAttn2_B01ID',\n", " 'EdAttn3_B01ID',\n", - " 'OwnCycle_B01ID', # Owns a cycle\n", + " 'OwnCycleN_B01ID', # Owns a cycle\n", " 'DrivLic_B02ID', # type of driving license\n", " 'CarAccess_B01ID',\n", " 'IndIncome2002_B02ID',\n", diff --git a/scripts/2_match_households_and_individuals.py b/scripts/2_match_households_and_individuals.py index e67deba..476d429 100644 --- a/scripts/2_match_households_and_individuals.py +++ b/scripts/2_match_households_and_individuals.py @@ -134,7 +134,7 @@ def get_interim_path( "EdAttn1_B01ID", "EdAttn2_B01ID", "EdAttn3_B01ID", - "OwnCycle_B01ID", # Owns a cycle + "OwnCycleN_B01ID", # Owns a cycle "DrivLic_B02ID", # type of driving license "CarAccess_B01ID", "IndIncome2002_B02ID", From 455e20183a42049db359314ed09e252488521483 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:06:09 +0100 Subject: [PATCH 4/8] add vehicle availability to individuals --- notebooks/6_acbm_to_matsim_xml.ipynb | 1428 ++++++++++++++++++++++++-- scripts/5_acbm_to_matsim_xml.py | 73 ++ 2 files changed, 1433 insertions(+), 68 deletions(-) diff --git a/notebooks/6_acbm_to_matsim_xml.ipynb b/notebooks/6_acbm_to_matsim_xml.ipynb index 47c2f8b..ef2713a 100644 --- a/notebooks/6_acbm_to_matsim_xml.ipynb +++ b/notebooks/6_acbm_to_matsim_xml.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 16, + "execution_count": 57, "metadata": {}, "outputs": [], "source": [ @@ -44,7 +44,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -58,16 +58,92 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "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", + "
pidhidfreqhzoneage_years
019989NaNE0200233039
120089NaNE0200233038
2312139NaNE0200233064
3610283NaNE0200233067
4611283NaNE0200233064
\n", + "
" + ], "text/plain": [ - "1709" + " pid hid freq hzone age_years\n", + "0 199 89 NaN E02002330 39\n", + "1 200 89 NaN E02002330 38\n", + "2 312 139 NaN E02002330 64\n", + "3 610 283 NaN E02002330 67\n", + "4 611 283 NaN E02002330 64" ] }, - "execution_count": 18, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -78,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -88,9 +164,188 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "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", + " \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", + "
idhouseholdage_yearsOA11CDnts_hh_idnts_ind_ideducation_typeTripIDTravDayseqmodeoactdacttsttetTripDisIncSWTripTotalTimeIndividualID
01998939E000590312.019001e+092019001326education_university2.019018e+093.01.0carhomeshop540.0555.02.015.02.019001e+09
11998939E000590312.019001e+092019001326education_university2.019018e+094.01.0car_passengerhomeother450.0480.020.030.02.019001e+09
21998939E000590312.019001e+092019001326education_university2.019018e+092.02.0carworkhome960.01020.025.060.02.019001e+09
31998939E000590312.019001e+092019001326education_university2.019018e+094.03.0carhomeshop960.0975.02.015.02.019001e+09
41998939E000590312.019001e+092019001326education_university2.019018e+097.02.0carworkhome1005.01065.025.060.02.019001e+09
\n", + "
" + ], + "text/plain": [ + " id household age_years OA11CD nts_hh_id nts_ind_id \\\n", + "0 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "1 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "2 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "3 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "4 199 89 39 E00059031 2.019001e+09 2019001326 \n", + "\n", + " education_type TripID TravDay seq mode oact \\\n", + "0 education_university 2.019018e+09 3.0 1.0 car home \n", + "1 education_university 2.019018e+09 4.0 1.0 car_passenger home \n", + "2 education_university 2.019018e+09 2.0 2.0 car work \n", + "3 education_university 2.019018e+09 4.0 3.0 car home \n", + "4 education_university 2.019018e+09 7.0 2.0 car work \n", + "\n", + " dact tst tet TripDisIncSW TripTotalTime IndividualID \n", + "0 shop 540.0 555.0 2.0 15.0 2.019001e+09 \n", + "1 other 450.0 480.0 20.0 30.0 2.019001e+09 \n", + "2 home 960.0 1020.0 25.0 60.0 2.019001e+09 \n", + "3 shop 960.0 975.0 2.0 15.0 2.019001e+09 \n", + "4 home 1005.0 1065.0 25.0 60.0 2.019001e+09 " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "spc_with_nts = pd.read_parquet(acbm.root_path / \"data/interim/matching/spc_with_nts_trips.parquet\")\n", "spc_with_nts.head(5)" @@ -98,7 +353,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -510,7 +765,7 @@ "[794639 rows x 38 columns]" ] }, - "execution_count": 19, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -522,9 +777,96 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "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", + "
idhouseholdage_yearssexsalary_yearly
00068maleNaN
11065femaleNaN
22186maleNaN
33258maleNaN
44256female36646.464844
\n", + "
" + ], + "text/plain": [ + " id household age_years sex salary_yearly\n", + "0 0 0 68 male NaN\n", + "1 1 0 65 female NaN\n", + "2 2 1 86 male NaN\n", + "3 3 2 58 male NaN\n", + "4 4 2 56 female 36646.464844" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# add sex column to individuals\n", "\n", @@ -542,67 +884,568 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "individuals = individuals.merge(spc[[\"id\", \"sex\"]], left_on=\"pid\", right_on=\"id\", how=\"left\")\n", - "individuals = individuals.drop(columns=\"id\")\n", - "individuals.head(5)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "individuals = get_passengers(\n", - " legs = legs, \n", - " individuals = individuals, \n", - " modes = ['car_passenger', 'taxi'])\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "individuals = get_pt_subscription(individuals = individuals, age_threshold = 66)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "individuals = get_students(\n", - " individuals = individuals,\n", - " activities = activities,\n", - " age_base_threshold = 16,\n", - " #age_upper_threshold = 30,\n", - " activity = 'education')\n", - "\n", - "individuals.head(10)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], - "source": [ - "# histogram of x by age and isStudent \n", - "individuals.groupby(['age', 'isStudent']).size().unstack().plot(kind='bar', stacked=True)\n" - ] + "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", + "
pidhidfreqhzoneagesex
019989NaNE0200233039male
120089NaNE0200233038female
2312139NaNE0200233064female
3610283NaNE0200233067female
4611283NaNE0200233064male
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age sex\n", + "0 199 89 NaN E02002330 39 male\n", + "1 200 89 NaN E02002330 38 female\n", + "2 312 139 NaN E02002330 64 female\n", + "3 610 283 NaN E02002330 67 female\n", + "4 611 283 NaN E02002330 64 male" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals = individuals.merge(spc[[\"id\", \"sex\"]], left_on=\"pid\", right_on=\"id\", how=\"left\")\n", + "individuals = individuals.drop(columns=\"id\")\n", + "individuals.head(5)" + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "individuals = get_passengers(\n", + " legs = legs, \n", + " individuals = individuals, \n", + " modes = ['car_passenger', 'taxi'])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, "metadata": {}, "outputs": [], + "source": [ + "individuals = get_pt_subscription(individuals = individuals, age_threshold = 66)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "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", + " \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", + "
pidhidfreqhzoneagesexisPassengerhasPTSubscriptionisStudent
019989NaNE0200233039maleFalseFalseFalse
120089NaNE0200233038femaleTrueFalseFalse
2312139NaNE0200233064femaleFalseFalseFalse
3610283NaNE0200233067femaleTrueTrueFalse
4611283NaNE0200233064maleFalseFalseFalse
5612283NaNE020023308maleTrueFalseTrue
6613283NaNE020023302femaleTrueFalseTrue
72016892NaNE0200233049maleTrueFalseFalse
82017892NaNE0200233048femaleFalseFalseFalse
92018892NaNE020023309maleTrueFalseTrue
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age sex isPassenger hasPTSubscription \\\n", + "0 199 89 NaN E02002330 39 male False False \n", + "1 200 89 NaN E02002330 38 female True False \n", + "2 312 139 NaN E02002330 64 female False False \n", + "3 610 283 NaN E02002330 67 female True True \n", + "4 611 283 NaN E02002330 64 male False False \n", + "5 612 283 NaN E02002330 8 male True False \n", + "6 613 283 NaN E02002330 2 female True False \n", + "7 2016 892 NaN E02002330 49 male True False \n", + "8 2017 892 NaN E02002330 48 female False False \n", + "9 2018 892 NaN E02002330 9 male True False \n", + "\n", + " isStudent \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "5 True \n", + "6 True \n", + "7 False \n", + "8 False \n", + "9 True " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "individuals = get_students(\n", + " individuals = individuals,\n", + " activities = activities,\n", + " age_base_threshold = 16,\n", + " #age_upper_threshold = 30,\n", + " activity = 'education')\n", + "\n", + "individuals.head(10)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# histogram of x by age and isStudent \n", + "individuals.groupby(['age', 'isStudent']).size().unstack().plot(kind='bar', stacked=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "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", + " \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", + "
pidhidfreqhzoneagesexisPassengerhasPTSubscriptionisStudenthhlIncome
019989NaNE0200233039maleFalseFalseFalse34167.0
120089NaNE0200233038femaleTrueFalseFalse34167.0
2312139NaNE0200233064femaleFalseFalseFalse22677.0
3610283NaNE0200233067femaleTrueTrueFalse13000.0
4611283NaNE0200233064maleFalseFalseFalse13000.0
5612283NaNE020023308maleTrueFalseTrue13000.0
6613283NaNE020023302femaleTrueFalseTrue13000.0
72016892NaNE0200233049maleTrueFalseFalse66666.0
82017892NaNE0200233048femaleFalseFalseFalse66666.0
92018892NaNE020023309maleTrueFalseTrue66666.0
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age sex isPassenger hasPTSubscription \\\n", + "0 199 89 NaN E02002330 39 male False False \n", + "1 200 89 NaN E02002330 38 female True False \n", + "2 312 139 NaN E02002330 64 female False False \n", + "3 610 283 NaN E02002330 67 female True True \n", + "4 611 283 NaN E02002330 64 male False False \n", + "5 612 283 NaN E02002330 8 male True False \n", + "6 613 283 NaN E02002330 2 female True False \n", + "7 2016 892 NaN E02002330 49 male True False \n", + "8 2017 892 NaN E02002330 48 female False False \n", + "9 2018 892 NaN E02002330 9 male True False \n", + "\n", + " isStudent hhlIncome \n", + "0 False 34167.0 \n", + "1 False 34167.0 \n", + "2 False 22677.0 \n", + "3 False 13000.0 \n", + "4 False 13000.0 \n", + "5 True 13000.0 \n", + "6 True 13000.0 \n", + "7 False 66666.0 \n", + "8 False 66666.0 \n", + "9 True 66666.0 " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "individuals = get_hhlIncome(\n", " individuals = individuals,\n", @@ -617,13 +1460,462 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Clean the data" + "### Add attributes to do with vehicle ownership \n", + "\n", + "These attributes are in the nts dataset. We will merge them onto the processed dataset\n", + "#TODO: move this upstream so that it is part of the individuals.csv output" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [], + "source": [ + "nts_individuals = pd.read_parquet(acbm.root_path / \"data/external/nts/filtered/nts_individuals.parquet\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Create a df with the vehicle ownership data (from the nts)" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "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", + "
IndividualIDCarAvailabilityBicycleAvailabilityhasLicence
02019002187yesyesTrue
12019002187yesyesTrue
22019002187yesyesTrue
32019002187yesyesTrue
42019002187yesyesTrue
52019002187yesyesTrue
62019002187yesyesTrue
72019002187yesyesTrue
82019002187yesyesTrue
92019002187yesyesTrue
\n", + "
" + ], + "text/plain": [ + " IndividualID CarAvailability BicycleAvailability hasLicence\n", + "0 2019002187 yes yes True\n", + "1 2019002187 yes yes True\n", + "2 2019002187 yes yes True\n", + "3 2019002187 yes yes True\n", + "4 2019002187 yes yes True\n", + "5 2019002187 yes yes True\n", + "6 2019002187 yes yes True\n", + "7 2019002187 yes yes True\n", + "8 2019002187 yes yes True\n", + "9 2019002187 yes yes True" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nts_individuals = nts_individuals[[\"IndividualID\", \"OwnCycleN_B01ID\", \"DrivLic_B02ID\", \"CarAccess_B01ID\"]]\n", + "\n", + "# Create CarAvailability colum\n", + "\n", + "car_availability_mapping = {\n", + " 1: \"yes\", # Main driver of company car\n", + " 2: \"yes\", # Other main driver\n", + " 3: \"some\", # Not main driver of household car\n", + " }\n", + "\n", + "nts_individuals['CarAvailability'] = nts_individuals['CarAccess_B01ID'].map(car_availability_mapping).fillna('no')\n", + "# Create BicycleAvailability column\n", + "\n", + "bicycle_availability_mapping = {\n", + " 1: \"yes\", # Own a pedal cycle yourself\n", + " 2: \"some\", # Have use of household pedal cycle\n", + " 3: \"no\", # Have use of non-household pedal cycle\n", + " }\n", + "\n", + "nts_individuals['BicycleAvailability'] = nts_individuals['OwnCycleN_B01ID'].map(bicycle_availability_mapping).fillna('no')\n", + "\n", + "# Create hasLicence column\n", + "# 1: Full licence, 2: Provisional licence, 3: Other or none\n", + "nts_individuals[\"hasLicence\"] = nts_individuals[\"DrivLic_B02ID\"].apply(lambda x: x == 1)\n", + "\n", + "# Keep only the columns we created\n", + "nts_individuals = nts_individuals[[\"IndividualID\", \"CarAvailability\", \"BicycleAvailability\", \"hasLicence\"]]\n", + "nts_individuals.head(10)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Merge the data onto the individuals df" ] }, { "cell_type": "code", "execution_count": null, "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", + " \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", + "
pidhidfreqhzoneagesexisPassengerhasPTSubscriptionisStudenthhlIncomeCarAvailabilityBicycleAvailabilityhasLicence
019989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
119989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
219989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
319989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
419989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
519989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
619989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
719989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
819989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
919989NaNE0200233039maleFalseFalseFalse34167.0yesyesTrue
\n", + "
" + ], + "text/plain": [ + " pid hid freq hzone age sex isPassenger hasPTSubscription \\\n", + "0 199 89 NaN E02002330 39 male False False \n", + "1 199 89 NaN E02002330 39 male False False \n", + "2 199 89 NaN E02002330 39 male False False \n", + "3 199 89 NaN E02002330 39 male False False \n", + "4 199 89 NaN E02002330 39 male False False \n", + "5 199 89 NaN E02002330 39 male False False \n", + "6 199 89 NaN E02002330 39 male False False \n", + "7 199 89 NaN E02002330 39 male False False \n", + "8 199 89 NaN E02002330 39 male False False \n", + "9 199 89 NaN E02002330 39 male False False \n", + "\n", + " isStudent hhlIncome CarAvailability BicycleAvailability hasLicence \n", + "0 False 34167.0 yes yes True \n", + "1 False 34167.0 yes yes True \n", + "2 False 34167.0 yes yes True \n", + "3 False 34167.0 yes yes True \n", + "4 False 34167.0 yes yes True \n", + "5 False 34167.0 yes yes True \n", + "6 False 34167.0 yes yes True \n", + "7 False 34167.0 yes yes True \n", + "8 False 34167.0 yes yes True \n", + "9 False 34167.0 yes yes True " + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# get spc id from spc_with_nts\n", + "nts_individuals = nts_individuals.merge(\n", + " spc_with_nts[[\"id\", \"nts_ind_id\"]], \n", + " left_on='IndividualID',\n", + " right_on='nts_ind_id', \n", + " how='inner').drop(columns=['nts_ind_id'])\n", + "\n", + "nts_individuals.rename(columns={\"id\": \"spc_id\"}, inplace=True)\n", + "nts_individuals.head(10)\n", + "\n", + "# merge vehicle ownership data onto individuals\n", + "individuals = individuals.merge(\n", + " nts_individuals, \n", + " left_on=\"pid\", \n", + " right_on=\"spc_id\", \n", + " how=\"left\").drop(columns= [\"spc_id\", \"IndividualID\"])\n", + "\n", + "individuals.head(10)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Clean the data" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, "outputs": [], "source": [ "# We will be removing some rows in each planning operation. This function helps keep a \n", diff --git a/scripts/5_acbm_to_matsim_xml.py b/scripts/5_acbm_to_matsim_xml.py index a4807ea..6837aca 100644 --- a/scripts/5_acbm_to_matsim_xml.py +++ b/scripts/5_acbm_to_matsim_xml.py @@ -101,6 +101,79 @@ def main(config_file): pension=config.postprocessing.state_pension, ) + # ----- Add vehicle ownership attributes (car, bicycle) to the individuals dataframe + # TODO: move this upstream + + # a. spc to nts match (used to get nts_id: spc_id match) + spc_with_nts = pd.read_parquet( + acbm.root_path / "data/interim/matching/spc_with_nts_trips.parquet" + ) + nts_individuals = pd.read_parquet( + acbm.root_path / "data/external/nts/filtered/nts_individuals.parquet" + ) + + # b. Create a df with the vehicle ownership data (from the nts) + + nts_individuals = nts_individuals[ + ["IndividualID", "OwnCycleN_B01ID", "DrivLic_B02ID", "CarAccess_B01ID"] + ] + + # Create CarAvailability colum + + car_availability_mapping = { + 1: "yes", # Main driver of company car + 2: "yes", # Other main driver + 3: "some", # Not main driver of household car + } + + nts_individuals["CarAvailability"] = ( + nts_individuals["CarAccess_B01ID"].map(car_availability_mapping).fillna("no") + ) + # Create BicycleAvailability column + + bicycle_availability_mapping = { + 1: "yes", # Own a pedal cycle yourself + 2: "some", # Have use of household pedal cycle + 3: "no", # Have use of non-household pedal cycle + } + + nts_individuals["BicycleAvailability"] = ( + nts_individuals["OwnCycleN_B01ID"] + .map(bicycle_availability_mapping) + .fillna("no") + ) + + # Create hasLicence column + # 1: Full licence, 2: Provisional licence, 3: Other or none + nts_individuals["hasLicence"] = nts_individuals["DrivLic_B02ID"].apply( + lambda x: x == 1 + ) + + # Keep only the columns we created + nts_individuals = nts_individuals[ + ["IndividualID", "CarAvailability", "BicycleAvailability", "hasLicence"] + ] + nts_individuals.head(10) + + # c. add spc id to nts_individuals + + # create a df with spc_id and nts_id + spcid_to_ntsid = spc_with_nts[ + ["id", "nts_ind_id"] + ].drop_duplicates() # spc_with_nts has one row per travel day + + # add the spc_id column + nts_individuals = nts_individuals.merge( + spcid_to_ntsid, left_on="IndividualID", right_on="nts_ind_id", how="inner" + ).drop(columns=["nts_ind_id"]) + + nts_individuals.rename(columns={"id": "spc_id"}, inplace=True) + + # d. merge nts_individuals with individuals to get the vehicle ownership data + individuals = individuals.merge( + nts_individuals, left_on="pid", right_on="spc_id", how="left" + ).drop(columns=["spc_id", "IndividualID"]) + # We will be removing some rows in each planning operation. This function helps keep a # record of the number of rows in each table after each operation. From d6dc8a52060f7ee157d5291bb3919f47171bb020 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:32:41 +0100 Subject: [PATCH 5/8] add individual attributes example --- notebooks/6_acbm_to_matsim_xml.ipynb | 1468 +++++++++++++++++++++++--- 1 file changed, 1296 insertions(+), 172 deletions(-) diff --git a/notebooks/6_acbm_to_matsim_xml.ipynb b/notebooks/6_acbm_to_matsim_xml.ipynb index ef2713a..1d941ad 100644 --- a/notebooks/6_acbm_to_matsim_xml.ipynb +++ b/notebooks/6_acbm_to_matsim_xml.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 57, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -1468,7 +1468,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -1484,7 +1484,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -1516,71 +1516,71 @@ " \n", " \n", " \n", - " 0\n", - " 2019002187\n", - " yes\n", - " yes\n", - " True\n", + " 340877\n", + " 2019006027\n", + " no\n", + " no\n", + " False\n", " \n", " \n", - " 1\n", - " 2019002187\n", - " yes\n", - " yes\n", - " True\n", + " 340878\n", + " 2019006028\n", + " no\n", + " no\n", + " False\n", " \n", " \n", - " 2\n", - " 2019002187\n", - " yes\n", - " yes\n", - " True\n", + " 340879\n", + " 2019006029\n", + " no\n", + " no\n", + " False\n", " \n", " \n", - " 3\n", - " 2019002187\n", - " yes\n", + " 340882\n", + " 2019002185\n", + " some\n", " yes\n", " True\n", " \n", " \n", - " 4\n", - " 2019002187\n", - " yes\n", + " 340883\n", + " 2019002186\n", + " some\n", " yes\n", " True\n", " \n", " \n", - " 5\n", + " 340884\n", " 2019002187\n", " yes\n", " yes\n", " True\n", " \n", " \n", - " 6\n", - " 2019002187\n", + " 340885\n", + " 2019002188\n", " yes\n", " yes\n", " True\n", " \n", " \n", - " 7\n", - " 2019002187\n", - " yes\n", - " yes\n", - " True\n", + " 340886\n", + " 2019002189\n", + " no\n", + " no\n", + " False\n", " \n", " \n", - " 8\n", - " 2019002187\n", + " 340887\n", + " 2019004751\n", " yes\n", " yes\n", " True\n", " \n", " \n", - " 9\n", - " 2019002187\n", + " 340888\n", + " 2019004752\n", " yes\n", " yes\n", " True\n", @@ -1590,20 +1590,20 @@ "" ], "text/plain": [ - " IndividualID CarAvailability BicycleAvailability hasLicence\n", - "0 2019002187 yes yes True\n", - "1 2019002187 yes yes True\n", - "2 2019002187 yes yes True\n", - "3 2019002187 yes yes True\n", - "4 2019002187 yes yes True\n", - "5 2019002187 yes yes True\n", - "6 2019002187 yes yes True\n", - "7 2019002187 yes yes True\n", - "8 2019002187 yes yes True\n", - "9 2019002187 yes yes True" + " IndividualID CarAvailability BicycleAvailability hasLicence\n", + "340877 2019006027 no no False\n", + "340878 2019006028 no no False\n", + "340879 2019006029 no no False\n", + "340882 2019002185 some yes True\n", + "340883 2019002186 some yes True\n", + "340884 2019002187 yes yes True\n", + "340885 2019002188 yes yes True\n", + "340886 2019002189 no no False\n", + "340887 2019004751 yes yes True\n", + "340888 2019004752 yes yes True" ] }, - "execution_count": 79, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -1646,9 +1646,334 @@ "### Merge the data onto the individuals df" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Create a 1:1 mapping of spc_id to nts_id" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idnts_ind_id
01992019001326
202002019001325
362012019001327
443122019003730
783132019003731
804252019014984
814262019014985
826102019002009
936112019002008
1276122019002010
1456132019002011
15720162019012822
17120172019012823
18320182019012824
19522702019004682
21722712019004683
23025612019014624
24425622019014625
25925822019006176
27825832019006177
\n", + "
" + ], + "text/plain": [ + " id nts_ind_id\n", + "0 199 2019001326\n", + "20 200 2019001325\n", + "36 201 2019001327\n", + "44 312 2019003730\n", + "78 313 2019003731\n", + "80 425 2019014984\n", + "81 426 2019014985\n", + "82 610 2019002009\n", + "93 611 2019002008\n", + "127 612 2019002010\n", + "145 613 2019002011\n", + "157 2016 2019012822\n", + "171 2017 2019012823\n", + "183 2018 2019012824\n", + "195 2270 2019004682\n", + "217 2271 2019004683\n", + "230 2561 2019014624\n", + "244 2562 2019014625\n", + "259 2582 2019006176\n", + "278 2583 2019006177" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "spcid_to_ntsid = spc_with_nts[['id', 'nts_ind_id']].drop_duplicates()\n", + "spcid_to_ntsid.head(20)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "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", + "
IndividualIDCarAvailabilityBicycleAvailabilityhasLicencespc_id
02019004751yesyesTrue111243
12019004752yesyesTrue111244
22019004753noyesFalse111245
32019004775yesnoTrue319239
42019004776yesnoTrue319240
52019004777yesnoTrue110871
62019004778yesnoTrue110870
72019004779nonoFalse110872
82019004780yesnoTrue659043
92019004781yesyesTrue611325
\n", + "
" + ], + "text/plain": [ + " IndividualID CarAvailability BicycleAvailability hasLicence spc_id\n", + "0 2019004751 yes yes True 111243\n", + "1 2019004752 yes yes True 111244\n", + "2 2019004753 no yes False 111245\n", + "3 2019004775 yes no True 319239\n", + "4 2019004776 yes no True 319240\n", + "5 2019004777 yes no True 110871\n", + "6 2019004778 yes no True 110870\n", + "7 2019004779 no no False 110872\n", + "8 2019004780 yes no True 659043\n", + "9 2019004781 yes yes True 611325" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# add spc id to nts_individuals\n", + "nts_individuals = nts_individuals.merge(\n", + " spcid_to_ntsid, \n", + " left_on='IndividualID',\n", + " right_on='nts_ind_id', \n", + " how='inner').drop(columns=['nts_ind_id'])\n", + "\n", + "nts_individuals.rename(columns={\"id\": \"spc_id\"}, inplace=True)\n", + "nts_individuals.head(10)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -1706,13 +2031,13 @@ " \n", " \n", " 1\n", - " 199\n", + " 200\n", " 89\n", " NaN\n", " E02002330\n", - " 39\n", - " male\n", - " False\n", + " 38\n", + " female\n", + " True\n", " False\n", " False\n", " 34167.0\n", @@ -1722,178 +2047,168 @@ " \n", " \n", " 2\n", - " 199\n", - " 89\n", + " 312\n", + " 139\n", " NaN\n", " E02002330\n", - " 39\n", - " male\n", + " 64\n", + " female\n", " False\n", " False\n", " False\n", - " 34167.0\n", - " yes\n", + " 22677.0\n", " yes\n", + " no\n", " True\n", " \n", " \n", " 3\n", - " 199\n", - " 89\n", + " 610\n", + " 283\n", " NaN\n", " E02002330\n", - " 39\n", - " male\n", - " False\n", + " 67\n", + " female\n", + " True\n", + " True\n", " False\n", + " 13000.0\n", + " no\n", + " no\n", " False\n", - " 34167.0\n", - " yes\n", - " yes\n", - " True\n", " \n", " \n", " 4\n", - " 199\n", - " 89\n", + " 611\n", + " 283\n", " NaN\n", " E02002330\n", - " 39\n", + " 64\n", " male\n", " False\n", " False\n", " False\n", - " 34167.0\n", + " 13000.0\n", " yes\n", " yes\n", " True\n", " \n", " \n", " 5\n", - " 199\n", - " 89\n", + " 612\n", + " 283\n", " NaN\n", " E02002330\n", - " 39\n", + " 8\n", " male\n", + " True\n", " False\n", - " False\n", - " False\n", - " 34167.0\n", - " yes\n", - " yes\n", " True\n", + " 13000.0\n", + " no\n", + " yes\n", + " False\n", " \n", " \n", " 6\n", - " 199\n", - " 89\n", + " 613\n", + " 283\n", " NaN\n", " E02002330\n", - " 39\n", - " male\n", - " False\n", - " False\n", + " 2\n", + " female\n", + " True\n", " False\n", - " 34167.0\n", - " yes\n", - " yes\n", " True\n", + " 13000.0\n", + " no\n", + " no\n", + " False\n", " \n", " \n", " 7\n", - " 199\n", - " 89\n", + " 2016\n", + " 892\n", " NaN\n", " E02002330\n", - " 39\n", + " 49\n", " male\n", + " True\n", " False\n", " False\n", - " False\n", - " 34167.0\n", + " 66666.0\n", " yes\n", " yes\n", " True\n", " \n", " \n", " 8\n", - " 199\n", - " 89\n", + " 2017\n", + " 892\n", " NaN\n", " E02002330\n", - " 39\n", - " male\n", + " 48\n", + " female\n", " False\n", " False\n", " False\n", - " 34167.0\n", - " yes\n", - " yes\n", - " True\n", + " 66666.0\n", + " no\n", + " no\n", + " False\n", " \n", " \n", " 9\n", - " 199\n", - " 89\n", + " 2018\n", + " 892\n", " NaN\n", " E02002330\n", - " 39\n", + " 9\n", " male\n", + " True\n", " False\n", - " False\n", - " False\n", - " 34167.0\n", - " yes\n", - " yes\n", " True\n", + " 66666.0\n", + " no\n", + " no\n", + " False\n", " \n", " \n", "\n", "" ], "text/plain": [ - " pid hid freq hzone age sex isPassenger hasPTSubscription \\\n", - "0 199 89 NaN E02002330 39 male False False \n", - "1 199 89 NaN E02002330 39 male False False \n", - "2 199 89 NaN E02002330 39 male False False \n", - "3 199 89 NaN E02002330 39 male False False \n", - "4 199 89 NaN E02002330 39 male False False \n", - "5 199 89 NaN E02002330 39 male False False \n", - "6 199 89 NaN E02002330 39 male False False \n", - "7 199 89 NaN E02002330 39 male False False \n", - "8 199 89 NaN E02002330 39 male False False \n", - "9 199 89 NaN E02002330 39 male False False \n", + " pid hid freq hzone age sex isPassenger hasPTSubscription \\\n", + "0 199 89 NaN E02002330 39 male False False \n", + "1 200 89 NaN E02002330 38 female True False \n", + "2 312 139 NaN E02002330 64 female False False \n", + "3 610 283 NaN E02002330 67 female True True \n", + "4 611 283 NaN E02002330 64 male False False \n", + "5 612 283 NaN E02002330 8 male True False \n", + "6 613 283 NaN E02002330 2 female True False \n", + "7 2016 892 NaN E02002330 49 male True False \n", + "8 2017 892 NaN E02002330 48 female False False \n", + "9 2018 892 NaN E02002330 9 male True False \n", "\n", - " isStudent hhlIncome CarAvailability BicycleAvailability hasLicence \n", - "0 False 34167.0 yes yes True \n", - "1 False 34167.0 yes yes True \n", - "2 False 34167.0 yes yes True \n", - "3 False 34167.0 yes yes True \n", - "4 False 34167.0 yes yes True \n", - "5 False 34167.0 yes yes True \n", - "6 False 34167.0 yes yes True \n", - "7 False 34167.0 yes yes True \n", - "8 False 34167.0 yes yes True \n", - "9 False 34167.0 yes yes True " + " isStudent hhlIncome CarAvailability BicycleAvailability hasLicence \n", + "0 False 34167.0 yes yes True \n", + "1 False 34167.0 yes yes True \n", + "2 False 22677.0 yes no True \n", + "3 False 13000.0 no no False \n", + "4 False 13000.0 yes yes True \n", + "5 True 13000.0 no yes False \n", + "6 True 13000.0 no no False \n", + "7 False 66666.0 yes yes True \n", + "8 False 66666.0 no no False \n", + "9 True 66666.0 no no False " ] }, - "execution_count": 80, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# get spc id from spc_with_nts\n", - "nts_individuals = nts_individuals.merge(\n", - " spc_with_nts[[\"id\", \"nts_ind_id\"]], \n", - " left_on='IndividualID',\n", - " right_on='nts_ind_id', \n", - " how='inner').drop(columns=['nts_ind_id'])\n", - "\n", - "nts_individuals.rename(columns={\"id\": \"spc_id\"}, inplace=True)\n", - "nts_individuals.head(10)\n", - "\n", "# merge vehicle ownership data onto individuals\n", "individuals = individuals.merge(\n", " nts_individuals, \n", @@ -1901,8 +2216,7 @@ " right_on=\"spc_id\", \n", " how=\"left\").drop(columns= [\"spc_id\", \"IndividualID\"])\n", "\n", - "individuals.head(10)\n", - "\n" + "individuals.head(10)" ] }, { @@ -1914,7 +2228,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -1937,7 +2251,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -1950,9 +2264,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[('0_initial', 'individuals', 2960),\n", + " ('0_initial', 'households', 1709),\n", + " ('0_initial', 'activities', 11357),\n", + " ('0_initial', 'legs', 8397),\n", + " ('0_initial', 'legs_geo', 8397)]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "row_counts" ] @@ -1968,7 +2297,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -2015,7 +2344,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -2028,27 +2357,395 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[('0_initial', 'individuals', 2960),\n", + " ('0_initial', 'households', 1709),\n", + " ('0_initial', 'activities', 11357),\n", + " ('0_initial', 'legs', 8397),\n", + " ('0_initial', 'legs_geo', 8397),\n", + " ('1_filter_by_pid', 'individuals', 2931),\n", + " ('1_filter_by_pid', 'households', 1696),\n", + " ('1_filter_by_pid', 'activities', 11328),\n", + " ('1_filter_by_pid', 'legs', 8397),\n", + " ('1_filter_by_pid', 'legs_geo', 8397)]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "row_counts" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[('0_initial', 'individuals', 2960),\n", + " ('0_initial', 'households', 1709),\n", + " ('0_initial', 'activities', 11357),\n", + " ('0_initial', 'legs', 8397),\n", + " ('0_initial', 'legs_geo', 8397),\n", + " ('1_filter_by_pid', 'individuals', 2931),\n", + " ('1_filter_by_pid', 'households', 1696),\n", + " ('1_filter_by_pid', 'activities', 11328),\n", + " ('1_filter_by_pid', 'legs', 8397),\n", + " ('1_filter_by_pid', 'legs_geo', 8397)]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "sorted(row_counts, key=lambda x: x[0])" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "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", + " \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", + " \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", + "
pidhidozonedzonepurporigin activitydestination activitymodeseqtsttetdurationstart_location_idend_location_idstart_location_geometry_wktend_location_geometry_wkt
5945492107E02002330E02006875otherhomeotherwalk1.01900-01-01 08:32:001900-01-01 09:05:000:33:00None156862412NonePOINT (-172747.9714739804 7132434.416198847)
6045502107E02002330E02002390otherhomeotherwalk1.01900-01-01 08:32:001900-01-01 09:05:000:33:00None859863886NonePOINT (-164145.12529813123 7133893.434519876)
9554862499E02002330E02002330homeeducationhomecar_passenger2.01900-01-01 15:25:001900-01-01 15:29:000:04:00None1328971154NonePOINT (-167258.92084511882 7143476.774006749)
136139755990E02002332E02002374shophomeshopcar_passenger1.01900-01-01 12:20:001900-01-01 12:25:000:05:00None944325256NonePOINT (-176622.00253619973 7134449.399056955)
138146256309E02002332E02002427otherhomeotherwalk1.01900-01-01 07:30:001900-01-01 08:00:000:30:00None1392368056NonePOINT (-164873.8980231174 7122957.632887748)
...................................................
8146750434320294NoneE02006852homeeducationhomewalk2.01900-01-01 15:30:001900-01-01 15:50:000:20:00None400341812NonePOINT (-175859.81928684 7137067.487501181)
8226757296322904NoneE02006852homeeducationhomecar_passenger2.01900-01-01 16:30:001900-01-01 16:33:000:03:00None893100964NonePOINT (-177193.1389936416 7138848.613389791)
8246761165324230NoneE02006861homeworkhomecar_passenger2.01900-01-01 16:30:001900-01-01 16:35:000:05:00None894561802NonePOINT (-175350.8653553922 7135901.867221266)
8281768117326237E02006861E02006875shophomeshoppt1.01900-01-01 11:56:001900-01-01 12:30:000:34:00None310161982NonePOINT (-170556.39694620587 7131821.287018999)
8329784710330759E02006875E02002347otherhomeotherwalk1.01900-01-01 09:00:001900-01-01 09:20:000:20:00None1083335384NonePOINT (-173477.85368187493 7141276.259348786)
\n", + "

364 rows × 16 columns

\n", + "
" + ], + "text/plain": [ + " pid hid ozone dzone purp origin activity \\\n", + "59 4549 2107 E02002330 E02006875 other home \n", + "60 4550 2107 E02002330 E02002390 other home \n", + "95 5486 2499 E02002330 E02002330 home education \n", + "136 13975 5990 E02002332 E02002374 shop home \n", + "138 14625 6309 E02002332 E02002427 other home \n", + "... ... ... ... ... ... ... \n", + "8146 750434 320294 None E02006852 home education \n", + "8226 757296 322904 None E02006852 home education \n", + "8246 761165 324230 None E02006861 home work \n", + "8281 768117 326237 E02006861 E02006875 shop home \n", + "8329 784710 330759 E02006875 E02002347 other home \n", + "\n", + " destination activity mode seq tst \\\n", + "59 other walk 1.0 1900-01-01 08:32:00 \n", + "60 other walk 1.0 1900-01-01 08:32:00 \n", + "95 home car_passenger 2.0 1900-01-01 15:25:00 \n", + "136 shop car_passenger 1.0 1900-01-01 12:20:00 \n", + "138 other walk 1.0 1900-01-01 07:30:00 \n", + "... ... ... ... ... \n", + "8146 home walk 2.0 1900-01-01 15:30:00 \n", + "8226 home car_passenger 2.0 1900-01-01 16:30:00 \n", + "8246 home car_passenger 2.0 1900-01-01 16:30:00 \n", + "8281 shop pt 1.0 1900-01-01 11:56:00 \n", + "8329 other walk 1.0 1900-01-01 09:00:00 \n", + "\n", + " tet duration start_location_id end_location_id \\\n", + "59 1900-01-01 09:05:00 0:33:00 None 156862412 \n", + "60 1900-01-01 09:05:00 0:33:00 None 859863886 \n", + "95 1900-01-01 15:29:00 0:04:00 None 1328971154 \n", + "136 1900-01-01 12:25:00 0:05:00 None 944325256 \n", + "138 1900-01-01 08:00:00 0:30:00 None 1392368056 \n", + "... ... ... ... ... \n", + "8146 1900-01-01 15:50:00 0:20:00 None 400341812 \n", + "8226 1900-01-01 16:33:00 0:03:00 None 893100964 \n", + "8246 1900-01-01 16:35:00 0:05:00 None 894561802 \n", + "8281 1900-01-01 12:30:00 0:34:00 None 310161982 \n", + "8329 1900-01-01 09:20:00 0:20:00 None 1083335384 \n", + "\n", + " start_location_geometry_wkt \\\n", + "59 None \n", + "60 None \n", + "95 None \n", + "136 None \n", + "138 None \n", + "... ... \n", + "8146 None \n", + "8226 None \n", + "8246 None \n", + "8281 None \n", + "8329 None \n", + "\n", + " end_location_geometry_wkt \n", + "59 POINT (-172747.9714739804 7132434.416198847) \n", + "60 POINT (-164145.12529813123 7133893.434519876) \n", + "95 POINT (-167258.92084511882 7143476.774006749) \n", + "136 POINT (-176622.00253619973 7134449.399056955) \n", + "138 POINT (-164873.8980231174 7122957.632887748) \n", + "... ... \n", + "8146 POINT (-175859.81928684 7137067.487501181) \n", + "8226 POINT (-177193.1389936416 7138848.613389791) \n", + "8246 POINT (-175350.8653553922 7135901.867221266) \n", + "8281 POINT (-170556.39694620587 7131821.287018999) \n", + "8329 POINT (-173477.85368187493 7141276.259348786) \n", + "\n", + "[364 rows x 16 columns]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# all rows where start_location_geometry_wkt is null\n", "legs_geo[legs_geo['start_location_geometry_wkt'].isnull()]\n", @@ -2066,9 +2763,337 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": {}, - "outputs": [], + "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", + " \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", + " \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", + "
pidhidozonedzonepurporigin activitydestination activitymodeseqtsttetdurationstart_location_idend_location_idstart_locend_loc
019989E02002330E02006875shophomeshopcar1.01900-01-01 09:00:001900-01-01 09:15:000:15:001328970162408195016POINT (-167397.56531315646 7143640.45559949)POINT (-171371.01028764987 7131169.312723003)
119989E02006875E02002330homeshophomecar2.01900-01-01 09:45:001900-01-01 10:00:000:15:004081950161328970162POINT (-171371.01028764987 7131169.312723003)POINT (-167397.56531315646 7143640.45559949)
220089E02002330E02006875shophomeshopcar_passenger1.01900-01-01 09:00:001900-01-01 09:15:000:15:00132897016254957076POINT (-167397.56531315646 7143640.45559949)POINT (-171754.62143938692 7132283.384033667)
320089E02006875E02002330homeshophomecar_passenger2.01900-01-01 09:45:001900-01-01 10:00:000:15:00549570761328970162POINT (-171754.62143938692 7132283.384033667)POINT (-167397.56531315646 7143640.45559949)
4312139E02002330E02002402otherhomeothercar1.01900-01-01 09:00:001900-01-01 09:07:000:07:00136415719823376925POINT (-165837.93994546734 7146289.198739764)POINT (-158590.10429323144 7132494.796008638)
...................................................
8392791889333558E02006876E02006875shophomeshopwalk1.01900-01-01 11:00:001900-01-01 11:45:000:45:0012344842261904725674POINT (-171040.97173284873 7127547.111372213)POINT (-172391.3534696827 7131595.359505144)
8393791889333558E02006875E02006876homeshophomecar_passenger2.01900-01-01 13:30:001900-01-01 13:50:000:20:0019047256741234484226POINT (-172391.3534696827 7131595.359505144)POINT (-171040.97173284873 7127547.111372213)
8394794272334647E02006876E02006875otherhomeothercar1.01900-01-01 11:00:001900-01-01 11:15:000:15:00123890187646375628POINT (-170465.43907988604 7128930.59006113)POINT (-172078.9593115899 7132361.310596656)
8395794272334647E02006875E02006876homeotherhomecar2.01900-01-01 12:40:001900-01-01 12:55:000:15:00463756281238901876POINT (-172078.9593115899 7132361.310596656)POINT (-170465.43907988604 7128930.59006113)
8396794273334647E02006876E02002337workhomeworkcar1.01900-01-01 09:20:001900-01-01 10:45:001:25:00123890187611990461POINT (-170465.43907988604 7128930.59006113)POINT (-190466.878660929 7146766.5424680635)
\n", + "

8397 rows × 16 columns

\n", + "
" + ], + "text/plain": [ + " pid hid ozone dzone purp origin activity \\\n", + "0 199 89 E02002330 E02006875 shop home \n", + "1 199 89 E02006875 E02002330 home shop \n", + "2 200 89 E02002330 E02006875 shop home \n", + "3 200 89 E02006875 E02002330 home shop \n", + "4 312 139 E02002330 E02002402 other home \n", + "... ... ... ... ... ... ... \n", + "8392 791889 333558 E02006876 E02006875 shop home \n", + "8393 791889 333558 E02006875 E02006876 home shop \n", + "8394 794272 334647 E02006876 E02006875 other home \n", + "8395 794272 334647 E02006875 E02006876 home other \n", + "8396 794273 334647 E02006876 E02002337 work home \n", + "\n", + " destination activity mode seq tst \\\n", + "0 shop car 1.0 1900-01-01 09:00:00 \n", + "1 home car 2.0 1900-01-01 09:45:00 \n", + "2 shop car_passenger 1.0 1900-01-01 09:00:00 \n", + "3 home car_passenger 2.0 1900-01-01 09:45:00 \n", + "4 other car 1.0 1900-01-01 09:00:00 \n", + "... ... ... ... ... \n", + "8392 shop walk 1.0 1900-01-01 11:00:00 \n", + "8393 home car_passenger 2.0 1900-01-01 13:30:00 \n", + "8394 other car 1.0 1900-01-01 11:00:00 \n", + "8395 home car 2.0 1900-01-01 12:40:00 \n", + "8396 work car 1.0 1900-01-01 09:20:00 \n", + "\n", + " tet duration start_location_id end_location_id \\\n", + "0 1900-01-01 09:15:00 0:15:00 1328970162 408195016 \n", + "1 1900-01-01 10:00:00 0:15:00 408195016 1328970162 \n", + "2 1900-01-01 09:15:00 0:15:00 1328970162 54957076 \n", + "3 1900-01-01 10:00:00 0:15:00 54957076 1328970162 \n", + "4 1900-01-01 09:07:00 0:07:00 1364157198 23376925 \n", + "... ... ... ... ... \n", + "8392 1900-01-01 11:45:00 0:45:00 1234484226 1904725674 \n", + "8393 1900-01-01 13:50:00 0:20:00 1904725674 1234484226 \n", + "8394 1900-01-01 11:15:00 0:15:00 1238901876 46375628 \n", + "8395 1900-01-01 12:55:00 0:15:00 46375628 1238901876 \n", + "8396 1900-01-01 10:45:00 1:25:00 1238901876 11990461 \n", + "\n", + " start_loc \\\n", + "0 POINT (-167397.56531315646 7143640.45559949) \n", + "1 POINT (-171371.01028764987 7131169.312723003) \n", + "2 POINT (-167397.56531315646 7143640.45559949) \n", + "3 POINT (-171754.62143938692 7132283.384033667) \n", + "4 POINT (-165837.93994546734 7146289.198739764) \n", + "... ... \n", + "8392 POINT (-171040.97173284873 7127547.111372213) \n", + "8393 POINT (-172391.3534696827 7131595.359505144) \n", + "8394 POINT (-170465.43907988604 7128930.59006113) \n", + "8395 POINT (-172078.9593115899 7132361.310596656) \n", + "8396 POINT (-170465.43907988604 7128930.59006113) \n", + "\n", + " end_loc \n", + "0 POINT (-171371.01028764987 7131169.312723003) \n", + "1 POINT (-167397.56531315646 7143640.45559949) \n", + "2 POINT (-171754.62143938692 7132283.384033667) \n", + "3 POINT (-167397.56531315646 7143640.45559949) \n", + "4 POINT (-158590.10429323144 7132494.796008638) \n", + "... ... \n", + "8392 POINT (-172391.3534696827 7131595.359505144) \n", + "8393 POINT (-171040.97173284873 7127547.111372213) \n", + "8394 POINT (-172078.9593115899 7132361.310596656) \n", + "8395 POINT (-170465.43907988604 7128930.59006113) \n", + "8396 POINT (-190466.878660929 7146766.5424680635) \n", + "\n", + "[8397 rows x 16 columns]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# TODO rename in 3.3_assign_facility_all script\n", "# rename start_location_geometry_wkt and end_location_geometry_wkt to start_loc and end_loc\n", @@ -2085,7 +3110,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -2155,7 +3180,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ @@ -2168,18 +3193,65 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[('0_initial', 'individuals', 2960),\n", + " ('0_initial', 'households', 1709),\n", + " ('0_initial', 'activities', 11357),\n", + " ('0_initial', 'legs', 8397),\n", + " ('0_initial', 'legs_geo', 8397),\n", + " ('1_filter_by_pid', 'individuals', 2931),\n", + " ('1_filter_by_pid', 'households', 1696),\n", + " ('1_filter_by_pid', 'activities', 11328),\n", + " ('1_filter_by_pid', 'legs', 8397),\n", + " ('1_filter_by_pid', 'legs_geo', 8397),\n", + " ('2_filter_no_location', 'individuals', 2623),\n", + " ('2_filter_no_location', 'households', 1585),\n", + " ('2_filter_no_location', 'activities', 10258),\n", + " ('2_filter_no_location', 'legs', 7635),\n", + " ('2_filter_no_location', 'legs_geo', 7635)]" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "row_counts" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0_initial - activities - 11357 rows: 100.0% rows remaining\n", + "1_filter_by_pid - activities - 11328 rows: 99.7% rows remaining\n", + "2_filter_no_location - activities - 10258 rows: 90.3% rows remaining\n", + "0_initial - households - 1709 rows: 100.0% rows remaining\n", + "1_filter_by_pid - households - 1696 rows: 99.2% rows remaining\n", + "2_filter_no_location - households - 1585 rows: 92.7% rows remaining\n", + "0_initial - individuals - 2960 rows: 100.0% rows remaining\n", + "1_filter_by_pid - individuals - 2931 rows: 99.0% rows remaining\n", + "2_filter_no_location - individuals - 2623 rows: 88.6% rows remaining\n", + "0_initial - legs - 8397 rows: 100.0% rows remaining\n", + "1_filter_by_pid - legs - 8397 rows: 100.0% rows remaining\n", + "2_filter_no_location - legs - 7635 rows: 90.9% rows remaining\n", + "0_initial - legs_geo - 8397 rows: 100.0% rows remaining\n", + "1_filter_by_pid - legs_geo - 8397 rows: 100.0% rows remaining\n", + "2_filter_no_location - legs_geo - 7635 rows: 90.9% rows remaining\n" + ] + } + ], "source": [ "def calculate_percentage_remaining(row_counts):\n", " \"\"\"\n", @@ -2232,9 +3304,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3327128/1617488548.py:8: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " legs_geo[\"start_loc\"] = legs_geo[\"start_loc\"].apply(convert_to_point)\n", + "/tmp/ipykernel_3327128/1617488548.py:9: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " legs_geo[\"end_loc\"] = legs_geo[\"end_loc\"].apply(convert_to_point)\n" + ] + } + ], "source": [ "# Function to convert to Point if not already a Point\n", "def convert_to_point(value):\n", @@ -2262,7 +3360,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": {}, "outputs": [], "source": [ @@ -2328,9 +3426,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "Using simple trip based purpose parser, this assumes first activity is 'home'.\n", + "If you do not wish to assume this, try setting 'tour_based' = True (default).\n", + "\n", + "Using freq of 'None' for all trips.\n" + ] + } + ], "source": [ "population = load_travel_diary(\n", " trips=legs_geo,\n", @@ -2344,9 +3454,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Person: 200\n", + "{'hzone': 'E02002330', 'age': 38, 'sex': 'female', 'isPassenger': True, 'hasPTSubscription': False, 'isStudent': False, 'hhlIncome': 34167.0, 'CarAvailability': 'yes', 'BicycleAvailability': 'yes', 'hasLicence': True}\n", + "0:\tActivity(act:home, location:POINT (-167397.56531315646 7143640.45559949), time:00:00:00 --> 09:00:00, duration:9:00:00)\n", + "1:\tLeg(mode:car_passenger, area:POINT (-167397.56531315646 7143640.45559949) --> POINT (-171754.62143938692 7132283.384033667), time:09:00:00 --> 09:15:00, duration:0:15:00)\n", + "2:\tActivity(act:shop, location:POINT (-171754.62143938692 7132283.384033667), time:09:15:00 --> 09:45:00, duration:0:30:00)\n", + "3:\tLeg(mode:car_passenger, area:POINT (-171754.62143938692 7132283.384033667) --> POINT (-167397.56531315646 7143640.45559949), time:09:45:00 --> 10:00:00, duration:0:15:00)\n", + "4:\tActivity(act:home, location:POINT (-167397.56531315646 7143640.45559949), time:10:00:00 --> 00:00:00, duration:14:00:00)\n" + ] + } + ], "source": [ "population[89][200].print()" ] From 8d4b017e2b4a12e121c46c47f9d5496e352d9599 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:42:17 +0100 Subject: [PATCH 6/8] add taxi mode --- .../2_match_households_and_individuals.ipynb | 346 +++++++++--------- scripts/2_match_households_and_individuals.py | 2 +- scripts/3.2.2_assign_primary_zone_work.py | 2 +- scripts/run_pipeline.sh | 6 +- src/acbm/assigning/select_zone_primary.py | 2 +- src/acbm/assigning/utils.py | 2 + 6 files changed, 181 insertions(+), 179 deletions(-) diff --git a/notebooks/2_match_households_and_individuals.ipynb b/notebooks/2_match_households_and_individuals.ipynb index 94d53a1..50c7578 100644 --- a/notebooks/2_match_households_and_individuals.ipynb +++ b/notebooks/2_match_households_and_individuals.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -64,17 +64,17 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# useful variables\n", - "region = \"west-yorkshire\"" + "region = \"leeds\"" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -144,121 +144,121 @@ " 0\n", " 0\n", " NaN\n", - " {'concert_f': 1.2791347489984115e-31, 'concert...\n", - " [1583, 13161]\n", - " [1582, 13160]\n", - " E02002183_0001_001\n", - " 11291218\n", - " 1\n", - " 2905399\n", - " E02002183\n", - " E00053954\n", - " [0]\n", - " 24.879356\n", - " False\n", + " {'concert_f': 3.6287833784528047e-16, 'concert...\n", + " [954, 1037, 1234, 2981, 6290, 9535, 10385, 106...\n", + " [955, 1036, 1235, 2980, 6291, 9536, 10384, 106...\n", + " E02002330_0001_001\n", + " 34051017\n", + " 1\n", + " 2911721\n", + " E02002330\n", + " E00059034\n", + " [0, 1]\n", + " 27.506445\n", " False\n", " False\n", + " True\n", " NaN\n", - " 3.0\n", " 2.0\n", - " J\n", - " 58.0\n", - " 1115.0\n", + " 4.0\n", + " Q\n", + " 88.0\n", + " 1184.0\n", " 6\n", " NaN\n", " NaN\n", - " E02002183_0001\n", + " E02002330_0001\n", " 1.0\n", - " 1.0\n", - " NaN\n", " 2.0\n", + " NaN\n", + " 6.0\n", " True\n", " 2.0\n", " 2\n", " 1\n", - " 86\n", + " 68\n", " 1\n", " 1.0\n", " \n", " \n", " 1\n", " 1\n", - " 1\n", + " 0\n", " NaN\n", - " {'concert_f': 9.743248151956307e-21, 'concert_...\n", - " [2900, 4948, 4972, 7424, 10284, 10586, 12199, ...\n", - " [2901, 4949, 4973, 7425, 10285, 10585, 12198, ...\n", - " E02002183_0002_001\n", - " 17291219\n", - " 1\n", - " 2905308\n", - " E02002183\n", - " E00053953\n", - " [1, 2]\n", - " 27.491207\n", - " False\n", + " {'concert_f': 9.903925281880971e-14, 'concert_...\n", + " [3435, 6069, 13203, 14704]\n", + " [3436, 6068, 13202, 14703]\n", + " E02002330_0001_002\n", + " 21040818\n", + " 1\n", + " 2904618\n", + " E02002330\n", + " E00059034\n", + " [0, 1]\n", + " 30.527805\n", + " True\n", " False\n", " True\n", - " NaN\n", + " 7.0\n", + " 2.0\n", " 3.0\n", - " NaN\n", - " C\n", - " 25.0\n", - " 1121.0\n", + " I\n", + " 56.0\n", + " 5434.0\n", " 6\n", " NaN\n", " NaN\n", - " E02002183_0002\n", + " E02002330_0001\n", " 1.0\n", - " 3.0\n", + " 2.0\n", " NaN\n", " 6.0\n", " True\n", " 2.0\n", " 2\n", + " 2\n", + " 65\n", " 1\n", - " 74\n", - " 3\n", - " 1.0\n", + " 6.0\n", " \n", " \n", " 2\n", " 2\n", " 1\n", " NaN\n", - " {'concert_f': 8.46716103992468e-16, 'concert_f...\n", - " [3010, 6389, 9448, 10184, 11598]\n", - " [3011, 6388, 9447, 10183, 11599]\n", - " E02002183_0002_002\n", - " 17070713\n", - " 2\n", - " 2907681\n", - " E02002183\n", - " E00053953\n", - " [1, 2]\n", - " 17.310829\n", + " {'concert_f': 1.2791347489984115e-31, 'concert...\n", + " [762, 5168, 6201, 8977]\n", + " [761, 5169, 6200, 8976]\n", + " E02002330_0002_001\n", + " 11131017\n", + " 1\n", + " 2902311\n", + " E02002330\n", + " E00059022\n", + " [2]\n", + " 22.261669\n", + " False\n", + " False\n", " False\n", - " True\n", - " True\n", " NaN\n", " 2.0\n", - " 4.0\n", - " P\n", - " 85.0\n", - " 2311.0\n", + " 3.0\n", + " Q\n", + " 86.0\n", + " 2211.0\n", " 6\n", " NaN\n", " NaN\n", - " E02002183_0002\n", + " E02002330_0002\n", + " 2.0\n", " 1.0\n", - " 3.0\n", " NaN\n", - " 6.0\n", + " 5.0\n", " True\n", - " 2.0\n", - " 2\n", + " 1.0\n", " 2\n", - " 68\n", + " 1\n", + " 86\n", " 1\n", " 2.0\n", " \n", @@ -266,40 +266,40 @@ " 3\n", " 3\n", " 2\n", - " 56126.0\n", - " {'concert_f': 1.8844366073608398, 'concert_fs'...\n", - " [366, 867, 2096, 3678, 5212, 5450, 8145, 9254,...\n", - " [365, 868, 2097, 3677, 5213, 5451, 8146, 9253,...\n", - " E02002183_0003_001\n", - " 20310313\n", - " 1\n", - " 2902817\n", - " E02002183\n", - " E00053689\n", - " [3, 4]\n", - " 20.852091\n", + " NaN\n", + " {'concert_f': 7.754311082130982e-10, 'concert_...\n", + " [1580, 5417, 5956, 12901]\n", + " [1581, 5416, 5957, 12900]\n", + " E02002330_0003_001\n", + " 15020311\n", + " 1\n", + " 2911131\n", + " E02002330\n", + " E00059022\n", + " [3, 4, 5]\n", + " 21.434204\n", " False\n", " False\n", " False\n", " NaN\n", - " 2.0\n", " 1.0\n", - " C\n", - " 31.0\n", - " 3422.0\n", - " 1\n", - " 32857.859375\n", - " 14.360952\n", - " E02002183_0003\n", - " 4.0\n", " 3.0\n", + " O\n", + " 84.0\n", + " 3314.0\n", + " 6\n", + " NaN\n", + " NaN\n", + " E02002330_0003\n", + " 4.0\n", + " 1.0\n", " NaN\n", " 6.0\n", " True\n", " 2.0\n", " 1\n", " 1\n", - " 27\n", + " 58\n", " 1\n", " 4.0\n", " \n", @@ -307,42 +307,42 @@ " 4\n", " 4\n", " 2\n", - " NaN\n", - " {'concert_f': 4.877435207366943, 'concert_fs':...\n", - " [1289, 12528, 12870]\n", - " [1288, 12529, 12871]\n", - " E02002183_0003_002\n", - " 13010909\n", - " 3\n", - " 2900884\n", - " E02002183\n", - " E00053689\n", - " [3, 4]\n", - " 20.032526\n", - " False\n", + " 508.0\n", + " {'concert_f': 2.1388457227544677e-08, 'concert...\n", + " [318, 3145, 10496, 12819, 13943]\n", + " [319, 3144, 10495, 12818, 13942]\n", + " E02002330_0003_002\n", + " 20090607\n", + " 1\n", + " 2909582\n", + " E02002330\n", + " E00059022\n", + " [3, 4, 5]\n", + " 12.644703\n", " False\n", " False\n", - " 1.0\n", - " 2.0\n", + " True\n", + " NaN\n", " 3.0\n", - " J\n", - " 62.0\n", - " 7214.0\n", + " 2.0\n", + " O\n", + " 84.0\n", + " 1131.0\n", " 1\n", - " 18162.451172\n", - " 9.439944\n", - " E02002183_0003\n", + " 36646.464844\n", + " 19.576103\n", + " E02002330_0003\n", " 4.0\n", - " 3.0\n", + " 1.0\n", " NaN\n", " 6.0\n", " True\n", " 2.0\n", " 1\n", " 2\n", - " 26\n", + " 56\n", " 1\n", - " 6.0\n", + " 1.0\n", " \n", " \n", "\n", @@ -351,76 +351,76 @@ "text/plain": [ " id household workplace \\\n", "0 0 0 NaN \n", - "1 1 1 NaN \n", + "1 1 0 NaN \n", "2 2 1 NaN \n", - "3 3 2 56126.0 \n", - "4 4 2 NaN \n", + "3 3 2 NaN \n", + "4 4 2 508.0 \n", "\n", " events \\\n", - "0 {'concert_f': 1.2791347489984115e-31, 'concert... \n", - "1 {'concert_f': 9.743248151956307e-21, 'concert_... \n", - "2 {'concert_f': 8.46716103992468e-16, 'concert_f... \n", - "3 {'concert_f': 1.8844366073608398, 'concert_fs'... \n", - "4 {'concert_f': 4.877435207366943, 'concert_fs':... \n", + "0 {'concert_f': 3.6287833784528047e-16, 'concert... \n", + "1 {'concert_f': 9.903925281880971e-14, 'concert_... \n", + "2 {'concert_f': 1.2791347489984115e-31, 'concert... \n", + "3 {'concert_f': 7.754311082130982e-10, 'concert_... \n", + "4 {'concert_f': 2.1388457227544677e-08, 'concert... \n", "\n", " weekday_diaries \\\n", - "0 [1583, 13161] \n", - "1 [2900, 4948, 4972, 7424, 10284, 10586, 12199, ... \n", - "2 [3010, 6389, 9448, 10184, 11598] \n", - "3 [366, 867, 2096, 3678, 5212, 5450, 8145, 9254,... \n", - "4 [1289, 12528, 12870] \n", + "0 [954, 1037, 1234, 2981, 6290, 9535, 10385, 106... \n", + "1 [3435, 6069, 13203, 14704] \n", + "2 [762, 5168, 6201, 8977] \n", + "3 [1580, 5417, 5956, 12901] \n", + "4 [318, 3145, 10496, 12819, 13943] \n", "\n", " weekend_diaries orig_pid \\\n", - "0 [1582, 13160] E02002183_0001_001 \n", - "1 [2901, 4949, 4973, 7425, 10285, 10585, 12198, ... E02002183_0002_001 \n", - "2 [3011, 6388, 9447, 10183, 11599] E02002183_0002_002 \n", - "3 [365, 868, 2097, 3677, 5213, 5451, 8146, 9253,... E02002183_0003_001 \n", - "4 [1288, 12529, 12871] E02002183_0003_002 \n", + "0 [955, 1036, 1235, 2980, 6291, 9536, 10384, 106... E02002330_0001_001 \n", + "1 [3436, 6068, 13202, 14703] E02002330_0001_002 \n", + "2 [761, 5169, 6200, 8976] E02002330_0002_001 \n", + "3 [1581, 5416, 5957, 12900] E02002330_0003_001 \n", + "4 [319, 3144, 10495, 12818, 13942] E02002330_0003_002 \n", "\n", - " id_tus_hh id_tus_p pid_hs msoa11cd oa11cd members bmi \\\n", - "0 11291218 1 2905399 E02002183 E00053954 [0] 24.879356 \n", - "1 17291219 1 2905308 E02002183 E00053953 [1, 2] 27.491207 \n", - "2 17070713 2 2907681 E02002183 E00053953 [1, 2] 17.310829 \n", - "3 20310313 1 2902817 E02002183 E00053689 [3, 4] 20.852091 \n", - "4 13010909 3 2900884 E02002183 E00053689 [3, 4] 20.032526 \n", + " id_tus_hh id_tus_p pid_hs msoa11cd oa11cd members bmi \\\n", + "0 34051017 1 2911721 E02002330 E00059034 [0, 1] 27.506445 \n", + "1 21040818 1 2904618 E02002330 E00059034 [0, 1] 30.527805 \n", + "2 11131017 1 2902311 E02002330 E00059022 [2] 22.261669 \n", + "3 15020311 1 2911131 E02002330 E00059022 [3, 4, 5] 21.434204 \n", + "4 20090607 1 2909582 E02002330 E00059022 [3, 4, 5] 12.644703 \n", "\n", " has_cardiovascular_disease has_diabetes has_high_blood_pressure \\\n", - "0 False False False \n", - "1 False False True \n", - "2 False True True \n", + "0 False False True \n", + "1 True False True \n", + "2 False False False \n", "3 False False False \n", - "4 False False False \n", + "4 False False True \n", "\n", " number_medications self_assessed_health life_satisfaction sic1d2007 \\\n", - "0 NaN 3.0 2.0 J \n", - "1 NaN 3.0 NaN C \n", - "2 NaN 2.0 4.0 P \n", - "3 NaN 2.0 1.0 C \n", - "4 1.0 2.0 3.0 J \n", + "0 NaN 2.0 4.0 Q \n", + "1 7.0 2.0 3.0 I \n", + "2 NaN 2.0 3.0 Q \n", + "3 NaN 1.0 3.0 O \n", + "4 NaN 3.0 2.0 O \n", "\n", " sic2d2007 soc2010 pwkstat salary_yearly salary_hourly hid \\\n", - "0 58.0 1115.0 6 NaN NaN E02002183_0001 \n", - "1 25.0 1121.0 6 NaN NaN E02002183_0002 \n", - "2 85.0 2311.0 6 NaN NaN E02002183_0002 \n", - "3 31.0 3422.0 1 32857.859375 14.360952 E02002183_0003 \n", - "4 62.0 7214.0 1 18162.451172 9.439944 E02002183_0003 \n", + "0 88.0 1184.0 6 NaN NaN E02002330_0001 \n", + "1 56.0 5434.0 6 NaN NaN E02002330_0001 \n", + "2 86.0 2211.0 6 NaN NaN E02002330_0002 \n", + "3 84.0 3314.0 6 NaN NaN E02002330_0003 \n", + "4 84.0 1131.0 1 36646.464844 19.576103 E02002330_0003 \n", "\n", " nssec8 accommodation_type communal_type num_rooms central_heat tenure \\\n", - "0 1.0 1.0 NaN 2.0 True 2.0 \n", - "1 1.0 3.0 NaN 6.0 True 2.0 \n", - "2 1.0 3.0 NaN 6.0 True 2.0 \n", - "3 4.0 3.0 NaN 6.0 True 2.0 \n", - "4 4.0 3.0 NaN 6.0 True 2.0 \n", + "0 1.0 2.0 NaN 6.0 True 2.0 \n", + "1 1.0 2.0 NaN 6.0 True 2.0 \n", + "2 2.0 1.0 NaN 5.0 True 1.0 \n", + "3 4.0 1.0 NaN 6.0 True 2.0 \n", + "4 4.0 1.0 NaN 6.0 True 2.0 \n", "\n", " num_cars sex age_years ethnicity nssec8_household \n", - "0 2 1 86 1 1.0 \n", - "1 2 1 74 3 1.0 \n", - "2 2 2 68 1 2.0 \n", - "3 1 1 27 1 4.0 \n", - "4 1 2 26 1 6.0 " + "0 2 1 68 1 1.0 \n", + "1 2 2 65 1 6.0 \n", + "2 2 1 86 1 2.0 \n", + "3 1 1 58 1 4.0 \n", + "4 1 2 56 1 1.0 " ] }, - "execution_count": 3, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -433,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -447,7 +447,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -470,7 +470,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -487,7 +487,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -539,7 +539,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -587,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -635,11 +635,11 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "years = [2018, 2019, 2021, 2022]\n", + "years = [2019, 2021, 2022]\n", "\n", "nts_individuals = nts_filter_by_year(nts_individuals, psu, years)\n", "nts_households = nts_filter_by_year(nts_households, psu, years)\n", diff --git a/scripts/2_match_households_and_individuals.py b/scripts/2_match_households_and_individuals.py index 476d429..864a999 100644 --- a/scripts/2_match_households_and_individuals.py +++ b/scripts/2_match_households_and_individuals.py @@ -1040,7 +1040,7 @@ def get_interim_path( 9: "pt", #'Non-local bus', 10: "pt", #'London Underground', 11: "pt", #'Surface Rail', - 12: "car_passenger", #'Taxi/minicab', + 12: "taxi", #'Taxi/minicab', 13: "pt", #'Other public transport', -10: "DEAD", -8: "NA", diff --git a/scripts/3.2.2_assign_primary_zone_work.py b/scripts/3.2.2_assign_primary_zone_work.py index 66ad872..47b964f 100644 --- a/scripts/3.2.2_assign_primary_zone_work.py +++ b/scripts/3.2.2_assign_primary_zone_work.py @@ -101,7 +101,7 @@ def main(config_file): "Train": "pt", "Underground, metro, light rail, tram": "pt", "On foot": "walk", - "Taxi": "car_passenger", + "Taxi": "taxi", "Other method of travel to work": "other", "Bicycle": "cycle", "Passenger in a car or van": "car_passenger", diff --git a/scripts/run_pipeline.sh b/scripts/run_pipeline.sh index 025ed8c..9da0845 100755 --- a/scripts/run_pipeline.sh +++ b/scripts/run_pipeline.sh @@ -2,9 +2,9 @@ set -e -python scripts/0_preprocess_inputs.py --config_file $1 -python scripts/0.1_run_osmox.py --config_file $1 -python scripts/1_prep_synthpop.py --config_file $1 +# python scripts/0_preprocess_inputs.py --config_file $1 +# python scripts/0.1_run_osmox.py --config_file $1 +# python scripts/1_prep_synthpop.py --config_file $1 python scripts/2_match_households_and_individuals.py --config_file $1 python scripts/3.1_assign_primary_feasible_zones.py --config_file $1 python scripts/3.2.1_assign_primary_zone_edu.py --config_file $1 diff --git a/src/acbm/assigning/select_zone_primary.py b/src/acbm/assigning/select_zone_primary.py index 7b63435..e2b5877 100644 --- a/src/acbm/assigning/select_zone_primary.py +++ b/src/acbm/assigning/select_zone_primary.py @@ -241,7 +241,7 @@ def _get_zones_using_time_estimate( The zone that has the estimated time closest to the given time. """ - acceptable_modes = ["car", "car_passenger", "pt", "walk", "cycle"] + acceptable_modes = ["car", "car_passenger", "pt", "walk", "cycle", "taxi"] if mode is not None and mode not in acceptable_modes: error_message = f"Invalid mode: {mode}. Mode must be one of {acceptable_modes}." diff --git a/src/acbm/assigning/utils.py b/src/acbm/assigning/utils.py index 2f6caaf..27d9ce7 100644 --- a/src/acbm/assigning/utils.py +++ b/src/acbm/assigning/utils.py @@ -334,6 +334,7 @@ def zones_to_time_matrix( mode_speeds_mps = { "car": 20 * 1000 / 3600, "car_passenger": 20 * 1000 / 3600, + "taxi": 20 * 1000 / 3600, "pt": 15 * 1000 / 3600, "cycle": 15 * 1000 / 3600, "walk": 5 * 1000 / 3600, @@ -452,6 +453,7 @@ def intrazone_time(zones: gpd.GeoDataFrame, key_column: str) -> dict: mode_speeds_mps = { "car": 20 * 1000 / 3600, "car_passenger": 20 * 1000 / 3600, + "taxi": 20 * 1000 / 3600, "pt": 15 * 1000 / 3600, "cycle": 15 * 1000 / 3600, "walk": 5 * 1000 / 3600, From e7b375c0cf27bd272dddf9d1376ab67c14212406 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:46:44 +0100 Subject: [PATCH 7/8] edit optional type --- src/acbm/postprocessing/matsim.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/acbm/postprocessing/matsim.py b/src/acbm/postprocessing/matsim.py index b8d67c2..fd99b4c 100644 --- a/src/acbm/postprocessing/matsim.py +++ b/src/acbm/postprocessing/matsim.py @@ -1,5 +1,3 @@ -from typing import Optional - import numpy as np import pandas as pd @@ -282,8 +280,8 @@ def get_pt_subscription(individuals: pd.DataFrame, age_threshold=60): def get_students( individuals: pd.DataFrame, activities: pd.DataFrame, - age_base_threshold: Optional[int] = None, - age_upper_threshold: Optional[int] = None, + age_base_threshold: int | None = None, + age_upper_threshold: int | None = None, activity: str = "education", ) -> pd.DataFrame: """ From 4cde9a3982a070ee9e0016cc01b6251eb3aabd65 Mon Sep 17 00:00:00 2001 From: Hussein Mahfouz <45176416+Hussein-Mahfouz@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:54:46 +0100 Subject: [PATCH 8/8] update config template --- config/README.md | 63 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/config/README.md b/config/README.md index c1bf75e..8794cb9 100644 --- a/config/README.md +++ b/config/README.md @@ -3,31 +3,74 @@ The config.toml file has an explanation for each parameter. You can copy the tom ``` toml [parameters] seed = 0 -region = "leeds" # this is used to query poi data from osm and to load in SPC data -number_of_households = 5000 # how many people from the SPC do we want to run the model for? Comment out if you want to run the analysis on the entire SPC populaiton -zone_id = "OA21CD" # "OA21CD": OA level, "MSOA11CD": MSOA level -travel_times = true # Only set to true if you have travel time matrix at the level specified in boundary_geography -boundary_geography = "OA" + # this is used to query poi data from osm and to load in SPC data +region = "leeds" +# how many people from the SPC do we want to run the model for? Comment out if you want to run the analysis on the entire SPC populaiton +number_of_households = 2500 +# "OA21CD": OA level, "MSOA11CD": MSOA level +zone_id = "MSOA21CD" + # Only set to true if you have travel time matrix at the level specified in boundary_geography +travel_times = false +boundary_geography = "MSOA" +# NTS years to use +nts_years = [2019, 2021, 2022] +# NTS regions to use +nts_regions = [ + 'Yorkshire and the Humber', + 'North West', + 'North East', + 'East Midlands', + 'West Midlands', + 'East of England', + 'South East', + 'South West'] +# nts day of the week to use +# 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday, 7: Sunday +nts_day_of_week = 3 +# what crs do we want the output to be in? (just add the number, e.g. 3857) +output_crs = 3857 [matching] # for optional and required columns, see the [iterative_match_categorical](https://github.com/Urban-Analytics-Technology-Platform/acbm/blob/ca181c54d7484ebe44706ff4b43c26286b22aceb/src/acbm/matching.py#L110) function # Do not add any column not listed below. You can only move a column from optional to require (or vise versa) -required_columns = ["number_adults", "number_children"] +required_columns = [ + "number_adults", + "number_children", + "num_pension_age", +] optional_columns = [ "number_cars", - "num_pension_age", "rural_urban_2_categories", "employment_status", "tenure_status", ] -n_matches = 10 # What is the maximum number of NTS matches we want for each SPC household? +# What is the maximum number of NTS matches we want for each SPC household? +n_matches = 10 [work_assignment] -use_percentages = true # if true, optimization problem will try to minimize percentage difference at OD level (not absolute numbers). Recommended to set it to true +commute_level = "MSOA" +# if true, optimization problem will try to minimize percentage difference at OD level (not absolute numbers). Recommended to set it to true +use_percentages = true # weights to add for each objective in the optimization problem weight_max_dev = 0.2 weight_total_dev = 0.8 -max_zones = 8 # maximum number of feasible zones to include in the optimization problem (less zones makes problem smaller - so faster, but at the cost of a better solution) +# maximum number of feasible zones to include in the optimization problem (less zones makes problem smaller - so faster, but at the cost of a better solution) +max_zones = 10 +[postprocessing] +pam_jitter = 30 +pam_min_duration = 10 +# for get_pt_subscription: everyone above this age has a subscription (pensioners get free travel) +# TODO: more sophisticated approach +pt_subscription_age = 66 +# to define if a person is a student: +# eveyone below this age is a student +student_age_base = 16 +# everyone below this age that has at least one "education" activity is a student +student_age_upper = 30 +# eveyone who uses one of the modes below is classified as a passenger (isPassenger = True) +modes_passenger = ['car_passenger', 'taxi'] +# yearly state pension: for getting hhlIncome of pensioners +state_pension = 11502 ```