From a746ecbdba9f6f24e64269eec0c5e0cbffd18c3d Mon Sep 17 00:00:00 2001 From: Rahul Kulhalli Date: Mon, 29 Apr 2024 14:22:51 -0400 Subject: [PATCH 1/6] synced with main, cleaned outputs --- .../01_extract_db_data.ipynb | 1645 +++++++++++++++++ .../02_run_trip_level_models.py | 491 +++++ .../03_user_level_models.ipynb | 1120 +++++++++++ .../04_FeatureClustering.ipynb | 1108 +++++++++++ replacement_mode_modeling/README.md | 31 + replacement_mode_modeling/data/README.md | 1 + replacement_mode_modeling/outputs/README.md | 1 + 7 files changed, 4397 insertions(+) create mode 100644 replacement_mode_modeling/01_extract_db_data.ipynb create mode 100644 replacement_mode_modeling/02_run_trip_level_models.py create mode 100644 replacement_mode_modeling/03_user_level_models.ipynb create mode 100644 replacement_mode_modeling/04_FeatureClustering.ipynb create mode 100644 replacement_mode_modeling/README.md create mode 100644 replacement_mode_modeling/data/README.md create mode 100644 replacement_mode_modeling/outputs/README.md diff --git a/replacement_mode_modeling/01_extract_db_data.ipynb b/replacement_mode_modeling/01_extract_db_data.ipynb new file mode 100644 index 00000000..216b88bd --- /dev/null +++ b/replacement_mode_modeling/01_extract_db_data.ipynb @@ -0,0 +1,1645 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "38b147ff", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import ast\n", + "import sys\n", + "import pickle\n", + "import importlib\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "from pandas.api.types import is_string_dtype\n", + "from pathlib import Path\n", + "from uuid import UUID\n", + "from collections import defaultdict\n", + "\n", + "pd.set_option(\"display.max_columns\", 100)\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e550aa2b", + "metadata": {}, + "outputs": [], + "source": [ + "INCLUDE_TEST_USERS = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39306a1d", + "metadata": {}, + "outputs": [], + "source": [ + "# Add path to your emission server here.\n", + "emission_path = Path(os.getcwd()).parent.parent / 'my_emission_server' / 'e-mission-server'\n", + "sys.path.append(str(emission_path))\n", + "\n", + "# Also add the home (viz_scripts) to the path\n", + "sys.path.append('../viz_scripts')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94f673d6", + "metadata": {}, + "outputs": [], + "source": [ + "import scaffolding\n", + "import emission.core.get_database as edb\n", + "import emission.storage.timeseries.abstract_timeseries as esta" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e171e277", + "metadata": {}, + "outputs": [], + "source": [ + "DB_SOURCE = [\n", + " \"Stage_database\", # Does NOT have composite trips BUT has section modes and distances\n", + " \"openpath_prod_durham\", # Has composite trips\n", + " \"openpath_prod_mm_masscec\", # Has composite trips\n", + " \"openpath_prod_ride2own\", # Has composite trips\n", + "# \"openpath_prod_uprm_civic\", # No replaced mode (Excluded)\n", + " \"openpath_prod_uprm_nicr\" # Has composite trips\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70fa3112", + "metadata": {}, + "outputs": [], + "source": [ + "CURRENT_DB = DB_SOURCE[0]\n", + "\n", + "assert CURRENT_DB in DB_SOURCE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbde79d1", + "metadata": {}, + "outputs": [], + "source": [ + "REPLACED_MODE_DICT = {\n", + " \"Stage_database\": {\n", + " 'no_trip': 'no_trip',\n", + " 'no_travel': 'no_trip',\n", + " 'Unknown': 'unknown',\n", + " 'unknown': 'unknown',\n", + " 'bus': 'transit',\n", + " 'drove_alone': 'car',\n", + " 'bike': 'p_micro',\n", + " 'shared_ride': 's_car',\n", + " 'walk': 'walk',\n", + " 'train': 'transit',\n", + " 'bikeshare': 's_micro',\n", + " 'not_a trip': 'no_trip',\n", + " 'pilot_ebike': 'p_micro',\n", + " 'electric_car': 'car',\n", + " 'taxi': 'ridehail',\n", + " 'not_a_trip': 'no_trip',\n", + " 'run': 'walk',\n", + " 'scootershare': 's_micro',\n", + " 'tramway': 'transit',\n", + " 'free_shuttle': 'transit',\n", + " 'e-bike': 'p_micro',\n", + " 'rental_car': 'car',\n", + " 'train_+ bus': 'transit',\n", + " 'skateboard': 'p_micro',\n", + " 'snowboarding': 'p_micro',\n", + " 'e_bike': 'p_micro',\n", + " 'golf_cart': 'unknown',\n", + " 'emergency_vehicle with others': 's_car',\n", + " 'call_friend': 's_car',\n", + " 'no_replacement': 'no_travel',\n", + " 'doing_nothing': 'no_trip',\n", + " 'na': 'no_trip',\n", + " 'ebike': 'p_micro',\n", + " 'hiking': 'walk',\n", + " 'n/a': 'no_trip',\n", + " 'testing': 'unknown',\n", + " 'home': 'no_trip',\n", + " 'must_walk 3-5 mi a day for back': 'walk',\n", + " 'family': 's_car',\n", + " 'car': 'car',\n", + " 'pilot_e-bike': 'p_micro',\n", + " 'pilot_bike': 'p_micro',\n", + " 'time_spent on the clock at amazon': 'no_trip',\n", + " 'working': 'no_trip',\n", + " 'walk_at work': 'walk',\n", + " 'sitting_on my butt doing nothing': 'no_trip',\n", + " 'nothing._delivered food for work': 'no_trip',\n", + " 'train,_bus and walk': 'transit',\n", + " 'work_vehicle': 'car',\n", + " 'friend_picked me up': 's_car',\n", + " 'ski': 'p_micro',\n", + " 'not_accurate': 'unknown',\n", + " 'stolen_ebike': 'p_micro'\n", + " },\n", + " \"openpath_prod_durham\": {\n", + " 'Unknown': 'unknown',\n", + " 'bike': 'p_micro',\n", + " 'shared_ride': 's_car',\n", + " 'drove_alone': 'car',\n", + " 'bus': 'transit',\n", + " 'no_travel': 'no_trip',\n", + " 'scootershare': 's_micro',\n", + " 'walk': 'walk',\n", + " 'taxi': 'ridehail',\n", + " 'e_car_drove_alone': 'car',\n", + " 'bikeshare': 's_micro',\n", + " 'ebike': 'p_micro',\n", + " 'train': 'transit',\n", + " 'e_car_shared_ride': 's_car'\n", + " },\n", + " \"openpath_prod_mm_masscec\": {\n", + " 'Unknown': 'unknown',\n", + " 'drove_alone': 'car',\n", + " 'walk': 'walk',\n", + " 'shared_ride': 's_car',\n", + " 'bike': 'p_micro',\n", + " 'bikeshare': 's_micro',\n", + " 'no_travel': 'no_trip',\n", + " 'taxi': 'ridehail',\n", + " 'bus': 'transit',\n", + " 'scootershare': 's_micro',\n", + " 'train': 'transit',\n", + " 'walking': 'walk',\n", + " 'e_car_drove_alone': 'car'\n", + " },\n", + " \"openpath_prod_ride2own\": {\n", + " 'Unknown': 'unknown',\n", + " 'drove_alone': 'car',\n", + " 'walk': 'walk',\n", + " 'shared_ride': 's_car',\n", + " 'bike': 'p_micro',\n", + " 'no_travel': 'no_trip',\n", + " 'taxi': 'ridehail',\n", + " 'bus': 'transit',\n", + " 'train': 'transit',\n", + " 'e_car_drove_alone': 'car',\n", + " 'e_car_shared_ride': 's_car'\n", + " },\n", + " \"openpath_prod_uprm_nicr\": {\n", + " 'Unknown': 'unknown',\n", + " 'walk': 'walk',\n", + " 'drove_alone': 'car'\n", + " }\n", + "}\n", + "\n", + "SENSED_SECTION_DICT = {\n", + " \"openpath_prod_mm_masscec\": {'AIR_OR_HSR', 'BICYCLING', 'BUS', 'CAR', 'LIGHT_RAIL', 'SUBWAY', 'TRAIN', 'UNKNOWN', 'WALKING'}\n", + "}\n", + "\n", + "SURVEY_DATA_DICT = {\n", + " \"Stage_database\": {\n", + " \"Unique User ID (auto-filled, do not edit)\": \"user_id\",\n", + " \"In which year were you born?\": \"birth_year\",\n", + " \"What is your gender?\": \"gender\",\n", + " \"Do you have a valid driver's license?\": \"has_drivers_license\",\n", + " \"Are you a student?\": \"is_student\",\n", + " \"What is the highest grade or degree that you have completed?\": \"highest_education\",\n", + " \"Do you work for either pay or profit?\": \"is_paid\",\n", + " \"Do you have more than one job?\": \"has_multiple_jobs\",\n", + " \"Do you work full-time or part-time at your primary job?\": \"primary_job_type\",\n", + " \"Which best describes your primary job?\": \"primary_job_description\",\n", + " \"How did you usually get to your primary job last week? \": \"primary_job_commute_mode\",\n", + " \"Thinking about your daily commute to work last week, how many minutes did it usually take to get from home to the primary job/work place?\": \"primary_job_commute_time\",\n", + " \"At your primary job, do you have the ability to set or change your own start time?\": \"is_primary_job_flexible\",\n", + " \"Do you have the option of working from home or an alternate location instead of going into your primary work place?\": \"primary_job_can_wfh\",\n", + " \"How many days per week do you usually work from home or an alternate location?\": \"wfh_days\",\n", + " \"Do you own or rent your place of residence?\": \"residence_ownership_type\",\n", + " \"What is your home type?\": \"residence_type\",\n", + " \"Please identify which category represents your total household income, before taxes, for last year.\": \"income_category\",\n", + " \"Including yourself, how many people live in your home?\": \"n_residence_members\",\n", + " \"How many children under age 18 live in your home?\": \"n_residents_u18\",\n", + " \"Including yourself, how many people have a driver's license in your household?\": \"n_residents_with_license\",\n", + " \"How many motor vehicles are owned, leased, or available for regular use by the people who currently live in your household?\": \"n_motor_vehicles\",\n", + " \"If you were unable to use your household vehicle(s), which of the following options would be available to you to get you from place to place?\": \"available_modes\",\n", + " \"Do you have a medical condition that makes it difficult to travel outside of the home?\": \"has_medical_condition\",\n", + " \"How long have you had this condition?\": \"medical_condition_duration\"\n", + " },\n", + " # Retrieved from: e-mission-phone/survey-resources/data-xls/demo-survey-v1.xlsx\n", + " \"openpath_prod_durham\": {\n", + " \"At_your_primary_job_do_you_ha\": \"is_primary_job_flexible\",\n", + " \"Which_best_describes_your_prim\": \"primary_job_description\",\n", + " \"Do_you_work_full_time_or_part_\": \"primary_job_type\",\n", + " \"Do_you_have_the_option_of_work\": \"primary_job_can_wfh\",\n", + " \"Please_describe_your_primary_job\": \"primary_job_description_2\",\n", + " \"Do_you_have_more_than_one_job\": \"has_multiple_jobs\",\n", + " # Two columns: how many days/week do you work & what days of the week do you work. \n", + " # the latter has only 4 NA values, the former has 45 NA values.\n", + " \"What_days_of_the_week_do_you_t\": \"wfh_days\",\n", + " \"How_many_days_do_you_usually_w_001\": \"n_wfh_days\",\n", + " # All these are NAs.\n", + " \"Which_one_below_describe_you_b\": \"description\",\n", + " \"What_is_your_race_ethnicity\": \"race_or_ethnicity\",\n", + " \"Are_you_a_student\": \"is_student\",\n", + " \"What_is_the_highest_grade_or_d\": \"highest_education\",\n", + " \"do_you_consider_yourself_to_be\": \"is_transgender\",\n", + " \"What_is_your_gender\": \"gender\",\n", + " \"How_old_are_you\": \"age\",\n", + " \"Are_you_a_paid_worker\": \"is_paid\",\n", + " \"Do_you_have_a_driver_license\": \"has_drivers_license\",\n", + " \"How_long_you_had_this_conditio\": \"medical_condition_duration\",\n", + " \"Including_yourself_how_many_w_001\": \"n_residents_u18\",\n", + " \"Including_yourself_how_many_p\": \"n_residence_members\",\n", + " \"Do_you_own_or_rent_your_home\": \"residence_ownership_type\",\n", + " \"Please_identify_which_category\": \"income_category\",\n", + " \"If_you_were_unable_to_use_your\": \"available_modes\",\n", + " \"Including_yourself_how_many_p_001\": \"n_residents_with_license\",\n", + " \"Including_yourself_how_many_w\": \"n_working_residents\",\n", + " \"What_is_your_home_type\": \"residence_type\",\n", + " \"How_many_motor_vehicles_are_ow\": \"n_motor_vehicles\",\n", + " \"Do_you_have_a_condition_or_han\": \"has_medical_condition\"\n", + " },\n", + " \"openpath_prod_mm_masscec\": {\n", + " # Same questions as Durham.\n", + " \"At_your_primary_job_do_you_ha\": \"is_primary_job_flexible\",\n", + " \"Which_best_describes_your_prim\": \"primary_job_description\",\n", + " \"Do_you_work_full_time_or_part_\": \"primary_job_type\",\n", + " \"Do_you_have_the_option_of_work\": \"primary_job_can_wfh\",\n", + " \"Please_describe_your_primary_job\": \"primary_job_description_2\",\n", + " \"Do_you_have_more_than_one_job\": \"has_multiple_jobs\",\n", + " # Two columns: how many days/week do you work & what days of the week do you work. \n", + " # the latter has only 4 NA values, the former has 45 NA values.\n", + " \"What_days_of_the_week_do_you_t\": \"wfh_days\",\n", + " \"How_many_days_do_you_usually_w_001\": \"n_wfh_days\",\n", + " # All these are NAs.\n", + " \"Which_one_below_describe_you_b\": \"description\",\n", + " \"What_is_your_race_ethnicity\": \"race_or_ethnicity\",\n", + " \"Are_you_a_student\": \"is_student\",\n", + " \"What_is_the_highest_grade_or_d\": \"highest_education\",\n", + " \"do_you_consider_yourself_to_be\": \"is_transgender\",\n", + " \"What_is_your_gender\": \"gender\",\n", + " \"How_old_are_you\": \"age\",\n", + " \"Are_you_a_paid_worker\": \"is_paid\",\n", + " \"Do_you_have_a_driver_license\": \"has_drivers_license\",\n", + " \"How_long_you_had_this_conditio\": \"medical_condition_duration\",\n", + " \"Including_yourself_how_many_w_001\": \"n_residents_u18\",\n", + " \"Including_yourself_how_many_p\": \"n_residence_members\",\n", + " \"Do_you_own_or_rent_your_home\": \"residence_ownership_type\",\n", + " \"Please_identify_which_category\": \"income_category\",\n", + " \"If_you_were_unable_to_use_your\": \"available_modes\",\n", + " \"Including_yourself_how_many_p_001\": \"n_residents_with_license\",\n", + " \"Including_yourself_how_many_w\": \"n_working_residents\",\n", + " \"What_is_your_home_type\": \"residence_type\",\n", + " \"How_many_motor_vehicles_are_ow\": \"n_motor_vehicles\",\n", + " \"Do_you_have_a_condition_or_han\": \"has_medical_condition\"\n", + " },\n", + " \"openpath_prod_ride2own\": {\n", + " # Same questions as Durham.\n", + " \"How_old_are_you\": \"age\",\n", + " \"What_is_your_gender\": \"gender\",\n", + " \"do_you_consider_yourself_to_be\": \"is_transgender\",\n", + " \"What_is_your_race_ethnicity\": \"race_or_ethnicity\",\n", + " \"Do_you_have_a_driver_license\": \"has_drivers_license\",\n", + " \"Are_you_a_student\": \"is_student\",\n", + " \"What_is_the_highest_grade_or_d\": \"highest_education\",\n", + " \"Are_you_a_paid_worker\": \"is_paid\",\n", + " \"Which_one_below_describe_you_b\": \"description\",\n", + " \"Do_you_own_or_rent_your_home\": \"residence_ownership_type\",\n", + " \"What_is_your_home_type\": \"residence_type\",\n", + " \"Please_identify_which_category\": \"income_category\",\n", + " \"Including_yourself_how_many_p\": \"n_residence_members\",\n", + " \"Including_yourself_how_many_w\": \"n_working_residents\",\n", + " \"Including_yourself_how_many_p_001\": \"n_residents_with_license\",\n", + " \"Including_yourself_how_many_w_001\": \"n_residents_u18\",\n", + " \"How_many_motor_vehicles_are_ow\": \"n_motor_vehicles\",\n", + " \"If_you_were_unable_to_use_your\": \"available_modes\",\n", + " \"Do_you_have_a_condition_or_han\": \"has_medical_condition\",\n", + " \"How_long_you_had_this_conditio\": \"medical_condition_duration\",\n", + " \"Do_you_have_more_than_one_job\": \"has_multiple_jobs\",\n", + " \"Do_you_work_full_time_or_part_\": \"primary_job_type\",\n", + " \"Which_best_describes_your_prim\": \"primary_job_description\",\n", + " \"Please_describe_your_primary_job\": \"primary_job_description_2\",\n", + " \"At_your_primary_job_do_you_ha\": \"is_primary_job_flexible\",\n", + " \"Do_you_have_the_option_of_work\": \"primary_job_can_wfh\",\n", + " \"How_many_days_do_you_usually_w_001\": \"n_wfh_days\",\n", + " \"What_days_of_the_week_do_you_t\": \"wfh_days\"\n", + " },\n", + " \"openpath_prod_uprm_nicr\": {\n", + " # Same as Durham!\n", + " \"At_your_primary_job_do_you_ha\": \"is_primary_job_flexible\",\n", + " \"Which_best_describes_your_prim\": \"primary_job_description\",\n", + " \"Do_you_work_full_time_or_part_\": \"primary_job_type\",\n", + " \"Do_you_have_the_option_of_work\": \"primary_job_can_wfh\",\n", + " \"Please_describe_your_primary_job\": \"primary_job_description_2\",\n", + " \"Do_you_have_more_than_one_job\": \"has_multiple_jobs\",\n", + " # Two columns: how many days/week do you work & what days of the week do you work. \n", + " # the latter has only 4 NA values, the former has 45 NA values.\n", + " \"What_days_of_the_week_do_you_t\": \"wfh_days\",\n", + " \"How_many_days_do_you_usually_w_001\": \"n_wfh_days\",\n", + " # All these are NAs.\n", + " \"Which_one_below_describe_you_b\": \"description\",\n", + " \"What_is_your_race_ethnicity\": \"race_or_ethnicity\",\n", + " \"Are_you_a_student\": \"is_student\",\n", + " \"What_is_the_highest_grade_or_d\": \"highest_education\",\n", + " \"do_you_consider_yourself_to_be\": \"is_transgender\",\n", + " \"What_is_your_gender\": \"gender\",\n", + " \"How_old_are_you\": \"age\",\n", + " \"Are_you_a_paid_worker\": \"is_paid\",\n", + " \"Do_you_have_a_driver_license\": \"has_drivers_license\",\n", + " \"How_long_you_had_this_conditio\": \"medical_condition_duration\",\n", + " \"Including_yourself_how_many_w_001\": \"n_residents_u18\",\n", + " \"Including_yourself_how_many_p\": \"n_residence_members\",\n", + " \"Do_you_own_or_rent_your_home\": \"residence_ownership_type\",\n", + " \"Please_identify_which_category\": \"income_category\",\n", + " \"If_you_were_unable_to_use_your\": \"available_modes\",\n", + " \"Including_yourself_how_many_p_001\": \"n_residents_with_license\",\n", + " \"Including_yourself_how_many_w\": \"n_working_residents\",\n", + " \"What_is_your_home_type\": \"residence_type\",\n", + " \"How_many_motor_vehicles_are_ow\": \"n_motor_vehicles\",\n", + " \"Do_you_have_a_condition_or_han\": \"has_medical_condition\"\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69008893", + "metadata": {}, + "outputs": [], + "source": [ + "## Source: db_utils.py in op-admin-dashboard.\n", + "\n", + "BINARY_DEMOGRAPHICS_COLS = [\n", + " 'user_id',\n", + " '_id',\n", + "]\n", + "\n", + "EXCLUDED_DEMOGRAPHICS_COLS = [\n", + " 'data.xmlResponse', \n", + " 'data.name',\n", + " 'data.version',\n", + " 'data.label',\n", + " 'xmlns:jr',\n", + " 'xmlns:orx',\n", + " 'id',\n", + " 'start',\n", + " 'end',\n", + " 'attrxmlns:jr',\n", + " 'attrxmlns:orx',\n", + " 'attrid',\n", + " '__version__',\n", + " 'attrversion',\n", + " 'instanceID',\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12cc0c54", + "metadata": {}, + "outputs": [], + "source": [ + "## Source: scaffolding.py\n", + "\n", + "def expand_userinputs(labeled_ct):\n", + " '''\n", + " param: labeled_ct: a dataframe of confirmed trips, some of which have labels\n", + " params: labels_per_trip: the number of labels for each trip.\n", + " Currently, this is 2 for studies and 3 for programs, and should be \n", + " passed in by the notebook based on the input config.\n", + " If used with a trip-level survey, it could be even larger.\n", + " '''\n", + " # CASE 1 of https://github.com/e-mission/em-public-dashboard/issues/69#issuecomment-1256835867\n", + " if len(labeled_ct) == 0:\n", + " return labeled_ct\n", + " label_only = pd.DataFrame(labeled_ct.user_input.to_list(), index=labeled_ct.index)\n", + " # disp.display(label_only.head())\n", + " labels_per_trip = len(label_only.columns)\n", + " print(\"Found %s columns of length %d\" % (label_only.columns, labels_per_trip))\n", + " expanded_ct = pd.concat([labeled_ct, label_only], axis=1)\n", + " assert len(expanded_ct) == len(labeled_ct), \\\n", + " (\"Mismatch after expanding labels, expanded_ct.rows = %s != labeled_ct.rows %s\" %\n", + " (len(expanded_ct), len(labeled_ct)))\n", + " print(\"After expanding, columns went from %s -> %s\" %\n", + " (len(labeled_ct.columns), len(expanded_ct.columns)))\n", + " assert len(expanded_ct.columns) == len(labeled_ct.columns) + labels_per_trip, \\\n", + " (\"Mismatch after expanding labels, expanded_ct.columns = %s != labeled_ct.columns %s\" %\n", + " (len(expanded_ct.columns), len(labeled_ct.columns)))\n", + " # disp.display(expanded_ct.head())\n", + " return expanded_ct" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a98e2fb", + "metadata": {}, + "outputs": [], + "source": [ + "## Source: scaffolding.py\n", + "\n", + "def data_quality_check(expanded_ct):\n", + " '''1. Delete rows where the mode_confirm was pilot_ebike and repalced_mode was pilot_ebike.\n", + " 2. Delete rows where the mode_confirm was pilot_ebike and repalced_mode was same_mode.\n", + " 3. Replace same_mode for the mode_confirm for Energy Impact Calcualtion.'''\n", + "\n", + " # TODO: This is only really required for the initial data collection around the minipilot\n", + " # in subsequent deployes, we removed \"same mode\" and \"pilot_ebike\" from the options, so the\n", + " # dataset did not contain of these data quality issues\n", + "\n", + " if 'replaced_mode' in expanded_ct.columns:\n", + " expanded_ct.drop(expanded_ct[(expanded_ct['mode_confirm'] == 'pilot_ebike') & (expanded_ct['replaced_mode'] == 'pilot_ebike')].index, inplace=True)\n", + " expanded_ct.drop(expanded_ct[(expanded_ct['mode_confirm'] == 'pilot_ebike') & (expanded_ct['replaced_mode'] == 'same_mode')].index, inplace=True)\n", + " expanded_ct['replaced_mode'] = np.where(expanded_ct['replaced_mode'] == 'same_mode',expanded_ct['mode_confirm'], expanded_ct['replaced_mode'])\n", + " \n", + " return expanded_ct" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe37bf27", + "metadata": {}, + "outputs": [], + "source": [ + "if CURRENT_DB != \"Stage_database\":\n", + "\n", + " ## Source: scaffolding.py\n", + "\n", + " uuid_df = pd.json_normalize(list(edb.get_uuid_db().find()))\n", + "\n", + " if not INCLUDE_TEST_USERS:\n", + " uuid_df = uuid_df.loc[~uuid_df.user_email.str.contains('_test_'), :]\n", + "\n", + " filtered = uuid_df.uuid.unique()\n", + "\n", + " agg = esta.TimeSeries.get_aggregate_time_series()\n", + " all_ct = agg.get_data_df(\"analysis/confirmed_trip\", None)\n", + "\n", + " print(f\"Before filtering, length={len(all_ct)}\")\n", + " participant_ct_df = all_ct.loc[all_ct.user_id.isin(filtered), :]\n", + " print(f\"After filtering, length={len(participant_ct_df)}\")\n", + "\n", + " expanded_ct = expand_userinputs(participant_ct_df)\n", + " expanded_ct = data_quality_check(expanded_ct)\n", + " print(expanded_ct.columns.tolist())\n", + " expanded_ct['replaced_mode'] = expanded_ct['replaced_mode'].fillna('Unknown')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13536d14", + "metadata": {}, + "outputs": [], + "source": [ + "# # Additional preprocessing for replaced mode (if any)\n", + "\n", + "if CURRENT_DB != \"Stage_database\":\n", + "\n", + " mode_counts = expanded_ct['replaced_mode'].value_counts()\n", + " drop_modes = mode_counts[mode_counts == 1].index.tolist()\n", + "\n", + " expanded_ct.drop(\n", + " index=expanded_ct.loc[expanded_ct.replaced_mode.isin(drop_modes)].index,\n", + " inplace=True\n", + " )\n", + "\n", + " # Additional modes to drop.\n", + " expanded_ct.drop(\n", + " index=expanded_ct.loc[expanded_ct.replaced_mode.isin(\n", + " # Remove all rows with air, boat, or weird answers.\n", + " ['houseboat', 'gondola', 'airline_flight', 'aircraft', 'zoo', 'air',\n", + " 'airplane', 'boat', 'flight', 'plane', 'meal', 'lunch']\n", + " )].index,\n", + " inplace=True\n", + " )\n", + " \n", + " expanded_ct.replaced_mode = expanded_ct.replaced_mode.apply(lambda x: REPLACED_MODE_DICT[CURRENT_DB][x])" + ] + }, + { + "cell_type": "markdown", + "id": "258844f4", + "metadata": {}, + "source": [ + "# Demographic pre-processing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7461a4d2", + "metadata": {}, + "outputs": [], + "source": [ + "# Demographics\n", + "\n", + "if CURRENT_DB != \"Stage_database\":\n", + "\n", + " decoded_uuids = [str(x) for x in filtered]\n", + "\n", + " ## Source: query_demographics() in op-admin-dashboard.\n", + " ts = esta.TimeSeries.get_aggregate_time_series()\n", + " entries = list(ts.find_entries([\"manual/demographic_survey\"]))\n", + "\n", + " available_key = {}\n", + " for entry in entries:\n", + " survey_key = list(entry['data']['jsonDocResponse'].keys())[0]\n", + " if survey_key not in available_key:\n", + " available_key[survey_key] = []\n", + "\n", + " # Minor modification: Added user_id check to filter users.\n", + " if str(entry['user_id']) in decoded_uuids:\n", + " available_key[survey_key].append(entry)\n", + "\n", + " dataframes = {}\n", + " for key, json_object in available_key.items():\n", + " df = pd.json_normalize(json_object)\n", + " dataframes[key] = df\n", + "\n", + " for key, df in dataframes.items():\n", + " if not df.empty:\n", + " for col in BINARY_DEMOGRAPHICS_COLS:\n", + " if col in df.columns:\n", + " df[col] = df[col].apply(str) \n", + " columns_to_drop = [col for col in df.columns if col.startswith(\"metadata\")]\n", + " df.drop(columns= columns_to_drop, inplace=True) \n", + " df.columns=[col.rsplit('.',1)[-1] if col.startswith('data.jsonDocResponse.') else col for col in df.columns]\n", + " for col in EXCLUDED_DEMOGRAPHICS_COLS:\n", + " if col in df.columns:\n", + " df.drop(columns= [col], inplace=True)\n", + "\n", + " survey_data = pd.DataFrame() \n", + " for v in dataframes.values():\n", + " survey_data = pd.concat([survey_data, v], axis=0, ignore_index=True)\n", + "else:\n", + " # Read the demographics.\n", + " survey_data = pd.read_csv('./viz_scripts/Can Do Colorado eBike Program - en.csv')\n", + " survey_data.rename(columns={'Unique User ID (auto-filled, do not edit)': 'user_id'}, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe5a9dff", + "metadata": {}, + "outputs": [], + "source": [ + "if CURRENT_DB == \"Stage_database\":\n", + " \n", + " if os.path.exists('./data/cached_allceo_data.csv'):\n", + " \n", + " # Replace current instance of dataframe with the cached dataframe.\n", + " expanded_ct = pd.read_csv('./data/cached_allceo_data.csv')\n", + " expanded_ct.loc[expanded_ct.replaced_mode == 'no_travel', 'replaced_mode'] = 'no_trip'\n", + " else:\n", + " ## NOTE: Run this cell only if the cached CSV is not already available. It will take a LOT of time.\n", + " ## Benchmark timing: ~12 hours on a MacBook Pro (2017 model) with pandarallel, 4 workers.\n", + " \n", + " importlib.reload(scaffolding)\n", + " expanded_ct = scaffolding.get_section_durations(expanded_ct)\n", + " expanded_ct.to_csv('./data/cached_allceo_data.csv', index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6be751e", + "metadata": {}, + "outputs": [], + "source": [ + "print(len(survey_data.user_id.unique()), len(expanded_ct.user_id.unique()))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ebc87d8", + "metadata": {}, + "outputs": [], + "source": [ + "survey_data.rename(SURVEY_DATA_DICT[CURRENT_DB], axis='columns', inplace=True)" + ] + }, + { + "cell_type": "markdown", + "id": "522b1362", + "metadata": {}, + "source": [ + "### Demographic data preprocessing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "336508c2", + "metadata": {}, + "outputs": [], + "source": [ + "print(survey_data.columns.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29bc7996", + "metadata": {}, + "outputs": [], + "source": [ + "# gtg\n", + "survey_data['ft_job'] = survey_data.primary_job_type.apply(\n", + " lambda x: 1 if str(x).lower() == 'full_time' else 0\n", + ")\n", + "\n", + "# gtg\n", + "survey_data['multiple_jobs'] = survey_data.has_multiple_jobs.apply(\n", + " lambda x: 1 if str(x).lower() == 'yes' else 0\n", + ")\n", + "\n", + "# gtg\n", + "survey_data.loc[\n", + " survey_data.n_motor_vehicles.isin(\n", + " ['prefer_not_to_say', 'Prefer not to say / Prefiero no decir.']\n", + " ), 'n_motor_vehicles'\n", + "] = 0\n", + "survey_data.loc[survey_data.n_motor_vehicles.isin(['more_than_3', '4+', 'more_than_4']), 'n_motor_vehicles'] = 4\n", + "survey_data.n_motor_vehicles = survey_data.n_motor_vehicles.astype(int)\n", + "\n", + "# gtg\n", + "survey_data.has_drivers_license = survey_data.has_drivers_license.apply(\n", + " lambda x: 1 if str(x).lower() == 'yes' else 0\n", + ")\n", + "\n", + "survey_data.loc[survey_data.n_residents_u18 == 'prefer_not_to_say'] = 0\n", + "survey_data.n_residents_u18 = survey_data.n_residents_u18.astype(int)\n", + "\n", + "survey_data.loc[survey_data.n_residence_members == 'prefer_not_to_say'] = 0\n", + "survey_data.n_residence_members = survey_data.n_residence_members.astype(int)\n", + "\n", + "survey_data.loc[survey_data.n_residents_with_license == 'prefer_not_to_say'] = 0\n", + "survey_data.loc[survey_data.n_residents_with_license == 'more_than_4'] = 4\n", + "survey_data.n_residents_with_license = survey_data.n_residents_with_license.astype(int)\n", + "\n", + "# In allCEO, we see 50 & 9999. What??\n", + "survey_data = survey_data[\n", + " (survey_data.n_residence_members < 10) & (survey_data.n_residents_u18 < 10) & \n", + " (survey_data.n_residents_with_license < 10) & \n", + " (survey_data.n_residence_members - survey_data.n_residents_with_license > 0) &\n", + " (survey_data.n_residence_members - survey_data.n_residents_u18 > 0)\n", + "].reset_index(drop=True)\n", + "\n", + "# gtg\n", + "if CURRENT_DB != \"Stage_database\":\n", + " survey_data.n_working_residents = survey_data.n_working_residents.apply(\n", + " lambda x: 0 if x == 'prefer_not_to_say' else int(x)\n", + " )\n", + "else:\n", + " survey_data['n_working_residents'] = survey_data['n_residence_members'] - survey_data['n_residents_u18']\n", + " \n", + "survey_data = survey_data[survey_data.n_working_residents >= 0].reset_index(drop=True)\n", + "\n", + "# gtg\n", + "survey_data.is_paid = survey_data.is_paid.apply(lambda x: 1 if x == 'Yes' else 0)\n", + "\n", + "# gtg\n", + "survey_data.has_medical_condition = survey_data.has_medical_condition.apply(\n", + " lambda x: 1 if str(x).lower() == 'yes' else 0\n", + ")\n", + "\n", + "## gtg\n", + "survey_data.is_student.replace({\n", + " 'Not a student': 0, \n", + " 'Yes - Full Time College/University': 1,\n", + " 'Yes - Vocation/Technical/Trade School': 1,\n", + " 'Yes - K-12th Grade including GED': 1, \n", + " 'Work': 0, \n", + " 'No': 0,\n", + " 'Prefer not to say': 0,\n", + " 'Yes - Part-Time College/University': 1,\n", + " 'Taking prerequisites missing for grad program ': 1, \n", + " 'Graduate': 1,\n", + " 'Custodian': 0, \n", + " 'Work at csu': 0,\n", + " 'not_a_student': 0, \n", + " 'yes___vocation_technical_trade_school': 1,\n", + " 'yes___part_time_college_university': 1,\n", + " 'prefer_not_to_say': 0, \n", + " 'yes___k_12th_grade_including_ged': 1,\n", + " 'yes___full_time_college_university': 1\n", + "}, inplace=True)" + ] + }, + { + "cell_type": "markdown", + "id": "aeb85637", + "metadata": {}, + "source": [ + "### Additinal Demographic Data Preprocessing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c069bd2", + "metadata": {}, + "outputs": [], + "source": [ + "if CURRENT_DB == \"Stage_database\":\n", + " age = survey_data.birth_year.apply(\n", + " lambda x: 2024 - int(x) if int(x) > 100 else int(x)\n", + " )\n", + " \n", + " upper = age - (age % 5)\n", + " lower = upper + 5\n", + " new_col = (upper + 1).astype(str) + '___' + lower.astype(str) + '_years_old'\n", + " survey_data['age'] = new_col\n", + " \n", + " survey_data.loc[survey_data.age.isin([\n", + " '66___70_years_old', '76___80_years_old', '81___85_years_old'\n", + " ]), 'age'] = '__65_years_old'\n", + " \n", + " survey_data.drop(columns=['birth_year'], inplace=True)\n", + "\n", + "else:\n", + " survey_data = survey_data[survey_data.age != 0].reset_index(drop=True)\n", + "\n", + "if survey_data.columns.isin(['primary_job_commute_mode', 'primary_job_commute_time']).all():\n", + " survey_data.drop(columns=['primary_job_commute_mode', 'primary_job_commute_time'], inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f094cadd", + "metadata": {}, + "outputs": [], + "source": [ + "def normalize_job_descriptions(db_name, df):\n", + " if db_name != 'Stage_database':\n", + " PRIMARY_JOB_DESCRIPTION_DICT = {\n", + " \"sales_or_service\": \"Sales or service\",\n", + " \"other\": \"Other\",\n", + " \"\": \"Other\",\n", + " \"professional__managerial__or_technical\": \"Professional, Manegerial, or Technical\",\n", + " \"manufacturing__construction__maintenance\": \"Manufacturing, construction, maintenance, or farming\",\n", + " \"clerical_or_administrative_support\": \"Clerical or administrative support\",\n", + " \"prefer_not_to_say\": \"Prefer not to say\",\n", + " }\n", + " \n", + " df.primary_job_description = df.primary_job_description.apply(\n", + " lambda x: PRIMARY_JOB_DESCRIPTION_DICT[x]\n", + " )\n", + " else:\n", + " df.primary_job_description = df.primary_job_description.str.strip()\n", + "\n", + " # Normalize the job description. Inspired from the 'e-bike trips by occupation' \n", + " # plot in the CanBikeCo full pilot paper.\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Paraprofessional', 'Education', 'education/early childhood', 'Teacher',\n", + " 'Education non-profit manager', 'Scientific research', 'Research',\n", + " 'Preschool Tracher'\n", + " ]), 'primary_job_description'\n", + " ] = 'Education'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Custodian', 'Custodial', 'Csu custodian', 'Janitorial',\n", + " 'Custodial Maintanace'\n", + " ]), 'primary_job_description'\n", + " ] = 'Custodial'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Inbound cs', 'Accounting Technician', \n", + " 'Clerical'\n", + " ]), 'primary_job_description'\n", + " ] = 'Clerical or administrative support'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Restaurant manager', 'Transportaion Services',\n", + " ]), 'primary_job_description'\n", + " ] = 'Sales or service'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Pastry chef and line cook', 'Cook', 'Chef', 'Dining Services',\n", + " 'Food Service', 'Cooking', 'Residential Dining Services', 'Line Cook'\n", + " ]), 'primary_job_description'\n", + " ] = 'Food service'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'CNA', 'Caregiver/ Qmap', 'Health care', 'Nurse',\n", + " 'Healthcare', 'Medical', 'Medical field',\n", + " 'Family support'\n", + " ]), 'primary_job_description'\n", + " ] = 'Medical/healthcare'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Amazon', 'Hockey rink', 'Caregiver', 'Security', 'Nonprofit social work',\n", + " 'Therapeutic', 'Driver'\n", + " ]), 'primary_job_description'\n", + " ] = 'Other'\n", + "\n", + " df.loc[\n", + " df.primary_job_description.isin([\n", + " 'Hospital laundry', 'Matreal handler', 'Maintenance',\n", + " 'Co op laundry'\n", + " ]), 'primary_job_description'\n", + " ] = 'Manufacturing, construction, maintenance, or farming'\n", + "\n", + " df.loc[df.primary_job_description.isna(), 'primary_job_description'] = 'Other'\n", + "\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bf37859", + "metadata": {}, + "outputs": [], + "source": [ + "INCOME_DICT = {\n", + " 'Stage_database': {\n", + " 'Prefer not to say': 0,\n", + " 'Less than $24,999': 1,\n", + " '$25,000-$49,999': 2,\n", + " '$50,000-$99,999': 3,\n", + " '$100,000 -$149,999': 4,\n", + " '$150,000-$199,999': 5,\n", + " '$150,000': 5,\n", + " '$150,000-$199,999': 6,\n", + " '$200,000 or more': 7\n", + " },\n", + " 'Others': {\n", + " 'prefer_not_to_say': 0, \n", + " 'less_than__24_999': 1,\n", + " '_25_000_to__49_999': 2,\n", + " '_50_000_to__99_999': 3,\n", + " '_100_000_to__149_999': 4,\n", + " '_150_000_to__199_999': 5\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42b3163a", + "metadata": {}, + "outputs": [], + "source": [ + "survey_data = normalize_job_descriptions(CURRENT_DB, survey_data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe2b18b6", + "metadata": {}, + "outputs": [], + "source": [ + "if CURRENT_DB == 'Stage_database':\n", + " survey_data.income_category = survey_data.income_category.apply(\n", + " lambda x: INCOME_DICT['Stage_database'][x]\n", + " )\n", + "else:\n", + " survey_data.income_category = survey_data.income_category.apply(\n", + " lambda x: INCOME_DICT['Others'][x]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b36672b9", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.preprocessing import OneHotEncoder\n", + "\n", + "def generate_ohe_features(df, feature_name):\n", + " ohe = OneHotEncoder()\n", + " ohe.fit(df[[feature_name]])\n", + " return pd.DataFrame(\n", + " ohe.transform(df[[feature_name]]).todense(), \n", + " columns=ohe.get_feature_names_out(),\n", + " index=df.index\n", + " ), ohe" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc8d1846", + "metadata": {}, + "outputs": [], + "source": [ + "survey_data.reset_index(drop=True, inplace=True)\n", + "\n", + "ohe_features = ['highest_education', 'primary_job_description', 'gender', 'age']\n", + "\n", + "for ohe in ohe_features:\n", + " df, _ = generate_ohe_features(survey_data, ohe)\n", + " survey_data = survey_data.merge(right=df, left_index=True, right_index=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2d6f8c1", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "to_drop = [\n", + " 'Timestamp', 'gender', 'highest_education', 'primary_job_type', 'primary_job_description', \n", + " 'primary_job_commute_mode', 'primary_job_commute_time', 'is_primary_job_flexible', \n", + " 'primary_job_can_wfh', 'wfh_days', 'Which one below describe you best?', 'residence_ownership_type', \n", + " 'residence_type', 'medical_condition_duration', 'has_multiple_jobs', 'age', '_id', 'data.ts',\n", + " 'primary_job_description_2', 'wfh_days', 'n_wfh_days', 'description', 'race_or_ethnicity', \n", + " 'highest_education', 'is_transgender', 'medical_condition_duration'\n", + "]\n", + "\n", + "for column in to_drop:\n", + " if column in survey_data.columns:\n", + " survey_data.drop(columns=[column], inplace=True)" + ] + }, + { + "cell_type": "markdown", + "id": "65039f73", + "metadata": {}, + "source": [ + "## Merge sensed data and demographics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7eb2e09", + "metadata": {}, + "outputs": [], + "source": [ + "# Additional preprocessing to filter unwanted users from sensed trips data.\n", + "expanded_ct['user_id_join'] = expanded_ct['user_id'].apply(lambda x: str(x).replace('-', ''))\n", + "survey_data['user_id_join'] = survey_data['user_id'].apply(lambda x: str(x).replace('-', ''))\n", + "\n", + "survey_data.rename(columns={'user_id': 'survey_user_id'}, inplace=True)\n", + "\n", + "common = set(expanded_ct.user_id_join.unique()).intersection(\n", + " set(survey_data.user_id_join.unique())\n", + ")\n", + "\n", + "filtered_trips = expanded_ct.loc[expanded_ct.user_id_join.isin(common), :].reset_index(drop=True)\n", + "filtered_survey = survey_data.loc[survey_data.user_id_join.isin(common), :].reset_index(drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53927d5f", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# Just to double-check.\n", + "print(len(filtered_trips.user_id.unique()), len(filtered_survey.survey_user_id.unique()))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "daed8fb0", + "metadata": {}, + "outputs": [], + "source": [ + "# Compute the section_*_argmax.\n", + "\n", + "def compute_argmax(db: str, row):\n", + " \n", + " if db != 'Stage_database':\n", + " \n", + " sections = row['inferred_section_summary']\n", + "\n", + " if pd.isna(sections) or len(sections) == 0 or len(sections['distance']) == 0:\n", + " return row\n", + "\n", + " try:\n", + " mode = sorted(sections['distance'].items(), key=lambda x: x[-1], reverse=True)[0][0]\n", + " distance = sections['distance'][mode]\n", + " duration = sections['duration'][mode]\n", + "\n", + " row['section_mode_argmax'] = mode\n", + " row['section_distance_argmax'] = distance\n", + " row['section_duration_argmax'] = duration\n", + "\n", + " except:\n", + " row['section_mode_argmax'] = np.nan\n", + " row['section_distance_argmax'] = np.nan\n", + " row['section_duration_argmax'] = np.nan\n", + "\n", + " finally:\n", + " return row\n", + " else:\n", + " \n", + " try:\n", + " distances = ast.literal_eval(row['section_distances'])\n", + " durations = ast.literal_eval(row['section_durations'])\n", + " modes = ast.literal_eval(row['section_modes'])\n", + "\n", + " argmax = np.argmax(distances)\n", + " \n", + " row['section_distance_argmax'] = distances[argmax]\n", + " row['section_duration_argmax'] = durations[argmax]\n", + " row['section_mode_argmax'] = modes[argmax]\n", + " \n", + " except:\n", + " row['section_mode_argmax'] = np.nan\n", + " row['section_distance_argmax'] = np.nan\n", + " row['section_duration_argmax'] = np.nan\n", + " \n", + " finally:\n", + " return row" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0c008a3", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips.reset_index(drop=True, inplace=True)" + ] + }, + { + "cell_type": "markdown", + "id": "7e1baa06", + "metadata": {}, + "source": [ + "### Available feature generation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de49ec4f", + "metadata": {}, + "outputs": [], + "source": [ + "available = {\n", + " # AllCEO\n", + " 'Bicycle': 'p_micro',\n", + " 'Do not have vehicle': 'unknown',\n", + " 'Do not have vehicle ': 'unknown',\n", + " 'Get a ride from a friend or family member': 's_car',\n", + " 'None': 'no_trip',\n", + " 'Public transportation (bus, subway, light rail, etc.)': 'transit',\n", + " 'Rental car (including Zipcar/ Car2Go)': 'car',\n", + " 'Shared bicycle or scooter': 's_micro',\n", + " 'Skateboard': 'p_micro',\n", + " 'Taxi (regular taxi, Uber, Lyft, etc)': 'ridehail',\n", + " 'Walk/roll': 'walk',\n", + " 'Prefer not to say': 'unknown',\n", + " # Others\n", + " 'public_transportation__bus__subway__ligh': 'transit',\n", + " 'get_a_ride_from_a_friend_or_family_membe': 's_car', \n", + " 'bicycle': 'p_micro', \n", + " 'walk': 'walk',\n", + " 'taxi__regular_taxi__uber__lyft__etc': 'ridehail',\n", + " 'rental_car__including_zipcar__car2go': 'car', \n", + " 'prefer_not_to_say': 'unknown'\n", + "}\n", + "\n", + "# We use the sensed mode to update the available modes.\n", + "# This is to account for any user data input errors. E.g.: user does not select car as available mode\n", + "# but the sensed mode is car.\n", + "section_mode_mapping = {\n", + " 'bicycling': ['p_micro', 's_micro'],\n", + " 'car': ['s_car', 'car', 'ridehail'],\n", + " 'no_sensed': ['unknown'],\n", + " 'walking': ['walk'],\n", + " 'unknown': ['unknown'],\n", + " 'transit': ['transit']\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62960039", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips = filtered_trips.apply(lambda x: compute_argmax(CURRENT_DB, x), axis=1)\n", + "\n", + "# Drop all rows where argmax mode == air\n", + "filtered_trips.drop(\n", + " index=filtered_trips.loc[filtered_trips.section_mode_argmax.isin(['AIR_OR_HSR', 'air_or_hsr']),:].index, \n", + " inplace=True\n", + ")\n", + "\n", + "filtered_trips.section_mode_argmax.replace({\n", + " 'subway': 'transit',\n", + " 'no_sensed': 'unknown',\n", + " 'train': 'transit',\n", + " 'TRAM': 'transit',\n", + " 'LIGHT_RAIL': 'transit',\n", + " 'CAR': 'car',\n", + " 'WALKING': 'walking',\n", + " 'BICYCLING': 'bicycling',\n", + " 'UNKNOWN': 'unknown',\n", + " 'TRAIN': 'transit',\n", + " 'SUBWAY': 'transit',\n", + " 'BUS': 'transit',\n", + " 'bus': 'transit'\n", + "}, inplace=True)\n", + "\n", + "filtered_trips.dropna(subset='section_mode_argmax', inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8583a709", + "metadata": {}, + "outputs": [], + "source": [ + "## Meters -> miles\n", + "filtered_trips['section_distance_argmax'] *= 0.000621371\n", + "\n", + "## Seconds -> minutes\n", + "filtered_trips['section_duration_argmax'] /= 60.\n", + "\n", + "## Total distance and duration are scaled too.\n", + "filtered_trips['distance'] *= 0.000621371\n", + "filtered_trips['duration'] /= 60." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e4d05eb", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips = filtered_trips.merge(right=filtered_survey, left_on='user_id_join', right_on='user_id_join')" + ] + }, + { + "cell_type": "markdown", + "id": "383fe251", + "metadata": {}, + "source": [ + "## Update available indicators" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee097233", + "metadata": {}, + "outputs": [], + "source": [ + "import itertools\n", + "\n", + "new_cols = list(set(available.values()))\n", + "filtered_trips[new_cols] = 0\n", + "\n", + "for user_id, user_trips in filtered_trips.groupby('user_id'):\n", + " \n", + " if CURRENT_DB == \"Stage_database\":\n", + " \n", + " # Get the set of available modes (demographics.)\n", + " all_av_modes = user_trips['available_modes'].str.split(';').explode()\n", + " else:\n", + " # Get the set of available modes (demographics.)\n", + " all_av_modes = user_trips['available_modes'].str.split().explode()\n", + " \n", + " # Get all sensed modes.\n", + " all_sections = user_trips['section_mode_argmax'].unique()\n", + " \n", + " # Map to Common Normal Form.\n", + " mapped_sections = set(list(itertools.chain.from_iterable([section_mode_mapping[x] for x in all_sections])))\n", + " mapped_demo_av = set([available[x] for x in all_av_modes.unique()])\n", + " \n", + " # Perform a set union.\n", + " combined = list(mapped_sections.union(mapped_demo_av))\n", + " \n", + " # Update dummy indicators.\n", + " filtered_trips.loc[filtered_trips.user_id == user_id, combined] = 1\n", + "\n", + "filtered_trips.rename(columns=dict([(c, 'av_'+c) for c in new_cols]), inplace=True)" + ] + }, + { + "cell_type": "markdown", + "id": "38bfcc0c", + "metadata": {}, + "source": [ + "### Cost estimation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "054a6ad1", + "metadata": {}, + "outputs": [], + "source": [ + "# All values are taken from VTPI.\n", + "# https://www.vtpi.org/tca/tca0501.pdf\n", + "mode_cost_per_mile = {\n", + " # bicycle/skateboard\n", + " 'p_micro': 0.,\n", + " 'no_trip': 0.,\n", + " # Shared car is half the cost of regular car, which is $0.6/mile.\n", + " 's_car': 0.3,\n", + " # Rental car.\n", + " 'car': 0.6,\n", + " # Average of bus and train taken.\n", + " 'transit': 0.5,\n", + " # Shared bicyle or scooter - values taken from https://nacto.org/shared-micromobility-2020-2021/ and \n", + " # https://www.mckinsey.com/industries/automotive-and-assembly/our-insights/how-sharing-the-road-is-likely-to-transform-american-mobility\n", + " 's_micro': 0.3,\n", + " # uber/taxi/lyft\n", + " 'ridehail': 2.,\n", + " 'walk': 0.,\n", + " 'unknown': 0.\n", + "}\n", + "\n", + "# Assumptions.\n", + "mode_init_cost = {\n", + " 'p_micro': 0.,\n", + " 'no_trip': 0.,\n", + " # Shared car is half the cost of regular car, which is $0.6/mile.\n", + " 's_car': 0.,\n", + " # Rental car.\n", + " 'car': 0.,\n", + " # Average of bus and train taken.\n", + " 'transit': 0.,\n", + " # $1 unlocking cost.\n", + " 's_micro': 1.,\n", + " # uber/taxi/lyft\n", + " 'ridehail': 1.5,\n", + " 'walk': 0.,\n", + " 'unknown': 0.\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bccd3efb", + "metadata": {}, + "outputs": [], + "source": [ + "def compute_cost_estimates(df: pd.DataFrame):\n", + " \n", + " # Create some extra colums.\n", + " columns = [c.replace('av_', '') for c in df.columns if 'av_' in c]\n", + "\n", + " # Initialize the columns to 0.\n", + " df[columns] = 0.\n", + "\n", + " rows = list()\n", + "\n", + " # Iterate over every row.\n", + " for _, row in df.iterrows():\n", + " # Check which flags are active.\n", + " row_dict = row.to_dict()\n", + "\n", + " # Access the section_distance_argmax attribute for the distance. Note that this is now in miles.\n", + " distance = row_dict['section_distance_argmax']\n", + " \n", + " # Mask using availability.\n", + " for lookup in columns:\n", + " row_dict[lookup] = row_dict['av_' + lookup] * (\n", + " mode_init_cost[lookup] + (mode_cost_per_mile[lookup] * distance)\n", + " )\n", + "\n", + " rows.append(row_dict)\n", + "\n", + " new_df = pd.DataFrame(rows)\n", + " new_df.rename(columns=dict([(c, 'cost_'+c) for c in columns]), inplace=True)\n", + "\n", + " return new_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c39f1901", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips = compute_cost_estimates(filtered_trips)" + ] + }, + { + "cell_type": "markdown", + "id": "a6c20466", + "metadata": {}, + "source": [ + "### Outlier removal" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c05071cc", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"For {CURRENT_DB=}, before outlier removal, n_rows = {filtered_trips.shape[0]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b222715f", + "metadata": {}, + "outputs": [], + "source": [ + "# Drop instances where duration/distance is unusable.\n", + "filtered_trips.drop(\n", + " index=filtered_trips.loc[(filtered_trips.section_distance_argmax <= 0) | (filtered_trips.section_duration_argmax <= 0), :].index,\n", + " inplace=False\n", + ").reset_index(drop=True, inplace=True)\n", + "\n", + "\n", + "# bus, train, bicycling, walking, car\n", + "# split-apply-combine\n", + "def drop_outliers(df: pd.DataFrame, low=0.1, high=0.9) -> pd.DataFrame:\n", + " \n", + " def filter_by_percentiles(group):\n", + " distance_low = group['section_distance_argmax'].quantile(low)\n", + " distance_high = group['section_distance_argmax'].quantile(high)\n", + " duration_low = group['section_duration_argmax'].quantile(low)\n", + " duration_high = group['section_duration_argmax'].quantile(high)\n", + " \n", + " l1_filter = group[\n", + " (group['section_distance_argmax'] >= distance_low) &\n", + " (group['section_distance_argmax'] <= distance_high)\n", + " ].reset_index(drop=True)\n", + " \n", + " l2_filter = l1_filter[\n", + " (l1_filter['section_duration_argmax'] >= duration_low) &\n", + " (l1_filter['section_duration_argmax'] <= duration_high)\n", + " ].reset_index(drop=True)\n", + " \n", + " return l2_filter\n", + " \n", + " return df.groupby('section_mode_argmax').apply(filter_by_percentiles).reset_index(drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d77febb3", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips = drop_outliers(filtered_trips, low=0.01, high=0.99)\n", + "\n", + "# Ideal speed. distance/time (in hours).\n", + "filtered_trips['mph'] = (\n", + " (filtered_trips['section_distance_argmax'] * 60.)/filtered_trips['section_duration_argmax']\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b52d5325", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips[['section_mode_argmax', 'section_duration_argmax', 'section_distance_argmax', 'mph']].head(10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7ed953d", + "metadata": {}, + "outputs": [], + "source": [ + "def filter_mph(df: pd.DataFrame, low=0.1, high=0.9) -> pd.DataFrame:\n", + " \n", + " MPH_THRESHOLDS = {\n", + " # https://www.sciencedirect.com/science/article/pii/S2210670718304682\n", + " 'bicycling': 15.,\n", + " # https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7806575/\n", + " 'walking': 2.93\n", + " }\n", + " \n", + " def custom_filter(group):\n", + " # Drop data specified in the dict manually.\n", + " if group.name in MPH_THRESHOLDS.keys():\n", + " f_df = group[group['mph'] <= MPH_THRESHOLDS[group.name]]\n", + " else:\n", + " mph_low = group['mph'].quantile(low)\n", + " mph_high = group['mph'].quantile(high)\n", + "\n", + " f_df = group[(group['mph'] >= mph_low) & (group['mph'] <= mph_high)]\n", + " \n", + " return f_df\n", + " \n", + " return df.groupby('section_mode_argmax').apply(custom_filter).reset_index(drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c1904cd", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips = filter_mph(filtered_trips, low=0.01, high=0.99)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3dce2b1c", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips.groupby('section_mode_argmax')[['section_distance_argmax', 'section_duration_argmax']].describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "396f196b", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips.groupby('section_mode_argmax')[['mph']].describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41109148", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"For {CURRENT_DB=}, After outlier removal, n_rows = {filtered_trips.shape[0]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ca22a08", + "metadata": {}, + "outputs": [], + "source": [ + "to_drop=[\n", + " '_id', 'additions', 'cleaned_section_summary', 'cleaned_trip', 'confidence_threshold', \n", + " 'end_fmt_time', 'end_loc', 'end_local_dt_day', 'raw_trip', 'purpose_confirm',\n", + " 'end_local_dt_minute', 'end_local_dt_month', 'end_local_dt_second', 'end_local_dt_timezone', \n", + " 'end_local_dt_weekday', 'end_local_dt_year', 'end_place', 'end_ts', 'expectation', 'expected_trip', \n", + " 'inferred_labels', 'inferred_section_summary', 'inferred_trip', 'metadata_write_ts', 'mode_confirm', \n", + " 'section_durations', 'section_modes', 'source', 'start_fmt_time', 'start_loc', 'start_local_dt_day', \n", + " 'start_local_dt_minute', 'start_local_dt_month', 'start_local_dt_second', \n", + " 'start_local_dt_timezone', 'start_local_dt_weekday', 'start_local_dt_year', 'start_place', \n", + " 'start_ts', 'user_id_join', 'user_input', 'survey_user_id', 'section_distances',\n", + " 'data.local_dt.year', 'data.local_dt.month', 'data.local_dt.day', 'data.local_dt.hour', \n", + " 'data.local_dt.minute', 'data.local_dt.second', 'data.local_dt.weekday', 'data.local_dt.timezone',\n", + " 'data.fmt_time'\n", + "]\n", + "\n", + "for col in to_drop:\n", + " if col in filtered_trips.columns:\n", + " filtered_trips.drop(columns=[col], inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2937d4ef", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_trips.rename({'start_local_dt_hour': 'start:hour', 'end_local_dt_hour': 'end:hour'}, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87c7fc92", + "metadata": {}, + "outputs": [], + "source": [ + "print(filtered_trips.columns.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ea36cad", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "display(filtered_trips.head())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7018bf4", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"Done processing for {CURRENT_DB=}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0eacc539", + "metadata": {}, + "outputs": [], + "source": [ + "targets = ['p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown']\n", + "\n", + "# Rename and map targets.\n", + "filtered_trips.rename(columns={'replaced_mode': 'target'}, inplace=True)\n", + "filtered_trips.replace({'target': {t: ix+1 for ix, t in enumerate(targets)}}, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50d3eaec", + "metadata": {}, + "outputs": [], + "source": [ + "display(filtered_trips.target.unique())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31f35a04", + "metadata": {}, + "outputs": [], + "source": [ + "savepath = Path('./data/filtered_data')\n", + "\n", + "if not savepath.exists():\n", + " savepath.mkdir()\n", + "\n", + "filtered_trips.to_csv(savepath / f'preprocessed_data_{CURRENT_DB}.csv', index=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/replacement_mode_modeling/02_run_trip_level_models.py b/replacement_mode_modeling/02_run_trip_level_models.py new file mode 100644 index 00000000..3976ee10 --- /dev/null +++ b/replacement_mode_modeling/02_run_trip_level_models.py @@ -0,0 +1,491 @@ +from enum import Enum +import random +import warnings +import argparse +from pathlib import Path +from collections import Counter + +# Math and graphing. +import pandas as pd +import numpy as np +import seaborn as sns +import matplotlib.pyplot as plt + +# sklearn imports. +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import StandardScaler +from sklearn.linear_model import LinearRegression +from sklearn.metrics import f1_score, r2_score, ConfusionMatrixDisplay +from scipy.special import kl_div +from sklearn.metrics import classification_report +from sklearn.model_selection import GridSearchCV, StratifiedGroupKFold +from pprint import pprint +from sklearn.inspection import permutation_importance +from time import perf_counter +from sklearn.ensemble import RandomForestClassifier + +warnings.simplefilter(action='ignore', category=Warning) + +# Global experiment flags and variables. +SEED = 13210 +TARGETS = ['p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown'] +MAP = {ix+1:t for ix, t in enumerate(TARGETS)} + +CV = False + +# Set the Numpy seed too. +random.seed(SEED) +np.random.seed(SEED) + +class SPLIT_TYPE(Enum): + INTRA_USER = 0 + INTER_USER = 1 + TARGET = 2 + MODE = 3 + HIDE_USER = 4 + + +class SPLIT(Enum): + TRAIN = 0 + TEST = 1 + + +def get_train_test_splits(data: pd.DataFrame, how=SPLIT_TYPE, test_ratio=0.2, shuffle=True): + + if how == SPLIT_TYPE.INTER_USER: + + X = data.drop(columns=['target']) + y = data['target'].values + groups = data.user_id.values + + # n_splits determines split size. So n=5, is 20% for each split, which is what we want. + splitter = StratifiedGroupKFold(n_splits=5, shuffle=shuffle, random_state=SEED) + # splitter = GroupKFold(n_splits=5) + + for train_index, test_index in splitter.split(X, y, groups): + X_tr = data.iloc[train_index, :] + X_te = data.iloc[test_index, :] + + # Iterate only once and break. + break + + return X_tr, X_te, None + + elif how == SPLIT_TYPE.INTRA_USER: + + # There are certain users with only one observation. What do we do with those? + # As per the mobilitynet modeling pipeline, we randomly assign them to either the + # training or test set. + + value_counts = data.user_id.value_counts() + single_count_ids = value_counts[value_counts == 1].index + + data_filtered = data.loc[~data.user_id.isin(single_count_ids), :].reset_index(drop=True) + data_single_counts = data.loc[data.user_id.isin(single_count_ids), :].reset_index(drop=True) + + X_tr, X_te = train_test_split( + data_filtered, test_size=test_ratio, shuffle=shuffle, stratify=data_filtered.user_id, + random_state=SEED + ) + + data_single_counts['assigned'] = np.random.choice(['train', 'test'], len(data_single_counts)) + X_tr_merged = pd.concat( + [X_tr, data_single_counts.loc[data_single_counts.assigned == 'train', :].drop( + columns=['assigned'], inplace=False + )], + ignore_index=True, axis=0 + ) + + X_te_merged = pd.concat( + [X_te, data_single_counts.loc[data_single_counts.assigned == 'test', :].drop( + columns=['assigned'], inplace=False + )], + ignore_index=True, axis=0 + ) + + return X_tr_merged, X_te_merged, None + + elif how == SPLIT_TYPE.TARGET: + + X_tr, X_te = train_test_split( + data, test_size=test_ratio, shuffle=shuffle, stratify=data.target, + random_state=SEED + ) + + return X_tr, X_te, None + + elif how == SPLIT_TYPE.MODE: + X_tr, X_te = train_test_split( + data, test_size=test_ratio, shuffle=shuffle, stratify=data.section_mode_argmax, + random_state=SEED + ) + + return X_tr, X_te, None + + + elif how == SPLIT_TYPE.HIDE_USER: + users = data.user_id.value_counts(normalize=True) + percentiles = users.quantile([0.25, 0.5, 0.75]) + + low_trip_users = users[users <= percentiles[0.25]].index + mid_trip_users = users[(percentiles[0.25] <= users) & (users <= percentiles[0.5])].index + high_trip_users = users[(percentiles[0.5] <= users) & (users <= percentiles[0.75])].index + + # select one from each randomly. + user1 = np.random.choice(low_trip_users) + user2 = np.random.choice(mid_trip_users) + user3 = np.random.choice(high_trip_users) + + print(f"Users picked: {user1}, {user2}, {user3}") + + # Remove these users from the entire dataset. + held_out = data.loc[data.user_id.isin([user1, user2, user3]), :].reset_index(drop=True) + remaining = data.loc[~data.user_id.isin([user1, user2, user3]), :].reset_index(drop=True) + + # Split randomly. + X_tr, X_te = train_test_split( + remaining, test_size=test_ratio, shuffle=shuffle, random_state=SEED + ) + + return X_tr, X_te, held_out + + raise NotImplementedError("Unknown split type") + + +def get_duration_estimate(df: pd.DataFrame, dset: SPLIT, model_dict: dict): + + X_features = ['section_distance_argmax', 'mph'] + + if dset == SPLIT.TRAIN and model_dict is None: + model_dict = dict() + + if dset == SPLIT.TEST and model_dict is None: + raise AttributeError("Expected model dict for testing.") + + if dset == SPLIT.TRAIN: + for section_mode in df.section_mode_argmax.unique(): + section_data = df.loc[df.section_mode_argmax == section_mode, :] + if section_mode not in model_dict: + model_dict[section_mode] = dict() + + model = LinearRegression(fit_intercept=True) + + X = section_data[X_features] + Y = section_data[['section_duration_argmax']] + + model.fit(X, Y.values.ravel()) + + r2 = r2_score(y_pred=model.predict(X), y_true=Y.values.ravel()) + print(f"\t-> Train R2 for {section_mode}: {r2}") + + model_dict[section_mode]['model'] = model + + elif dset == SPLIT.TEST: + for section_mode in df.section_mode_argmax.unique(): + section_data = df.loc[df.section_mode_argmax == section_mode, :] + X = section_data[X_features] + Y = section_data[['section_duration_argmax']] + + y_pred = model_dict[section_mode]['model'].predict(X) + r2 = r2_score(y_pred=y_pred, y_true=Y.values.ravel()) + print(f"\t-> Test R2 for {section_mode}: {r2}") + + # Create the new columns for the duration. + new_columns = ['p_micro','no_trip','s_car','transit','car','s_micro','ridehail','walk','unknown'] + df[TARGETS] = 0 + df['temp'] = 0 + + for section in df.section_mode_argmax.unique(): + X_section = df.loc[df.section_mode_argmax == section, X_features] + + # broadcast to all columns. + df.loc[df.section_mode_argmax == section, 'temp'] = model_dict[section]['model'].predict(X_section) + + for c in TARGETS: + df[c] = df['av_' + c] * df['temp'] + + df.drop(columns=['temp'], inplace=True) + + df.rename(columns=dict([(x, 'tt_'+x) for x in TARGETS]), inplace=True) + + # return model_dict, result_df + return model_dict, df + +# Some helper functions that will help ease redundancy in the code. + +def drop_columns(df: pd.DataFrame): + to_drop = ['section_mode_argmax', 'available_modes', 'user_id'] + + # Drop section_mode_argmax and available_modes. + return df.drop( + columns=to_drop, + inplace=False + ) + + +def scale_values(df: pd.DataFrame, split: SPLIT, scalers=None): + # Scale costs using StandardScaler. + costs = df[[c for c in df.columns if 'cost_' in c]].copy() + times = df[[c for c in df.columns if 'tt_' in c or 'duration' in c]].copy() + distances = df[[c for c in df.columns if 'distance' in c or 'mph' in c]].copy() + + print( + "Cost columns to be scaled: ", costs.columns,"\nTime columns to be scaled: ", times.columns, \ + "\nDistance columns to be scaled: ", distances.columns + ) + + if split == SPLIT.TRAIN and scalers is None: + cost_scaler = StandardScaler() + tt_scaler = StandardScaler() + dist_scaler = StandardScaler() + + cost_scaled = pd.DataFrame( + cost_scaler.fit_transform(costs), + columns=costs.columns, + index=costs.index + ) + + tt_scaled = pd.DataFrame( + tt_scaler.fit_transform(times), + columns=times.columns, + index=times.index + ) + + dist_scaled = pd.DataFrame( + dist_scaler.fit_transform(distances), + columns=distances.columns, + index=distances.index + ) + + elif split == SPLIT.TEST and scalers is not None: + + cost_scaler, tt_scaler, dist_scaler = scalers + + cost_scaled = pd.DataFrame( + cost_scaler.transform(costs), + columns=costs.columns, + index=costs.index + ) + + tt_scaled = pd.DataFrame( + tt_scaler.transform(times), + columns=times.columns, + index=times.index + ) + + dist_scaled = pd.DataFrame( + dist_scaler.transform(distances), + columns=distances.columns, + index=distances.index + ) + + else: + raise NotImplementedError("Unknown split") + + # Drop the original columns. + df.drop( + columns=costs.columns.tolist() + times.columns.tolist() + distances.columns.tolist(), + inplace=True + ) + + df = df.merge(right=cost_scaled, left_index=True, right_index=True) + df = df.merge(right=tt_scaled, left_index=True, right_index=True) + df = df.merge(right=dist_scaled, left_index=True, right_index=True) + + return df, (cost_scaler, tt_scaler, dist_scaler) + + +def train(X_tr, Y_tr): + if CV: + + model = RandomForestClassifier(random_state=SEED) + + # We want to build bootstrapped trees that would not always use all the features. + param_set2 = { + 'n_estimators': [150, 200, 250], + 'min_samples_split': [2, 3, 4], + 'min_samples_leaf': [1, 2, 3], + 'class_weight': ['balanced_subsample'], + 'max_features': [None, 'sqrt'], + 'bootstrap': [True] + } + + cv_set2 = StratifiedKFold(n_splits=3, shuffle=True, random_state=SEED) + + clf_set2 = GridSearchCV(model, param_set2, cv=cv_set2, n_jobs=-1, scoring='f1_weighted', verbose=1) + + start = perf_counter() + + clf_set2.fit( + X_tr, + Y_tr + ) + + time_req = (perf_counter() - start)/60. + + best_model = clf_set2.best_estimator_ + else: + best_model = RandomForestClassifier( + n_estimators=150, + max_depth=None, + min_samples_leaf=2, + bootstrap=True, + class_weight='balanced_subsample', + random_state=SEED, + n_jobs=-1 + ).fit(X_tr, Y_tr) + + return best_model + + +def predict(model, X_tr, Y_tr, X_te, Y_te): + + y_test_pred = model.predict(X_te) + y_train_pred = model.predict(X_tr) + + train_f1 = f1_score( + y_true=Y_tr, + y_pred=y_train_pred, + average='weighted', + zero_division=0. + ) + + test_f1 = f1_score( + y_true=Y_te, + y_pred=y_test_pred, + average='weighted', + zero_division=0. + ) + + return y_train_pred, train_f1, y_test_pred, test_f1 + + +def run_sampled_sweep(df: pd.DataFrame, dir_name: Path, **kwargs): + + targets = TARGETS.copy() + + split = kwargs.pop('split', None) + + try: + train_data, test_data, hidden_data = get_train_test_splits(data=df, how=split, shuffle=True) + except Exception as e: + print(e) + return + + params, train_data = get_duration_estimate(train_data, SPLIT.TRAIN, None) + _, test_data = get_duration_estimate(test_data, SPLIT.TEST, params) + + train_data = drop_columns(train_data) + test_data = drop_columns(test_data) + + X_tr, Y_tr = train_data.drop(columns=['target'], inplace=False), train_data.target.values.ravel() + X_te, Y_te = test_data.drop(columns=['target'], inplace=False), test_data.target.values.ravel() + + model = train(X_tr, Y_tr) + tr_preds, tr_f1, te_preds, te_f1 = predict(model, X_tr, Y_tr, X_te, Y_te) + + print(f"\t-> Train F1: {tr_f1}, Test F1: {te_f1}") + + importance = sorted( + zip( + model.feature_names_in_, + model.feature_importances_ + ), + key=lambda x: x[-1], reverse=True + ) + + with open(dir_name / 'f1_scores.txt', 'w') as f: + f.write(f"Train F1: {tr_f1}\nTest F1: {te_f1}") + + importance_df = pd.DataFrame(importance, columns=['feature_name', 'importance']) + importance_df.to_csv(dir_name / 'feature_importance.csv', index=False) + + # target_names = [MAP[x] for x in np.unique(Y_te)] + + with open(dir_name / 'classification_report.txt', 'w') as f: + f.write(classification_report(y_true=Y_te, y_pred=te_preds)) + + if split == SPLIT_TYPE.HIDE_USER and hidden_data is not None: + _, hidden_data = get_duration_estimate(hidden_data, SPLIT.TEST, params) + hidden_data = drop_columns(hidden_data) + + X_hid, Y_hid = hidden_data.drop(columns=['target'], inplace=False), hidden_data.target.values.ravel() + + tr_preds, tr_f1, te_preds, te_f1 = predict(model, X_tr, Y_tr, X_hid, Y_hid) + print(f"\t\t ---> Hidden user F1: {te_f1} <---") + + fig, ax = plt.subplots(figsize=(7, 7)) + cm = ConfusionMatrixDisplay.from_estimator( + model, + X=X_te, + y=Y_te, + ax=ax + ) + # ax.set_xticklabels(target_names, rotation=45) + # ax.set_yticklabels(target_names) + fig.tight_layout() + plt.savefig(dir_name / 'test_confusion_matrix.png') + plt.close('all') + + +def save_metadata(dir_name: Path, **kwargs): + with open(dir_name / 'metadata.txt', 'w') as f: + for k, v in kwargs.items(): + f.write(f"{k}: {v}\n") + + + +if __name__ == "__main__": + + datasets = sorted(list(Path('./data/filtered_data').glob('preprocessed_data_*.csv'))) + + start = perf_counter() + + for dataset in datasets: + name = dataset.name.replace('.csv', '') + + print(f"Starting modeling for dataset = {name}") + + data = pd.read_csv(dataset) + data.drop_duplicates(inplace=True) + data.dropna(inplace=True) + + if 'deprecatedID' in data.columns: + data.drop(columns=['deprecatedID'], inplace=True) + if 'data.key' in data.columns: + data.drop(columns=['data.key'], inplace=True) + + # These two lines make all the difference. + data.sort_values(by=['user_id'], ascending=True, inplace=True) + data = data[sorted(data.columns.tolist())] + + print("Beginning sweeps.") + + # args = parse_args() + sweep_number = 1 + + root = Path('./outputs/benchmark_results') + if not root.exists(): + root.mkdir() + + for split in [SPLIT_TYPE.INTER_USER, SPLIT_TYPE.INTRA_USER, SPLIT_TYPE.TARGET, SPLIT_TYPE.MODE, SPLIT_TYPE.HIDE_USER]: + kwargs = { + 'dataset': name, + 'split': split + } + + dir_name = root / f'benchmark_{name}_{sweep_number}' + + if not dir_name.exists(): + dir_name.mkdir() + + print(f"\t-> Running sweep #{sweep_number} with metadata={str(kwargs)}") + save_metadata(dir_name, **kwargs) + run_sampled_sweep(data.copy(), dir_name, **kwargs) + print(f"Completed benchmarking for {sweep_number} experiment.") + print(50*'-') + sweep_number += 1 + + elapsed = perf_counter() - start + + print(f"Completed sweeps in {elapsed/60.} minutes") \ No newline at end of file diff --git a/replacement_mode_modeling/03_user_level_models.ipynb b/replacement_mode_modeling/03_user_level_models.ipynb new file mode 100644 index 00000000..da064680 --- /dev/null +++ b/replacement_mode_modeling/03_user_level_models.ipynb @@ -0,0 +1,1120 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "04ccf092", + "metadata": {}, + "source": [ + "## Some important points to remember:\n", + "\n", + "### We want to experiment with two types of models:\n", + "\n", + "\n", + "1. have one row per user, so that when predicting modes for a new user, we pick the \"similar user\" or users and determine the replaced mode\n", + " - In this, the traditional approach would only use demographics for the user features, we may experiment with some summaries of the trip data that will function as some level of \"fingerprint\" for the user. Ideally we would be able to show that this performs better than demographics alone\n", + " - Note also that the original method that you had outlined where the training set is a list of trips (O()) is a third approach which we will be comparing these two against" + ] + }, + { + "cell_type": "markdown", + "id": "c0c1ee88", + "metadata": {}, + "source": [ + "Target order:\n", + "\n", + "```\n", + "['p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown']\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21ef0f2e", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import random\n", + "import os\n", + "import pickle\n", + "import ast\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.ensemble import RandomForestClassifier\n", + "from sklearn.metrics import r2_score, f1_score, log_loss\n", + "from sklearn.model_selection import train_test_split, RandomizedSearchCV, StratifiedKFold, KFold\n", + "from sklearn.neighbors import KNeighborsClassifier\n", + "from sklearn.cluster import KMeans\n", + "from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances\n", + "from enum import Enum\n", + "from scipy.stats import uniform\n", + "from typing import List, Dict, Union\n", + "from pandas.api.types import is_numeric_dtype\n", + "from sklearn.manifold import TSNE\n", + "from multiprocessing import cpu_count\n", + "\n", + "pd.set_option('display.max_columns', 100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fef98692", + "metadata": {}, + "outputs": [], + "source": [ + "SEED = 13210\n", + "\n", + "np.random.seed(SEED)\n", + "random.seed(SEED)\n", + "\n", + "SimilarityMetric = Enum('SimilarityMetric', ['COSINE', 'EUCLIDEAN', 'KNN', 'KMEANS'])\n", + "GroupType = Enum('GroupType', ['GROUPBY', 'CUT'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79f8c51a", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv('./data/filtered_data/preprocessed_data_Stage_database.csv')\n", + "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_durham.csv')\n", + "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_mm_masscec.csv')\n", + "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_ride2own.csv')\n", + "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "915e9d6f", + "metadata": {}, + "outputs": [], + "source": [ + "df.groupby('user_id')['target'].apply(lambda x: x.value_counts().idxmax()).unique()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72793473", + "metadata": {}, + "outputs": [], + "source": [ + "print(df.columns.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "765f08ff", + "metadata": {}, + "outputs": [], + "source": [ + "def generate_tsne_plots(df: pd.DataFrame, **kwargs):\n", + " \n", + " df = df.copy()\n", + " \n", + " # Important - if not cast as a category, seaborn considers this as a numerical value.\n", + " df.target = df.target.astype('category')\n", + " \n", + " # print(\"Unique targets: \", df.target.unique())\n", + " \n", + " # According to the docs, > consider choosing a perplexity between 5 and 50.\n", + " tsne = TSNE(\n", + " n_components=2,\n", + " perplexity=kwargs.pop('perplexity', 5),\n", + " n_iter=kwargs.pop('n_iter', 2000),\n", + " metric=kwargs.pop('metric', 'cosine'),\n", + " random_state=SEED,\n", + " n_jobs=os.cpu_count()\n", + " )\n", + " \n", + " if df.index.name == 'user_id':\n", + " df.reset_index(drop=False, inplace=True)\n", + " \n", + " if 'user_id' in df.columns:\n", + " df.drop(columns=['user_id'], inplace=True)\n", + " \n", + " targets = df.target.values\n", + " df.drop(columns=['target'], inplace=True)\n", + " \n", + " projected = tsne.fit_transform(df)\n", + " \n", + " fig, ax = plt.subplots()\n", + " sns.scatterplot(x=projected[:, 0], y=projected[:, 1], hue=targets, ax=ax)\n", + " ax.set(xlabel='Embedding dimension 1', ylabel='Embedding dimension 2', title='t-SNE plot for data')\n", + " plt.show()\n", + " \n", + " return projected" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfe76e8c", + "metadata": {}, + "outputs": [], + "source": [ + "def get_mode_coverage(df: pd.DataFrame):\n", + " \n", + " coverage_df = df.groupby(['user_id', 'section_mode_argmax']).size().unstack(fill_value=0)\n", + " coverage_df.columns = ['coverage_' + str(c) for c in coverage_df.columns]\n", + " \n", + " # As a preventative measure.\n", + " coverage_df.fillna(0, inplace=True)\n", + " \n", + " # Normalize over rows.\n", + " coverage_df.iloc[:, 1:] = coverage_df.iloc[:, 1:].div(coverage_df.iloc[:, 1:].sum(axis=1), axis=0)\n", + " \n", + " return coverage_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75313008", + "metadata": {}, + "outputs": [], + "source": [ + "def get_trip_summaries(df: pd.DataFrame, group_key: str, feature_list: List[str], **kwargs):\n", + " \n", + " def get_feature_summaries(trip_feature: str, is_ordinal: bool = False):\n", + " \n", + " if is_numeric_dtype(df[group_key]):\n", + " col_prefix = f'{trip_feature}_mean_cut'\n", + " if not use_qcut:\n", + " grouper = df.groupby(['user_id', pd.cut(df[group_key], n_cuts)])[trip_feature]\n", + " else:\n", + " grouper = df.groupby(['user_id', pd.qcut(df[group_key], n_cuts)])[trip_feature]\n", + " else:\n", + " grouper = df.groupby(['user_id', group_key])[trip_feature]\n", + " \n", + " if not is_ordinal:\n", + " # A mean of 0 is an actual value.\n", + " \n", + " mean = grouper.mean().unstack(level=-1, fill_value=-1.)\n", + " \n", + " mean.columns = [f'{trip_feature}_mean_' + str(c) for c in mean.columns]\n", + " \n", + " # Same with percentiles - 0 is an actual value.\n", + " median = grouper.median().unstack(level=-1, fill_value=-1.)\n", + " median.columns = [f'{trip_feature}_median_' + str(c) for c in median.columns]\n", + " \n", + " iqr_df = grouper.quantile([0.25, 0.75]).unstack(level=-1)\n", + " iqr = (iqr_df[0.75] - iqr_df[0.25]).unstack(level=-1)\n", + " iqr.fillna(-1., inplace=True)\n", + " iqr.columns = [f'{trip_feature}_iqr_' + str(c) for c in iqr.columns]\n", + "\n", + " # Now merge.\n", + " merged = mean.copy()\n", + " merged = merged.merge(right=median, left_index=True, right_index=True)\n", + " merged = merged.merge(right=iqr, left_index=True, right_index=True)\n", + " \n", + " merged.fillna(-1., inplace=True)\n", + "\n", + " return merged\n", + " \n", + " # 0 is OK to indicate NaN values.\n", + " f_mode = grouper.apply(\n", + " lambda x: x.value_counts().idxmax()\n", + " ).unstack(fill_value=0.)\n", + " \n", + " f_mode.columns = [f'{trip_feature}_mode_' + str(c) for c in f_mode.columns]\n", + " f_mode.fillna(0., inplace=True)\n", + " \n", + " return f_mode\n", + " \n", + " assert group_key not in feature_list, \"Cannot perform grouping and summarization of the same feature.\"\n", + " \n", + " # Optional kwarg for number of cuts for numeric dtype grouping.\n", + " # Default is 3: short, medium, long trip types:\n", + " # For e.g., if the group key is 'section_duration', it will be cut into three equally-sized bins,\n", + " # However, an alternative is also present - we could use qcut() instead, which would ensure that\n", + " # each bin has roughly the same number of samples.\n", + " n_cuts = kwargs.pop('n_cuts', 3)\n", + " use_qcut = kwargs.pop('use_qcut', False)\n", + " \n", + " # This will be the dataframe that all subsequent features will join to.\n", + " feature_df = None\n", + " \n", + " for ix, feature in enumerate(feature_list):\n", + " is_ordinal = feature == 'start_local_dt_hour' or feature == 'end_local_dt_hour'\n", + " if ix == 0:\n", + " feature_df = get_feature_summaries(feature, is_ordinal)\n", + " else:\n", + " next_feature_df = get_feature_summaries(feature, is_ordinal)\n", + " feature_df = feature_df.merge(right=next_feature_df, left_index=True, right_index=True)\n", + " \n", + " return feature_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63617ada", + "metadata": {}, + "outputs": [], + "source": [ + "def get_demographic_data(df: pd.DataFrame, **trip_kwargs):\n", + " \n", + " '''\n", + " A method that returns a U x (D + t) matrix, where U = number of users,\n", + " D = number of demographic features, t (optional) = number of trip summary features.\n", + " \n", + " When use_trip_summaries=True, the 'available_modes' column is dropped in favor of\n", + " the already-preprocessed av_ columns. This is because we want to incorporate trip-level\n", + " information into the data. When the argument is False, we want to SOLELY use demographics.\n", + " '''\n", + " \n", + " trip_features_to_use = trip_kwargs.pop('trip_features', None)\n", + " trip_group_key = trip_kwargs.pop('trip_grouping', 'section_mode_argmax')\n", + " \n", + " demographics = [ \n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category', 'n_residence_members', \n", + " 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles',\n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'n_working_residents', \n", + " \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", + " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", + " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + " 'primary_job_description_Education', 'primary_job_description_Food service', \n", + " 'primary_job_description_Linecook', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Medical/healthcare', 'primary_job_description_Non-profit program manager', \n", + " 'primary_job_description_Other', 'primary_job_description_Professional, managerial, or technical', \n", + " 'primary_job_description_Sales or service', 'primary_job_description_Self employed', \n", + " 'primary_job_description_food service', 'gender_Man', 'gender_Nonbinary/genderqueer/genderfluid', \n", + " 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", + " 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', 'age_31___35_years_old', \n", + " 'age_36___40_years_old', 'age_41___45_years_old', 'age_46___50_years_old', 'age_51___55_years_old', \n", + " 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old', 'av_transit', 'av_no_trip', \n", + " 'av_p_micro', 'av_s_micro', 'av_ridehail', 'av_unknown', 'av_walk', 'av_car', 'av_s_car', \n", + " ]\n", + " \n", + " # Retain only the first instance of each user and subset the columns.\n", + " filtered = df.groupby('user_id').first()[demographics]\n", + " \n", + " # Get the targets.\n", + " targets = df.groupby('user_id')['target'].apply(lambda x: x.value_counts().idxmax())\n", + " \n", + " filtered = filtered.merge(right=targets, left_index=True, right_index=True)\n", + " \n", + " if trip_features_to_use is None or len(trip_features_to_use) == 0:\n", + "# # Use the available modes as indicators.\n", + "# return encode_availability(filtered)\n", + " return filtered\n", + " \n", + " # -----------------------------------------------------------\n", + " # Reaching here means that we need to include trip summaries\n", + " # -----------------------------------------------------------\n", + " \n", + " # If trip summaries are to be used, then re-use the preprocessed availability features.\n", + " availability = df[['user_id'] + [c for c in df.columns if 'av_' in c]]\n", + " availability = availability.groupby('user_id').first()\n", + " \n", + " # For every user, generate the global trip-level summaries.\n", + " global_aggs = df.groupby('user_id').agg({'duration': 'mean', 'distance': 'mean'})\n", + " \n", + " # coverage.\n", + " coverage = get_mode_coverage(df)\n", + " \n", + " # Trip-level features.\n", + " trip_features = get_trip_summaries(\n", + " df=df, \n", + " group_key=trip_group_key, \n", + " feature_list=trip_features_to_use,\n", + " use_qcut=trip_kwargs.pop('use_qcut', False)\n", + " )\n", + " \n", + " targets = df.groupby('user_id')['target'].apply(lambda x: x.value_counts().idxmax())\n", + " \n", + " trip_features = trip_features.merge(right=coverage, left_index=True, right_index=True)\n", + " trip_features = trip_features.merge(right=global_aggs, left_index=True, right_index=True)\n", + " \n", + " # Finally, join with availability indicators and targets.\n", + " trip_features = trip_features.merge(right=availability, left_index=True, right_on='user_id')\n", + " trip_features = trip_features.merge(right=targets, left_index=True, right_index=True)\n", + " \n", + " return trip_features.reset_index(drop=False)" + ] + }, + { + "cell_type": "markdown", + "id": "fedb51e8", + "metadata": {}, + "source": [ + "## Experiment 1: Only demographics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66421120", + "metadata": {}, + "outputs": [], + "source": [ + "## Educated suburban woman -> \n", + "# An embedding where:\n", + "# \"highest_education_Bachelor's degree\" == 1 or 'highest_education_Graduate degree or professional degree' == 1\n", + "# income_category >= 4 ( + more features that define 'suburban-ness')\n", + "# gender_Woman == 1\n", + "\n", + "demo_df = get_demographic_data(df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17196eaf", + "metadata": {}, + "outputs": [], + "source": [ + "display(demo_df.head())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c458c1a", + "metadata": {}, + "outputs": [], + "source": [ + "tsne_kwargs = {\n", + " 'perplexity': 6,\n", + " 'n_iter': 7500,\n", + " 'metric': 'cosine'\n", + "}\n", + "\n", + "## PLOT BY THE WAY IN WHICH PEOPLE USE THE SAME REPLACED MODE AND CHECK THE SIMILARITY.\n", + "\n", + "projections = generate_tsne_plots(demo_df, **tsne_kwargs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c023cf66", + "metadata": {}, + "outputs": [], + "source": [ + "# No stratification, pure random.\n", + "demo_df.reset_index(drop=False, inplace=True)\n", + "train, test = train_test_split(demo_df, test_size=0.2, random_state=SEED)\n", + "\n", + "TRAIN_USERS = train.user_id.unique().tolist()\n", + "TEST_USERS = test.user_id.unique().tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "376a4391", + "metadata": {}, + "outputs": [], + "source": [ + "print(train.shape[0], test.shape[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "630d6c08", + "metadata": {}, + "outputs": [], + "source": [ + "# Ensuring that no user information is leaked across sets.\n", + "assert train.shape[0] + test.shape[0] == len(df.user_id.unique())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef77c9c8", + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate_using_similarity(test_df, train_df, metric=SimilarityMetric.COSINE, **metric_kwargs):\n", + " \n", + " '''\n", + " This method treats each user row as a 'fingerprint' (embedding vector). We assume that we\n", + " have no idea about the test set labels. To find which replaced mode is most likely for the test\n", + " users, we compute the cosine similarity of each test user against the users in the training set.\n", + " For the most similar user, we use their target as a proxy for the test user's replaced mode.\n", + " This operates on the following intuition: If User A and User B are similar, then their replaced\n", + " modes are also similar.\n", + " '''\n", + " \n", + " tr_targets = train_df.target.values\n", + " tr = train_df.drop(columns=['target', 'user_id'], inplace=False).reset_index(drop=True, inplace=False)\n", + " \n", + " te_targets = test_df.target.values\n", + " te = test_df.drop(columns=['target', 'user_id'], inplace=False).reset_index(drop=True, inplace=False)\n", + " \n", + " if metric == SimilarityMetric.COSINE:\n", + " # Use cosine similarity to determine which element in the train set this user is closest to.\n", + " # Offset the columns from the second entry to exclude the user_id column.\n", + " # Returns a (n_te, n_tr) matrix.\n", + " sim = cosine_similarity(te.values, tr.values)\n", + " \n", + " # Compute the argmax across the train set.\n", + " argmax = np.argmax(sim, axis=1)\n", + "\n", + " # Index into the training targets to retrieve predicted label.\n", + " y_test_pred = tr_targets[argmax]\n", + " \n", + " elif metric == SimilarityMetric.EUCLIDEAN:\n", + " \n", + " # Here, we choose the embedding with the smallest L2 distance.\n", + " distances = euclidean_distances(te.values, tr.values)\n", + " \n", + " # We choose argmin\n", + " argmin = np.argmin(distances, axis=1)\n", + " \n", + " # Index into the targets.\n", + " y_test_pred = tr_targets[argmin]\n", + " \n", + " elif metric == SimilarityMetric.KNN:\n", + " \n", + " # Build the KNN classifier. By default, let it be 3.\n", + " knn = KNeighborsClassifier(\n", + " n_neighbors=metric_kwargs.pop('n_neighbors', 3),\n", + " weights='distance',\n", + " metric=metric_kwargs.pop('knn_metric', 'cosine'),\n", + " n_jobs=os.cpu_count()\n", + " )\n", + " \n", + " # Fit the data to the KNN model\n", + " knn.fit(tr, tr_targets)\n", + " \n", + " y_test_pred = knn.predict(te)\n", + " \n", + " elif metric == SimilarityMetric.KMEANS:\n", + " \n", + " # Build the model.\n", + " kmeans = KMeans(\n", + " n_clusters=metric_kwargs.pop('n_clusters', 8),\n", + " max_iter=metric_kwargs.pop('max_iter', 300),\n", + " n_init='auto',\n", + " random_state=SEED\n", + " )\n", + " \n", + " # Fit the clustering model\n", + " kmeans.fit(tr)\n", + " \n", + " # Construct the auxiliary df and merge with the training set.\n", + " label_df = pd.DataFrame({'label': kmeans.labels_, 'target': tr_targets}, index=tr.index)\n", + " \n", + " # Now, perform an inference on the test set.\n", + " predicted_labels = kmeans.predict(te)\n", + " \n", + " y_test_pred = []\n", + " for prediction in predicted_labels:\n", + " most_likely = label_df.loc[label_df.label == prediction, 'target'].value_counts().idxmax()\n", + " y_test_pred.append(most_likely)\n", + " \n", + " else:\n", + " raise NotImplementedError(\"Unknown similarity metric\")\n", + " \n", + " \n", + " f1 = f1_score(y_true=te_targets, y_pred=y_test_pred, average='weighted')\n", + " print(f\"Test F1 score using {metric.name} = {f1}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a95ad5e", + "metadata": {}, + "outputs": [], + "source": [ + "for metric in [\n", + " SimilarityMetric.COSINE, SimilarityMetric.EUCLIDEAN, SimilarityMetric.KNN, SimilarityMetric.KMEANS\n", + "]:\n", + " evaluate_using_similarity(test, train, metric, n_clusters=3)" + ] + }, + { + "cell_type": "markdown", + "id": "16e435a6", + "metadata": {}, + "source": [ + "Not bad - using just a simple random split gives us the following results:\n", + "\n", + "$allCEO$:\n", + "\n", + "```\n", + "Test F1 score using COSINE = 0.42692939244663386\n", + "Test F1 score using EUCLIDEAN = 0.4126984126984127\n", + "Test F1 score using KNN = 0.4393241167434716\n", + "Test F1 score using KMEANS = 0.4733893557422969\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81f0e842", + "metadata": {}, + "outputs": [], + "source": [ + "def custom_nll_scorer(clf, X, y):\n", + " \n", + " # [[yp1, yp2, yp3, ...], [yp1, yp3, ...]]\n", + " y_pred = clf.predict_proba(X)\n", + " \n", + " return -log_loss(y_true=y, y_pred=y_pred, labels=sorted(np.unique(y)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3a6af8f", + "metadata": {}, + "outputs": [], + "source": [ + "def estimate_using_model(train, test, **model_kwargs):\n", + " \n", + " cv = model_kwargs.pop('cv', None)\n", + " n_splits = model_kwargs.pop('n_splits', 5)\n", + " n_iter = model_kwargs.pop('n_iter', 500)\n", + " \n", + " if cv is None:\n", + " # Define the train-val splitter.\n", + " cv = KFold(n_splits=n_splits, shuffle=True, random_state=SEED)\n", + " \n", + " params = {\n", + " 'n_estimators': np.arange(100, 1001, 50),\n", + " 'max_depth': [i for i in range(5, 101, 5)],\n", + " 'ccp_alpha': np.linspace(0, 1, 10),\n", + " 'class_weight': ['balanced', 'balanced_subsample', None],\n", + " 'min_samples_split': np.arange(2, 25, 2),\n", + " 'min_samples_leaf': np.arange(1, 25)\n", + " }\n", + " \n", + " rf = RandomForestClassifier(random_state=SEED)\n", + " \n", + " # Search over hparams to minimize negative log likelihood. \n", + "# clf = RandomizedSearchCV(\n", + "# rf, params, n_iter=n_iter, scoring=custom_nll_scorer, \n", + "# n_jobs=os.cpu_count(), cv=cv, random_state=SEED,\n", + "# verbose=0\n", + "# )\n", + " \n", + " clf = RandomizedSearchCV(\n", + " rf, params, n_iter=n_iter, scoring='f1_weighted', \n", + " n_jobs=cpu_count(), cv=cv, random_state=SEED,\n", + " verbose=0\n", + " )\n", + " \n", + " X_tr = train.drop(columns=['user_id', 'target'])\n", + " y_tr = train.target.values.ravel()\n", + " \n", + " scorer = clf.fit(X_tr, y_tr)\n", + " \n", + " best_model = scorer.best_estimator_\n", + " \n", + " print(f\"Best val score = {scorer.best_score_}\")\n", + " \n", + " X_te = test.drop(columns=['user_id', 'target'])\n", + " \n", + " # Use the best model to compute F1 on the test set.\n", + " test_f1 = f1_score(y_true=test.target.values, y_pred=best_model.predict(X_te), average='weighted')\n", + " \n", + " print(f\"Test F1 = {test_f1}\")\n", + " \n", + " return best_model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2fab93ed", + "metadata": {}, + "outputs": [], + "source": [ + "model = estimate_using_model(train, test)" + ] + }, + { + "cell_type": "markdown", + "id": "2988c1b2", + "metadata": {}, + "source": [ + "Interesting! The model is slightly on par with K-Means!" + ] + }, + { + "cell_type": "markdown", + "id": "c6b77353", + "metadata": {}, + "source": [ + "## Experiment 2: Demographics with trip summaries" + ] + }, + { + "cell_type": "markdown", + "id": "bf7753d4", + "metadata": {}, + "source": [ + "Now that we've performed experiments with solely demographic data, let's expand the feature set by including \n", + "trip summary statistics. We would like this approach to do better than the aforementioned baselines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d46ab0f", + "metadata": {}, + "outputs": [], + "source": [ + "demo_plus_trips = get_demographic_data(\n", + " df, \n", + " trip_features=['mph', 'section_duration_argmax', 'section_distance_argmax', 'start_local_dt_hour', 'end_local_dt_hour']\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11c1ea2c", + "metadata": {}, + "outputs": [], + "source": [ + "demo_plus_trips.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6159c90a", + "metadata": {}, + "outputs": [], + "source": [ + "train = demo_plus_trips.loc[demo_plus_trips.user_id.isin(TRAIN_USERS), :]\n", + "test = demo_plus_trips.loc[demo_plus_trips.user_id.isin(TEST_USERS), :]\n", + "\n", + "print(train.shape[0], test.shape[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06e85bdd", + "metadata": {}, + "outputs": [], + "source": [ + "for metric in [\n", + " SimilarityMetric.COSINE, SimilarityMetric.EUCLIDEAN, SimilarityMetric.KNN, SimilarityMetric.KMEANS\n", + "]:\n", + " evaluate_using_similarity(test, train, metric, n_clusters=4)" + ] + }, + { + "cell_type": "markdown", + "id": "ba795489", + "metadata": {}, + "source": [ + "Great! Some improvement here and there.\n", + "\n", + "$allCEO$\n", + "```\n", + "Test F1 score using COSINE = 0.32098765432098775\n", + "Test F1 score using EUCLIDEAN = 0.36684303350970027\n", + "Test F1 score using KNN = 0.41269841269841273\n", + "Test F1 score using KMEANS = 0.4877344877344878\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9acd4b0b", + "metadata": {}, + "outputs": [], + "source": [ + "# Now, we try with the model\n", + "estimate_using_model(train, test)" + ] + }, + { + "cell_type": "markdown", + "id": "cd94c548", + "metadata": {}, + "source": [ + "Great! Compared to the previous model, we see definite improvements! I'm sure we can squeeze some more juice out of the models using fancy optimization, but as a baseline, these are good enough.\n", + "\n", + "\n", + "So, to recap:\n", + "$F1_{cosine} = 0.37$, $F1_{euclidean} = 0.33$, $F1_{knn} = 0.3$, $F1_{kmeans} = 0.36$, $F1_{RF} = 0.4215$" + ] + }, + { + "cell_type": "markdown", + "id": "8a8f6491", + "metadata": {}, + "source": [ + "### Different groupings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ce90367", + "metadata": {}, + "outputs": [], + "source": [ + "# trip_features = ['mph', 'section_duration_argmax', 'section_distance_argmax', 'start:hour', 'end:hour']\n", + "\n", + "# for group_mode in ['section_mode_argmax', 'section_distance_argmax', 'section_duration_argmax', 'duration', 'distance']:\n", + " \n", + "# if group_mode in trip_features:\n", + "# _ = trip_features.pop(trip_features.index(group_mode))\n", + " \n", + "# exp_df = get_demographic_data(\n", + "# df, \n", + "# trip_grouping=group_mode,\n", + "# trip_features=trip_features,\n", + "# use_qcut=True\n", + "# )\n", + " \n", + "# train, test = train_test_split(exp_df, test_size=0.2, random_state=SEED)\n", + " \n", + "# for sim in [\n", + "# SimilarityMetric.COSINE, SimilarityMetric.EUCLIDEAN, SimilarityMetric.KNN, SimilarityMetric.KMEANS\n", + "# ]:\n", + "# evaluate_using_similarity(test, train, sim, n_clusters=3)\n", + " \n", + "# # estimate_using_model(train, test, n_iter=200)\n", + " \n", + "# print(50*'=')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d53f945", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "_ = generate_tsne_plots(demo_plus_trips, perplexity=6, n_iter=7500)" + ] + }, + { + "cell_type": "markdown", + "id": "c339fcc6", + "metadata": {}, + "source": [ + "# Multi-level modeling" + ] + }, + { + "cell_type": "markdown", + "id": "213676ec", + "metadata": {}, + "source": [ + "In this approach, we want to piece together the similarity search and modeling processes. Here's a rough sketch of how it should be implemented:\n", + "\n", + "1. For every user in the training set, build a model using their entire trip history.\n", + "2. Consolidate these user-level models in data structure, preferably a dictionary.\n", + "3. Now, when we want to perform inference on a new user with no prior trips, we use the similarity search to get the user ID in the training set who is the most similar to the user in question.\n", + "4. We retrieve the model for this corresponding user and perform an inference. The hypothesis is that since the two users are similar, their trip substitution patterns are also similar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c48ee430", + "metadata": {}, + "outputs": [], + "source": [ + "def drop_columns(df: pd.DataFrame):\n", + " to_drop = [\n", + " 'source', 'end_ts', 'end_fmt_time', 'end_loc', 'raw_trip', 'start_ts', \n", + " 'start_fmt_time', 'start_loc', 'duration', 'distance', 'start_place', \n", + " 'end_place', 'cleaned_trip', 'inferred_labels', 'inferred_trip', 'expectation',\n", + " 'confidence_threshold', 'expected_trip', 'user_input', 'start:year', 'start:month', \n", + " 'start:day', 'start_local_dt_minute', 'start_local_dt_second', \n", + " 'start_local_dt_weekday', 'start_local_dt_timezone', 'end:year', 'end:month', 'end:day', \n", + " 'end_local_dt_minute', 'end_local_dt_second', 'end_local_dt_weekday', \n", + " 'end_local_dt_timezone', '_id', 'metadata_write_ts', 'additions', \n", + " 'mode_confirm', 'purpose_confirm', 'Mode_confirm', 'Trip_purpose', \n", + " 'original_user_id', 'program', 'opcode', 'Timestamp', 'birth_year', \n", + " 'available_modes', 'section_coordinates_argmax', 'section_mode_argmax'\n", + " ]\n", + " \n", + " # Drop section_mode_argmax and available_modes.\n", + " return df.drop(\n", + " columns=to_drop, \n", + " inplace=False\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca9e6e6a", + "metadata": {}, + "outputs": [], + "source": [ + "def construct_model_dictionary(train: pd.DataFrame):\n", + " \n", + " def train_on_user(user_id: str):\n", + " '''\n", + " Given the training set and the user ID to query, filter the dataset and\n", + " retain only the relevant trips. Then, create folds and optimize a model for this user.\n", + " Return the trained model instance.\n", + " '''\n", + " \n", + " user_data = train.loc[train.user_id == user_id, :].reset_index(drop=True)\n", + " \n", + " # Split user trips into train-test folds.\n", + " u_train, u_test = train_test_split(user_data, test_size=0.2, shuffle=True, random_state=SEED)\n", + " \n", + " user_model = estimate_using_model(\n", + " u_train, u_test, \n", + " n_iter=100\n", + " )\n", + " \n", + " return user_model\n", + " \n", + " for user in train.user_id.unique():\n", + " MODEL_DICT[user]['warm_start'] = train_on_user(user)\n", + " print(50*'=')\n", + " \n", + " print(\"\\nDone!\")" + ] + }, + { + "cell_type": "markdown", + "id": "2a035c16", + "metadata": {}, + "source": [ + "## Warm start:\n", + "\n", + "If the queried user has prior trips, we know that we we can harness the additional information. So if we encounter such a user, we will first find the most similar user (using only demographics). Once the most similar user is found, we query the trip model for the user and run inference through it.\n", + "\n", + "## Cold start:\n", + "\n", + "If the queried user has no prior trips, we will use the demo-only model. We first perform a similarity search and then run user inference through the demo-only model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "082c4e39", + "metadata": {}, + "outputs": [], + "source": [ + "class MultiLevelModel:\n", + " def __init__(self, model_dict: Dict, train: pd.DataFrame, test: pd.DataFrame, **model_kwargs):\n", + " \n", + " self._demographics = [\n", + " 'primary_job_commute_time', 'income_category', 'n_residence_members', 'n_residents_u18', \n", + " 'n_residents_with_license', 'n_motor_vehicles', 'available_modes', 'age', 'gender_Man', \n", + " 'gender_Man;Nonbinary/genderqueer/genderfluid', 'gender_Nonbinary/genderqueer/genderfluid', \n", + " 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", + " 'has_drivers_license_No', 'has_drivers_license_Prefer not to say', 'has_drivers_license_Yes', \n", + " 'has_multiple_jobs_No', 'has_multiple_jobs_Prefer not to say', 'has_multiple_jobs_Yes', \n", + " \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", + " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", + " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", + " 'primary_job_type_Full-time', 'primary_job_type_Part-time', 'primary_job_type_Prefer not to say', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + " 'primary_job_description_Education', 'primary_job_description_Food service', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Medical/healthcare', 'primary_job_description_Other', \n", + " 'primary_job_description_Professional, managerial, or technical', \n", + " 'primary_job_description_Sales or service', 'primary_job_commute_mode_Active transport', \n", + " 'primary_job_commute_mode_Car transport', 'primary_job_commute_mode_Hybrid', \n", + " 'primary_job_commute_mode_Public transport', 'primary_job_commute_mode_Unknown', \n", + " 'primary_job_commute_mode_WFH', 'is_overnight_trip', 'n_working_residents'\n", + " ]\n", + " \n", + " assert all([c in test.columns for c in self._demographics]), \"[test] Demographic features are missing!\"\n", + " assert all([c in train.columns for c in self._demographics]), \"[train] Demographic features are missing!\"\n", + " \n", + " self._mdict = model_dict\n", + " self._train = train\n", + " self._test = test\n", + " self.metric = model_kwargs.pop('metric', SimilarityMetric.COSINE)\n", + " \n", + " \n", + " def _phase1(self):\n", + " \n", + " tr = self._train.copy()\n", + " te = self._test.copy()\n", + " \n", + " if tr.columns.isin(['user_id', 'target']).sum() == 2:\n", + " tr = tr.drop(columns=['user_id', 'target']).reset_index(drop=True)\n", + " \n", + " if te.columns.isin(['user_id', 'target']).sum() == 2:\n", + " te = te.drop(columns=['user_id', 'target']).reset_index(drop=True)\n", + "\n", + " te_users = self._test.user_id.tolist()\n", + "\n", + " if self.metric == SimilarityMetric.COSINE:\n", + "\n", + " sim = cosine_similarity(te.values, tr.values)\n", + "\n", + " # Compute the argmax across the train set.\n", + " argmax = np.argmax(sim, axis=1)\n", + "\n", + " # Retrieve the user_id at these indices.\n", + " train_users = self._train.loc[argmax, 'user_id']\n", + "\n", + " elif self.metric == SimilarityMetric.EUCLIDEAN:\n", + "\n", + " sim = euclidean_distances(te.values, tr.values)\n", + "\n", + " # Compute the argmin here!\n", + " argmin = np.argmin(sim, axis=1)\n", + "\n", + " # Retrieve the train user_ids.\n", + " train_users = self._train.loc[argmin, 'user_id']\n", + "\n", + " return pd.DataFrame({'test_user_id': te_users, 'train_user_id': train_users})\n", + " \n", + " \n", + " def _phase2(self, sim_df: pd.DataFrame, cold_start: bool):\n", + " \n", + " prediction_df = list()\n", + " \n", + " # Now, we use the sim_df to run inference based on whether \n", + " for ix, row in sim_df.iterrows():\n", + " train_user = row['train_user_id']\n", + " \n", + " # Retrieve the appropriate model.\n", + " user_models = self._mdict.get(train_user, None)\n", + " \n", + " start_type = 'cold_start' if cold_start else 'warm_start'\n", + " \n", + " # which specific model?\n", + " sp_model = user_models.get(start_type, None)\n", + " \n", + " # Now get the test user data.\n", + " test_user = row['test_user_id']\n", + " \n", + " if cold_start:\n", + " test_data = self._test.loc[self._test.user_id == test_user, self._demographics]\n", + " test_data = test_data.iloc[0, :]\n", + " else:\n", + " test_data = self._test.loc[self._test.user_id == test_user, :]\n", + " \n", + " predictions = sp_model.predict(test_data)\n", + " \n", + " print(f\"test: [{test_user}], predictions: {predictions}\")\n", + " \n", + " \n", + " def execute_pipeline(self, cold_start: bool = False):\n", + " # For each test user, get the most similar train user.\n", + " sim_df = self._phase1()\n", + " \n", + " predictions = self._phase2(sim_df, cold_start)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb63632d", + "metadata": {}, + "outputs": [], + "source": [ + "# FULL DATA.\n", + "train = df.loc[df.user_id.isin(TRAIN_USERS), :]\n", + "test = df.loc[df.user_id.isin(TEST_USERS), :]\n", + "\n", + "train_counts = train.user_id.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2528eaa", + "metadata": {}, + "outputs": [], + "source": [ + "## We only want to train on users who have a good number of trips.\n", + "good_users = train_counts[train_counts >= 100].index\n", + "\n", + "bad_users = train_counts[train_counts < 100].index\n", + "\n", + "print(f\"Number of users filtered out of training: {len(bad_users)}\")\n", + "\n", + "filtered_train = train.loc[train.user_id.isin(good_users), :]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bae55b21", + "metadata": {}, + "outputs": [], + "source": [ + "# Full data.\n", + "\n", + "train_df = drop_columns(filtered_train)\n", + "test_df = drop_columns(test)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88d0e2d2", + "metadata": {}, + "outputs": [], + "source": [ + "print(train_df.shape, test_df.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37febd6d", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "model_dict = construct_model_dictionary(train_df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1249925", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/replacement_mode_modeling/04_FeatureClustering.ipynb b/replacement_mode_modeling/04_FeatureClustering.ipynb new file mode 100644 index 00000000..094d84c6 --- /dev/null +++ b/replacement_mode_modeling/04_FeatureClustering.ipynb @@ -0,0 +1,1108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "789df947", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import random\n", + "import os\n", + "import itertools\n", + "import pickle\n", + "import ast\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.colors as mcolors\n", + "import seaborn as sns\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances\n", + "from sklearn.metrics import davies_bouldin_score, calinski_harabasz_score, silhouette_score\n", + "from sklearn.preprocessing import MinMaxScaler, StandardScaler\n", + "from typing import List, Dict, Union\n", + "from pandas.api.types import is_numeric_dtype\n", + "from sklearn.cluster import DBSCAN, KMeans\n", + "from collections import Counter\n", + "\n", + "pd.set_option('display.max_columns', None)\n", + "\n", + "%matplotlib inline\n", + "\n", + "SEED = 13210\n", + "\n", + "np.random.seed(SEED)\n", + "random.seed(SEED)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aea4dda7", + "metadata": {}, + "outputs": [], + "source": [ + "DATA_SOURCES = [\n", + " ('./data/filtered_data/preprocessed_data_Stage_database.csv', 'allceo'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_durham.csv', 'durham'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_ride2own.csv', 'ride2own'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_mm_masscec.csv', 'masscec'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv', 'nicr')\n", + "]\n", + "\n", + "# Switch between 0-4\n", + "DB_NUMBER = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33ef3275", + "metadata": {}, + "outputs": [], + "source": [ + "# Change this name to something unique\n", + "CURRENT_DB = DATA_SOURCES[DB_NUMBER][1]\n", + "PATH = DATA_SOURCES[DB_NUMBER][0]\n", + "\n", + "df = pd.read_csv(PATH)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0d884a3", + "metadata": {}, + "outputs": [], + "source": [ + "df.target.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2281bdc", + "metadata": {}, + "outputs": [], + "source": [ + "df.rename(\n", + " columns={'end_local_dt_hour': 'end:hour', 'start_local_dt_hour': 'start:hour', 'replaced_mode': 'target'}, \n", + " inplace=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c22d6ac", + "metadata": {}, + "outputs": [], + "source": [ + "TARGETS = ['p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown']\n", + "MAP = {ix+1: t for (ix, t) in enumerate(TARGETS)}\n", + "TARGET_MAP = {v:k for k, v in MAP.items()}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "063f6124", + "metadata": {}, + "outputs": [], + "source": [ + "df.replace({'target': TARGET_MAP}, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cef8d45b", + "metadata": {}, + "outputs": [], + "source": [ + "# % of trips per mode.\n", + "trip_percents = df.groupby(['user_id'])['section_mode_argmax'].apply(lambda x: x.value_counts(normalize=True)).unstack(level=-1)\n", + "trip_percents.fillna(0., inplace=True)\n", + "\n", + "trip_percents.columns = ['coverage_'+x for x in trip_percents.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68c6af2d", + "metadata": {}, + "outputs": [], + "source": [ + "n_trips = pd.DataFrame(df.groupby('user_id').size(), columns=['n_trips'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eff378a7", + "metadata": {}, + "outputs": [], + "source": [ + "most_common_start = df.groupby('user_id')['start:hour'].apply(lambda x: x.value_counts().idxmax())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cffbd401", + "metadata": {}, + "outputs": [], + "source": [ + "most_common_end = df.groupby('user_id')['end:hour'].apply(lambda x: x.value_counts().idxmax())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1eb1633", + "metadata": {}, + "outputs": [], + "source": [ + "# % of distance in each primary sensed mode.\n", + "total_distance = df.groupby(['user_id', 'section_mode_argmax'])['section_distance_argmax'].sum().unstack(level=-1)\n", + "total_distance = total_distance.div(total_distance.sum(axis=1), axis=0)\n", + "total_distance.fillna(0., inplace=True)\n", + "total_distance.columns = ['pct_distance_' + x for x in total_distance.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9cc0a0f", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "figure1_df = trip_percents.merge(right=total_distance, left_index=True, right_index=True).merge(\n", + " right=n_trips, left_index=True, right_index=True\n", + ").merge(\n", + " right=most_common_start, left_index=True, right_index=True\n", + ").merge(right=most_common_end, left_index=True, right_index=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "750fbd0c", + "metadata": {}, + "outputs": [], + "source": [ + "# Normalize the last three columns.\n", + "\n", + "def min_max_normalize(col: pd.Series):\n", + " _max, _min = col.max(), col.min()\n", + " return pd.Series((col - _min)/(_max - _min))\n", + "\n", + "figure1_df['n_trips'] = min_max_normalize(figure1_df['n_trips'])\n", + "figure1_df['start:hour'] = np.sin(figure1_df['start:hour'].values)\n", + "figure1_df['end:hour'] = np.sin(figure1_df['end:hour'].values)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c3d1849", + "metadata": {}, + "outputs": [], + "source": [ + "figure1_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "598d82bc", + "metadata": {}, + "outputs": [], + "source": [ + "epsilons = np.linspace(1e-3, 1., 1000)\n", + "\n", + "best_eps = -np.inf\n", + "best_score = -np.inf\n", + "\n", + "for eps in epsilons:\n", + " model = DBSCAN(eps=eps).fit(figure1_df)\n", + " \n", + " if len(np.unique(model.labels_)) < 2:\n", + " continue\n", + " \n", + " score = silhouette_score(figure1_df, model.labels_)\n", + " if score > best_score:\n", + " best_eps = eps\n", + " best_score = score\n", + "\n", + "print(best_eps)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc89a42d", + "metadata": {}, + "outputs": [], + "source": [ + "'''\n", + "AlLCEO: eps=0.542\n", + "durham: eps=0.661\n", + "masscec: eps=0.64\n", + "'''\n", + "\n", + "clustering = DBSCAN(eps=0.8).fit(figure1_df)\n", + "\n", + "print(Counter(clustering.labels_))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05c9a7c4", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# After clustering, we would like to see what the replaced mode argmax distribution in each cluster is.\n", + "\n", + "labels = clustering.labels_\n", + "\n", + "for cix in np.unique(labels):\n", + " cluster_users = figure1_df.iloc[labels == cix,:].index\n", + " \n", + " print(f\"{len(cluster_users)} users in cluster {cix}\")\n", + " \n", + " # Now, for each user, look at the actual data and determine the replaced mode argmax distribution.\n", + " sub_df = df.loc[df.user_id.isin(cluster_users), :].reset_index(drop=True)\n", + " \n", + " sub_df['target'] = sub_df['target'].apply(lambda x: MAP[x])\n", + " \n", + " rm_argmax = sub_df.groupby('user_id')['target'].apply(lambda x: x.value_counts().idxmax())\n", + " fig, ax = plt.subplots()\n", + " rm_argmax.hist(ax=ax)\n", + " ax.set_title(f\"Replaced mode argmax distribution for users in cluster {cix}\")\n", + " ax.set_xlabel(\"Target\")\n", + " \n", + " plt.savefig(f'./outputs/{CURRENT_DB}__FIG1_cluster_{cix}_target_dist.png', dpi=300)\n", + " \n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2e8e117", + "metadata": {}, + "outputs": [], + "source": [ + "user_target_pct = pd.DataFrame()\n", + "\n", + "# For every user, compute the replaced mode distribution.\n", + "for user_id, user_data in df.groupby('user_id'):\n", + " \n", + " target_distribution = user_data['target'].value_counts(normalize=True)\n", + " target_distribution.rename(index=MAP, inplace=True)\n", + " user_target_pct = pd.concat([user_target_pct, target_distribution.to_frame(user_id).T])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99369dba", + "metadata": {}, + "outputs": [], + "source": [ + "user_target_pct.columns = ['pct_trips_' + str(x) for x in user_target_pct.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6cca3671", + "metadata": {}, + "outputs": [], + "source": [ + "target_distance = pd.DataFrame()\n", + "\n", + "# For every user, compute the replaced mode distribution.\n", + "for user_id, user_data in df.groupby('user_id'):\n", + " \n", + " # total_distance = user_data['distance'].sum()\n", + " distance_per_target = user_data.groupby('target')['section_distance_argmax'].sum()\n", + " distance_per_target.rename(index=MAP, inplace=True)\n", + " row = distance_per_target.to_frame(user_id).T\n", + " target_distance = pd.concat([target_distance, row])\n", + " \n", + "target_distance.columns = ['distance_' + str(x) for x in target_distance.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18093734", + "metadata": {}, + "outputs": [], + "source": [ + "target_duration = df.groupby(['user_id', 'target'])['section_duration_argmax'].sum().unstack()\n", + "target_duration.rename(columns=MAP, inplace=True)\n", + "target_duration.fillna(0., inplace=True)\n", + "target_duration.columns = ['duration_' + str(x) for x in target_duration.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8001a140", + "metadata": {}, + "outputs": [], + "source": [ + "target_df = user_target_pct.merge(right=target_distance, left_index=True, right_index=True).merge(\n", + " right=target_duration, left_index=True, right_index=True\n", + ")\n", + "\n", + "target_df.fillna(0., inplace=True)\n", + "\n", + "target_df = pd.DataFrame(\n", + " MinMaxScaler().fit_transform(target_df),\n", + " columns=target_df.columns,\n", + " index=target_df.index\n", + ")\n", + "\n", + "display(target_df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31fecc00", + "metadata": {}, + "outputs": [], + "source": [ + "epsilons = np.linspace(5e-3, 1., 1500)\n", + "best_score = -np.inf\n", + "best_eps = None\n", + "best_n = None\n", + "# alpha = 0.7\n", + "beta = 0.05\n", + "\n", + "for eps in epsilons:\n", + " for n in range(2, 30):\n", + " labels = DBSCAN(eps=eps, min_samples=n).fit(target_df).labels_\n", + " \n", + " n_unique = np.unique(labels)\n", + " n_outliers = len(labels[labels == -1])\n", + " \n", + " if n_outliers == len(labels) or len(n_unique) < 2:\n", + " continue\n", + " \n", + " # Encourage more clustering and discourage more outliers.\n", + " score = silhouette_score(target_df, labels) + (len(labels) - n_outliers)/n_outliers\n", + " \n", + " if score > best_score:\n", + " best_score = score\n", + " best_eps = eps\n", + " best_n = n\n", + "\n", + "print(f\"{best_score=}, {best_n=}, {best_eps=}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e39b41ba", + "metadata": {}, + "outputs": [], + "source": [ + "# 0.35 is a good value\n", + "\n", + "'''\n", + "allCEO = DBSCAN(eps=0.52, min_samples=2)\n", + "durham: DBSCAN(eps=best_eps, min_samples=2)\n", + "masscec: min_samples=2, eps=0.986724482988659\n", + "'''\n", + "\n", + "cl2 = DBSCAN(eps=best_eps, min_samples=2).fit(target_df)\n", + "# cl2 = KMeans(n_clusters=5).fit(target_df)\n", + "\n", + "Counter(cl2.labels_)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1dbf8763", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.decomposition import PCA\n", + "\n", + "tsfm = PCA(n_components=2).fit_transform(target_df)\n", + "\n", + "fig, ax = plt.subplots()\n", + "sns.scatterplot(x=tsfm[:,0], y=tsfm[:,1], c=cl2.labels_)\n", + "ax.set(xlabel='Latent Dim 0', ylabel='Latent Dim 1')\n", + "plt.savefig(f'./outputs/{CURRENT_DB}__Fig2__PCA_w_colors.png', dpi=300)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e444316", + "metadata": {}, + "outputs": [], + "source": [ + "print(df.columns.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0bc09b9", + "metadata": {}, + "outputs": [], + "source": [ + "# Per-cluster users.\n", + "from sklearn.preprocessing import OneHotEncoder\n", + "from sklearn.preprocessing import MinMaxScaler\n", + "from sklearn.ensemble import IsolationForest\n", + "from sklearn.svm import OneClassSVM\n", + "from sklearn.neighbors import LocalOutlierFactor\n", + "from sklearn.tree import DecisionTreeClassifier\n", + "\n", + "\n", + "demographic_cols = {\n", + " 'Stage_database': [\n", + " 'has_drivers_license', 'is_student', 'is_paid', \n", + " 'income_category', 'n_residence_members', 'n_residents_u18', 'n_residents_with_license', \n", + " 'n_motor_vehicles', 'has_medical_condition', 'ft_job', 'multiple_jobs', \n", + " 'n_working_residents', \"highest_education_Bachelor's degree\", \n", + " 'highest_education_Graduate degree or professional degree', \n", + " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", + " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + " 'primary_job_description_Education', 'primary_job_description_Food service', \n", + " 'primary_job_description_Linecook', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Medical/healthcare', 'primary_job_description_Non-profit program manager', \n", + " 'primary_job_description_Other', 'primary_job_description_Professional, managerial, or technical', \n", + " 'primary_job_description_Sales or service', 'primary_job_description_Self employed', \n", + " 'primary_job_description_food service', 'gender_Man', 'gender_Nonbinary/genderqueer/genderfluid', \n", + " 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", + " 'av_transit', 'av_no_trip', 'av_p_micro', 'av_s_micro', 'av_ridehail', 'av_unknown', 'av_walk', 'av_car', \n", + " 'av_s_car'\n", + " ] + [c for c in df.columns if 'age' in c],\n", + " 'durham': [\n", + " 'is_student', 'is_paid', 'has_drivers_license', \n", + " 'n_residents_u18', 'n_residence_members', 'income_category',\n", + " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition', \n", + " 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", + " 'highest_education_graduate_degree_or_professional_degree', \n", + " 'highest_education_high_school_graduate_or_ged', 'highest_education_less_than_a_high_school_graduate', \n", + " 'highest_education_some_college_or_associates_degree', \n", + " 'primary_job_description_Clerical or administrative support', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Other', 'primary_job_description_Professional, Manegerial, or Technical', \n", + " 'primary_job_description_Sales or service', 'gender_man', \n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman', \n", + " 'av_walk', 'av_unknown', 'av_no_trip', 'av_p_micro', 'av_transit', 'av_car', 'av_ridehail', \n", + " 'av_s_micro', 'av_s_car'\n", + " ] + [c for c in df.columns if 'age' in c],\n", + " 'masscec': [\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', \n", + " 'income_category', 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', \n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", + " 'highest_education_graduate_degree_or_professional_degree', \n", + " 'highest_education_high_school_graduate_or_ged', 'highest_education_less_than_a_high_school_graduate', \n", + " 'highest_education_prefer_not_to_say', 'highest_education_some_college_or_associates_degree', \n", + " 'primary_job_description_Clerical or administrative support', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Other', 'primary_job_description_Prefer not to say', \n", + " 'primary_job_description_Professional, Manegerial, or Technical', \n", + " 'primary_job_description_Sales or service', 'gender_man', 'gender_prefer_not_to_say', 'gender_woman', \n", + " 'av_p_micro', 'av_s_car', 'av_s_micro', 'av_transit', 'av_car', 'av_no_trip', 'av_unknown', \n", + " 'av_ridehail', 'av_walk'\n", + " ] + [c for c in df.columns if 'age' in c],\n", + "}\n", + "\n", + "\n", + "cluster_labels = cl2.labels_\n", + "demographics = df.groupby('user_id').first()[demographic_cols[CURRENT_DB]]\n", + "demographics = demographics.loc[target_df.index, :]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a3c6355", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "### DEMOGRAPHICS\n", + "\n", + "def entropy(x):\n", + " # Compute bincount, normalize over the entire size. Gives us probabilities.\n", + " p = np.unique(x, return_counts=True)[1]/len(x)\n", + " # Compute the enropy usnig the probabilities.\n", + " return -np.sum(p * np.log2(p))\n", + "\n", + "def preprocess_demo_data(df: pd.DataFrame):\n", + " return df\n", + "\n", + "\n", + "within_cluster_homogeneity = dict()\n", + "other_cluster_homogeneity = dict()\n", + "labels = cl2.labels_\n", + "\n", + "for cix in np.unique(labels):\n", + " within_cluster_homogeneity[cix] = dict()\n", + " users = target_df[labels == cix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " processed = preprocess_demo_data(data)\n", + " \n", + " for col in processed.columns:\n", + " # Numeric/ordinal values. Use std. to measure homogeneity.\n", + " if col in [\n", + " 'n_residence_members', 'n_residents_u18', 'n_working_residents', 'n_motor_vehicles',\n", + " 'n_residents_with_license', 'income_category'\n", + " ]:\n", + " within_cluster_homogeneity[cix][col] = processed[col].std()\n", + " else:\n", + " within_cluster_homogeneity[cix][col] = entropy(processed[col])\n", + "\n", + "# Compute average homogeneity across other clusters.\n", + "for cix in within_cluster_homogeneity.keys():\n", + " other_cluster_homogeneity[cix] = dict()\n", + " other_clusters = set(within_cluster_homogeneity.keys()) - set([cix])\n", + " for feature in within_cluster_homogeneity[cix].keys():\n", + " homogeneity_in_others = [within_cluster_homogeneity[x][feature] for x in other_clusters]\n", + " other_cluster_homogeneity[cix][feature] = np.mean(homogeneity_in_others)\n", + "\n", + " \n", + "# Compute contrastive homogeneity\n", + "# CH = homogeneity within cluster / average homogeneity across other clusters\n", + "for cix in within_cluster_homogeneity.keys():\n", + " ch_scores = list()\n", + " print(f\"For cluster {cix}:\")\n", + " for feature in within_cluster_homogeneity[cix].keys():\n", + " feature_ch = within_cluster_homogeneity[cix][feature]/(other_cluster_homogeneity[cix][feature] + 1e-6)\n", + " ch_scores.append((feature, feature_ch))\n", + " \n", + " ch_df = pd.DataFrame(ch_scores, columns=['feature', 'ch']).sort_values(by=['ch']).head(4)\n", + " \n", + " # Display actual values.\n", + " users = target_df[labels == cix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " processed = preprocess_demo_data(data)\n", + " \n", + " display(ch_df)\n", + " print()\n", + " filtered = processed.loc[:, processed.columns.isin(ch_df.feature)][ch_df.feature]\n", + " filtered_features = ch_df.feature.tolist()\n", + " \n", + " fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(12, 10))\n", + " for i, a in enumerate(ax.flatten()):\n", + " sns.histplot(filtered[filtered_features[i]], ax=a, stat=\"percent\")\n", + " plt.tight_layout()\n", + " plt.savefig(f\"{CURRENT_DB}_{cix}_Demographic_consistency.png\", dpi=300)\n", + " plt.show()\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "580bbd86", + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.stats import iqr\n", + "\n", + "def get_trip_summary_df(users, df):\n", + " '''\n", + " 1. df = a huge dataframe of user-trips. Each row is a trip.\n", + " 2. every trip is divided into sections: [walk, transit, walk]\n", + " 3. Each section has a corresponding distance and duration: [m1, m2, m3], [t1, t2, t3], [d1, d2, d3]\n", + " 4. What we are doing is only considering the mode, distance, and duration of the section with the largest distance\n", + " '''\n", + " \n", + " costs = [c for c in df.columns if 'av_' in c]\n", + " \n", + " mode_coverage = df.groupby(['user_id', 'section_mode_argmax'])[\n", + " ['section_duration_argmax', 'section_distance_argmax', 'mph'] + costs\n", + " ].agg(['mean', 'median']).unstack()\n", + " \n", + " global_stats = df.groupby('user_id')[['duration', 'distance']].agg(\n", + " ['mean', 'median']\n", + " )\n", + "\n", + " mode_coverage.columns = mode_coverage.columns.map('_'.join)\n", + " global_stats.columns = global_stats.columns.map('_'.join)\n", + " \n", + " # return mode_coverage\n", + " return mode_coverage.merge(right=global_stats, left_index=True, right_index=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92ad2485", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "## TRIP SUMMARIES\n", + "\n", + "# Per-cluster users.\n", + "from sklearn.preprocessing import MinMaxScaler, StandardScaler\n", + "from sklearn.ensemble import IsolationForest\n", + "from sklearn.svm import OneClassSVM\n", + "from sklearn.neighbors import LocalOutlierFactor\n", + "from sklearn.feature_selection import SelectKBest, mutual_info_classif\n", + "\n", + "labels = cl2.labels_\n", + "\n", + "def get_data(cix):\n", + " users = target_df.iloc[labels == cix, :].index\n", + " \n", + " # Compute trip summaries.\n", + " X = df.loc[df.user_id.isin(users), [\n", + " 'section_distance_argmax', 'duration', 'distance', 'section_mode_argmax',\n", + " 'section_duration_argmax', 'mph', 'target', 'user_id'\n", + " ] + [c for c in df.columns if 'cost_' in c]].reset_index(drop=True)\n", + " \n", + " # Compute the target distribution and select the argmax.\n", + " target_distribution = X.target.value_counts(ascending=False, normalize=True)\n", + " target_distribution.rename(index=MAP, inplace=True)\n", + " \n", + " # Caution - this summary df has NaNs. Use nanstd() to compute nan-aware std.\n", + " subset = get_trip_summary_df(users, X)\n", + " \n", + " norm_subset = pd.DataFrame(\n", + " MinMaxScaler().fit_transform(subset),\n", + " columns=subset.columns, index=subset.index\n", + " )\n", + " \n", + " return norm_subset, target_distribution\n", + "\n", + "\n", + "in_cluster_homogeneity = dict()\n", + "out_cluster_homogeneity = dict()\n", + "\n", + "for cluster_ix in np.unique(labels):\n", + " in_cluster_homogeneity[cluster_ix] = dict()\n", + " norm_subset, _ = get_data(cluster_ix)\n", + " for feature in norm_subset.columns:\n", + " in_cluster_homogeneity[cluster_ix][feature] = np.nanstd(norm_subset[feature])\n", + "\n", + "for cix in in_cluster_homogeneity.keys():\n", + " out_cluster_homogeneity[cix] = dict()\n", + " oix = set(labels) - set([cix])\n", + " for feature in norm_subset.columns:\n", + " out_cluster_homogeneity[cix][feature] = np.nanmean([in_cluster_homogeneity[x].get(feature, np.nan) for x in oix])\n", + "\n", + "# Now, compute the per-cluster homogeneity.\n", + "for cix in in_cluster_homogeneity.keys():\n", + " ch = list()\n", + " for feature in in_cluster_homogeneity[cix].keys():\n", + " if feature in in_cluster_homogeneity[cix] and feature in out_cluster_homogeneity[cix]:\n", + " ratio = in_cluster_homogeneity[cix][feature] / (out_cluster_homogeneity[cix][feature] + 1e-6)\n", + " ch.append([feature, ratio])\n", + " \n", + " ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).head(4)\n", + " data, target_dist = get_data(cix)\n", + " \n", + " features = ch_df.feature.tolist()\n", + " \n", + " print(f\"For cluster {cix}:\")\n", + " display(target_dist)\n", + " display(ch_df)\n", + " \n", + " fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(12, 10))\n", + " for i, a in enumerate(ax.flatten()):\n", + " sns.histplot(data[features[i]], ax=a, stat=\"percent\")\n", + " plt.tight_layout()\n", + " plt.savefig(f\"{CURRENT_DB}_{cix}_Trip_consistency.png\", dpi=300)\n", + " plt.show()\n", + " print()\n", + " \n", + " print(50*'=')" + ] + }, + { + "cell_type": "markdown", + "id": "4992ff45", + "metadata": {}, + "source": [ + "## Now check the combined homogeneity score" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8723e3d", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "ic, oc = dict(), dict()\n", + "\n", + "labels = cl2.labels_\n", + "TOP_K = 3\n", + "\n", + "\n", + "for cix in np.unique(labels):\n", + " ic[cix] = dict()\n", + " \n", + " # Trip characteristics.\n", + " norm_subset, _ = get_data(cix)\n", + " for feature in norm_subset.columns:\n", + " ic[cix][feature] = np.nanstd(norm_subset[feature])\n", + " \n", + " # Demographics.\n", + " users = target_df[labels == cix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " processed = preprocess_demo_data(data)\n", + " \n", + " for col in processed.columns:\n", + " # Numeric/ordinal values. Use std. to measure homogeneity.\n", + " if col in [\n", + " 'n_residence_members', 'n_residents_u18', 'n_working_residents', 'n_motor_vehicles',\n", + " 'n_residents_with_license', 'income_category'\n", + " ]:\n", + " ic[cix][col] = np.nanstd(processed[col])\n", + " else:\n", + " ic[cix][col] = entropy(processed[col])\n", + "\n", + "for cix in ic.keys():\n", + " oc[cix] = dict()\n", + " oix = set(labels) - set([cix])\n", + " for feature in ic[cix].keys():\n", + " oc[cix][feature] = np.nanmean([ic[x].get(feature, np.nan) for x in oix])\n", + "\n", + "per_cluster_most_homogeneous = dict()\n", + "\n", + "# Now, compute the per-cluster homogeneity.\n", + "ax_ix = 0\n", + "for cix in ic.keys():\n", + "\n", + " print(f\"For cluster {cix}:\")\n", + "\n", + " # For each, cluster, we will have (TOP_K x n_clusters) figures.\n", + " fig, ax = plt.subplots(nrows=TOP_K, ncols=len(ic.keys()), figsize=(12, 8))\n", + "\n", + " other_ix = set(ic.keys()) - set([cix])\n", + " \n", + " ch = list()\n", + " for feature in ic[cix].keys():\n", + " if feature in oc[cix]:\n", + " ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", + " ch.append([feature, ratio])\n", + " \n", + " # Just the top k.\n", + " ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).reset_index(drop=True).head(TOP_K)\n", + "\n", + " figure_data = dict()\n", + " \n", + " # Get the actual trip summary data.\n", + " trip_summary_data, target_dist = get_data(cix)\n", + " \n", + " # Get the actual demographic data.\n", + " users = target_df[labels == cix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " processed = preprocess_demo_data(data)\n", + "\n", + " # Left-most subplot will be that of the current cluster's feature.\n", + " for row_ix, row in ch_df.iterrows():\n", + " if row.feature in trip_summary_data.columns:\n", + " sns.histplot(trip_summary_data[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", + " else:\n", + " sns.histplot(processed[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", + " ax[row_ix][0].set_xlabel(ax[row_ix][0].get_xlabel(), fontsize=8)\n", + " ax[row_ix][0].set_ylim(0., 100.)\n", + "\n", + " offset_col_ix = 1\n", + " ## Now, others.\n", + " for oix in other_ix:\n", + " # Get the actual trip summary data.\n", + " other_summary_data, _ = get_data(oix)\n", + " \n", + " # Get the actual demographic data.\n", + " users = target_df[labels == oix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " other_demo = preprocess_demo_data(data)\n", + "\n", + " for row_ix, row in ch_df.iterrows():\n", + " if row.feature in other_summary_data.columns:\n", + " sns.histplot(other_summary_data[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", + " else:\n", + " sns.histplot(other_demo[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", + " ax[row_ix][offset_col_ix].set_xlabel(ax[row_ix][offset_col_ix].get_xlabel(), fontsize=8)\n", + " ax[row_ix][offset_col_ix].set_ylim(0., 100.)\n", + " \n", + " offset_col_ix += 1\n", + " \n", + " plt.tight_layout()\n", + " plt.savefig(f\"./outputs/{CURRENT_DB}_cluster{cix}_combined_features.png\", dpi=300)\n", + " plt.show()\n", + " print(50 * '=')" + ] + }, + { + "cell_type": "markdown", + "id": "24a80f68", + "metadata": {}, + "source": [ + "## Try a different clustering technique? (Unexplored)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0288db8", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.cluster import AffinityPropagation\n", + "\n", + "best_score = -np.inf\n", + "best_params = None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b14ad0c", + "metadata": {}, + "outputs": [], + "source": [ + "cls = AffinityPropagation(random_state=13210).fit(target_df)\n", + "labels = cls.labels_\n", + "\n", + "print(labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2562bbb6-66eb-4283-8c08-6e20a0b2ade5", + "metadata": {}, + "outputs": [], + "source": [ + "center_embeddings = cls.cluster_centers_\n", + "centers_proj = PCA(n_components=2).fit_transform(center_embeddings)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7aad38a", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "sns.scatterplot(x=tsfm[:,0], y=tsfm[:,1], c=cls.labels_, ax=ax)\n", + "ax.scatter(x=centers_proj[:,0], y=centers_proj[:,1], marker='X', c='red', alpha=0.5)\n", + "ax.set(xlabel='Latent Dim 0', ylabel='Latent Dim 1')\n", + "# plt.legend([str(x) for x in ap_labels], loc='best')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39ce0238-b3f2-4f46-a52f-13e3160cc52f", + "metadata": {}, + "outputs": [], + "source": [ + "def get_data2(cix, labels):\n", + " users = target_df.iloc[labels == cix, :].index\n", + " \n", + " # Compute trip summaries.\n", + " X = df.loc[df.user_id.isin(users), [\n", + " 'section_distance_argmax', 'section_duration_argmax',\n", + " 'section_mode_argmax', 'distance',\n", + " 'duration', 'mph', 'user_id', 'target'\n", + " ]]\n", + " \n", + " # Compute the target distribution and select the argmax.\n", + " target_distribution = X.target.value_counts(ascending=False, normalize=True)\n", + " target_distribution.rename(index=MAP, inplace=True)\n", + " \n", + " # Caution - this summary df has NaNs. Use nanstd() to compute nan-aware std.\n", + " subset = get_trip_summary_df(users, X)\n", + " \n", + " norm_subset = pd.DataFrame(\n", + " MinMaxScaler().fit_transform(subset),\n", + " columns=subset.columns, index=subset.index\n", + " )\n", + " \n", + " return norm_subset, target_distribution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec27cf29", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "## Analaysis for this data.\n", + "\n", + "ic, oc = dict(), dict()\n", + "labels = cls.labels_\n", + "\n", + "for cix in np.unique(labels):\n", + " users = target_df[labels == cix].index\n", + " \n", + " ic[cix] = dict()\n", + " \n", + " # Trip characteristics.\n", + " norm_subset, _ = get_data2(cix, labels)\n", + " for feature in norm_subset.columns:\n", + " ic[cix][feature] = np.nanstd(norm_subset[feature])\n", + " \n", + " # Demographics.\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " processed = preprocess_demo_data(data)\n", + " \n", + " for col in processed.columns:\n", + " # Numeric/ordinal values. Use std. to measure homogeneity.\n", + " if col == 'age' or col == 'income_category' or col == 'n_working_residents':\n", + " ic[cix][col] = np.nanstd(processed[col])\n", + " else:\n", + " ic[cix][col] = entropy(processed[col])\n", + "\n", + "for cix in ic.keys():\n", + " oc[cix] = dict()\n", + " oix = set(labels) - set([cix])\n", + " for feature in ic[cix].keys():\n", + " oc[cix][feature] = np.nanmean([ic[x].get(feature, np.nan) for x in oix])\n", + "\n", + "# # Now, compute the per-cluster homogeneity.\n", + "# for cix in ic.keys():\n", + " \n", + "# users = users = target_df[labels == cix].index\n", + "# norm_subset, target_dist = get_data(cix, labels)\n", + "# data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + "# processed = preprocess_demo_data(data)\n", + " \n", + "# concat = processed.merge(norm_subset, left_index=True, right_index=True)\n", + " \n", + "# ch = list()\n", + "# for feature in ic[cix].keys():\n", + "# ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", + "# ch.append([feature, ratio])\n", + " \n", + "# ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).head(TOP_K).reset_index(drop=True)\n", + "\n", + "\n", + "# Now, compute the per-cluster homogeneity.\n", + "ax_ix = 0\n", + "for cix in ic.keys():\n", + "\n", + " print(f\"For cluster {cix}:\")\n", + "\n", + " # For each, cluster, we will have (TOP_K x n_clusters) figures.\n", + " fig, ax = plt.subplots(nrows=5, ncols=len(ic.keys()), figsize=(12, 8))\n", + "\n", + " other_ix = set(ic.keys()) - set([cix])\n", + " \n", + " ch = list()\n", + " for feature in ic[cix].keys():\n", + " ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", + " ch.append([feature, ratio])\n", + " \n", + " # Just the top k.\n", + " ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).reset_index(drop=True).head(5)\n", + " figure_data = dict()\n", + " \n", + " # Get the actual trip summary data.\n", + " trip_summary_data, target_dist = get_data(cix)\n", + "\n", + " display(target_dist)\n", + " \n", + " # Get the actual demographic data.\n", + " users = target_df[labels == cix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " processed = preprocess_demo_data(data)\n", + "\n", + " # Left-most subplot will be that of the current cluster's feature.\n", + " for row_ix, row in ch_df.iterrows():\n", + " if row.feature in trip_summary_data.columns:\n", + " sns.histplot(trip_summary_data[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", + " else:\n", + " sns.histplot(processed[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", + " ax[row_ix][0].set_xlabel(ax[row_ix][0].get_xlabel(), fontsize=6)\n", + " ax[row_ix][0].set_ylim(0., 100.)\n", + "\n", + " offset_col_ix = 1\n", + " ## Now, others.\n", + " for oix in other_ix:\n", + " # Get the actual trip summary data.\n", + " other_summary_data, _ = get_data(oix)\n", + " \n", + " # Get the actual demographic data.\n", + " users = target_df[labels == oix].index\n", + " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + " other_demo = preprocess_demo_data(data)\n", + "\n", + " for row_ix, row in ch_df.iterrows():\n", + " if row.feature in other_summary_data.columns:\n", + " sns.histplot(other_summary_data[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", + " else:\n", + " sns.histplot(other_demo[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", + " ax[row_ix][offset_col_ix].set_xlabel(ax[row_ix][offset_col_ix].get_xlabel(), fontsize=6)\n", + " ax[row_ix][offset_col_ix].set_ylim(0., 100.)\n", + " \n", + " offset_col_ix += 1\n", + "\n", + " plt.tight_layout()\n", + " plt.show()\n", + " print(50 * '=')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0b642db", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/replacement_mode_modeling/README.md b/replacement_mode_modeling/README.md new file mode 100644 index 00000000..999722d2 --- /dev/null +++ b/replacement_mode_modeling/README.md @@ -0,0 +1,31 @@ +# Efforts towards predicting the replaced mode without user labels + +## Prerequisites: +- These experiments were conducted on top of the `emission` anaconda environment. Please ensure that this environment is available to you before re-running the code. +- In addition, the script uses `seaborn` for plotting and `pandarallel` for parallel pandas processing. +- Ensure you have the following data sources loaded in your MongoDB Docker container: + - Stage_database (All CEO) + - Durham + - Masscec + - Ride2own + - UPRM NICR +- Once these data sources are procured and loaded in your Mongo container, you will need to add the inferred sections to the data. To do this, please run the [add_sections_and_summaries_to_trips.py](https://github.com/e-mission/e-mission-server/blob/master/bin/historical/migrations/add_sections_and_summaries_to_trips.py) script. **NOTE**: If you see a lot of errors in the log, try to re-run the script by modifying the following line from: + +```language=python +# Before +eps.dispatch(split_lists, skip_if_no_new_data=False, target_fn=add_sections_to_trips) + +# After +eps.dispatch(split_lists, skip_if_no_new_data=False, target_fn=None) +``` + +This will trigger the intake pipeline for the current db and add the inferred section. + +- Note 2: The script above did not work for the All CEO data for me. Therefore, I obtained the section durations using the `get_section_durations` method I've written in `scaffolding.py` (you do not have to call this method, it is already handled in the notebooks). Please note that running this script takes a long time and it is advised to cache the generated output. + +## Running the experiments +The order in which the experiments are to be run are denoted by the preceding number. The following is a brief summary about each notebook: +1. `01_extract_db_data.ipynb`: This notebook extracts the data, performs the necessary preprocessing, updates availability indicators, computes cost estimates, and stores the preprocessed data in `data/filtered_trips`. +2. `02_run_trip_level_models.py`: This script reads all the preprocessed data, fits trip-level models with different stratitifications, generates the outputs, and stores them in `outputs/benchmark_results/`. +3. `03_user_level_models.ipynb`: This notebook explores user fingerprints, similarity searching, and naive user-level models. +4. `04_FeatureClustering.ipynb`: This notebook performs two functions: (a) Cluster users based on demographics/trip feature summaries and check for target distributions across clusters, and (b) Cluster users by grouping w.r.t. the target and checking for feature homogeneity within clusters diff --git a/replacement_mode_modeling/data/README.md b/replacement_mode_modeling/data/README.md new file mode 100644 index 00000000..6d2c55c4 --- /dev/null +++ b/replacement_mode_modeling/data/README.md @@ -0,0 +1 @@ +Temporary folder \ No newline at end of file diff --git a/replacement_mode_modeling/outputs/README.md b/replacement_mode_modeling/outputs/README.md new file mode 100644 index 00000000..6d2c55c4 --- /dev/null +++ b/replacement_mode_modeling/outputs/README.md @@ -0,0 +1 @@ +Temporary folder \ No newline at end of file From a1a4ef7b30cb6e0459830686e5271199e6ff4c60 Mon Sep 17 00:00:00 2001 From: Rahul Kulhalli Date: Mon, 29 Apr 2024 14:46:04 -0400 Subject: [PATCH 2/6] Updated README with specific package versions --- replacement_mode_modeling/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/replacement_mode_modeling/README.md b/replacement_mode_modeling/README.md index 999722d2..d6f3ee73 100644 --- a/replacement_mode_modeling/README.md +++ b/replacement_mode_modeling/README.md @@ -1,8 +1,16 @@ + # Efforts towards predicting the replaced mode without user labels ## Prerequisites: - These experiments were conducted on top of the `emission` anaconda environment. Please ensure that this environment is available to you before re-running the code. -- In addition, the script uses `seaborn` for plotting and `pandarallel` for parallel pandas processing. +- In addition, some notebooks use `seaborn` for plotting and `pandarallel` for parallel pandas processing. The packages can be installed in the following manner: + +``` +(After activating emission conda env) +pip3 install pandarallel==1.6.5 +pip3 install seaborn==0.12.2 +``` + - Ensure you have the following data sources loaded in your MongoDB Docker container: - Stage_database (All CEO) - Durham From 31eb26136b919a95c67a14a506645800d1e8ef3a Mon Sep 17 00:00:00 2001 From: Rahul Kulhalli Date: Mon, 29 Apr 2024 14:59:56 -0400 Subject: [PATCH 3/6] Removed scaffolding dependency; updated README --- .../01_extract_db_data.ipynb | 122 ++++++++++++------ replacement_mode_modeling/README.md | 5 +- 2 files changed, 84 insertions(+), 43 deletions(-) diff --git a/replacement_mode_modeling/01_extract_db_data.ipynb b/replacement_mode_modeling/01_extract_db_data.ipynb index 216b88bd..1706837b 100644 --- a/replacement_mode_modeling/01_extract_db_data.ipynb +++ b/replacement_mode_modeling/01_extract_db_data.ipynb @@ -206,10 +206,6 @@ " }\n", "}\n", "\n", - "SENSED_SECTION_DICT = {\n", - " \"openpath_prod_mm_masscec\": {'AIR_OR_HSR', 'BICYCLING', 'BUS', 'CAR', 'LIGHT_RAIL', 'SUBWAY', 'TRAIN', 'UNKNOWN', 'WALKING'}\n", - "}\n", - "\n", "SURVEY_DATA_DICT = {\n", " \"Stage_database\": {\n", " \"Unique User ID (auto-filled, do not edit)\": \"user_id\",\n", @@ -477,28 +473,26 @@ "metadata": {}, "outputs": [], "source": [ - "if CURRENT_DB != \"Stage_database\":\n", - "\n", - " ## Source: scaffolding.py\n", + "## Source: scaffolding.py\n", "\n", - " uuid_df = pd.json_normalize(list(edb.get_uuid_db().find()))\n", + "uuid_df = pd.json_normalize(list(edb.get_uuid_db().find()))\n", "\n", - " if not INCLUDE_TEST_USERS:\n", - " uuid_df = uuid_df.loc[~uuid_df.user_email.str.contains('_test_'), :]\n", + "if not INCLUDE_TEST_USERS:\n", + " uuid_df = uuid_df.loc[~uuid_df.user_email.str.contains('_test_'), :]\n", "\n", - " filtered = uuid_df.uuid.unique()\n", + "filtered = uuid_df.uuid.unique()\n", "\n", - " agg = esta.TimeSeries.get_aggregate_time_series()\n", - " all_ct = agg.get_data_df(\"analysis/confirmed_trip\", None)\n", + "agg = esta.TimeSeries.get_aggregate_time_series()\n", + "all_ct = agg.get_data_df(\"analysis/confirmed_trip\", None)\n", "\n", - " print(f\"Before filtering, length={len(all_ct)}\")\n", - " participant_ct_df = all_ct.loc[all_ct.user_id.isin(filtered), :]\n", - " print(f\"After filtering, length={len(participant_ct_df)}\")\n", + "print(f\"Before filtering, length={len(all_ct)}\")\n", + "participant_ct_df = all_ct.loc[all_ct.user_id.isin(filtered), :]\n", + "print(f\"After filtering, length={len(participant_ct_df)}\")\n", "\n", - " expanded_ct = expand_userinputs(participant_ct_df)\n", - " expanded_ct = data_quality_check(expanded_ct)\n", - " print(expanded_ct.columns.tolist())\n", - " expanded_ct['replaced_mode'] = expanded_ct['replaced_mode'].fillna('Unknown')" + "expanded_ct = expand_userinputs(participant_ct_df)\n", + "expanded_ct = data_quality_check(expanded_ct)\n", + "print(expanded_ct.columns.tolist())\n", + "expanded_ct['replaced_mode'] = expanded_ct['replaced_mode'].fillna('Unknown')" ] }, { @@ -510,27 +504,25 @@ "source": [ "# # Additional preprocessing for replaced mode (if any)\n", "\n", - "if CURRENT_DB != \"Stage_database\":\n", + "mode_counts = expanded_ct['replaced_mode'].value_counts()\n", + "drop_modes = mode_counts[mode_counts == 1].index.tolist()\n", "\n", - " mode_counts = expanded_ct['replaced_mode'].value_counts()\n", - " drop_modes = mode_counts[mode_counts == 1].index.tolist()\n", + "expanded_ct.drop(\n", + " index=expanded_ct.loc[expanded_ct.replaced_mode.isin(drop_modes)].index,\n", + " inplace=True\n", + ")\n", "\n", - " expanded_ct.drop(\n", - " index=expanded_ct.loc[expanded_ct.replaced_mode.isin(drop_modes)].index,\n", - " inplace=True\n", - " )\n", + "# Additional modes to drop.\n", + "expanded_ct.drop(\n", + " index=expanded_ct.loc[expanded_ct.replaced_mode.isin(\n", + " # Remove all rows with air, boat, or weird answers.\n", + " ['houseboat', 'gondola', 'airline_flight', 'aircraft', 'zoo', 'air',\n", + " 'airplane', 'boat', 'flight', 'plane', 'meal', 'lunch']\n", + " )].index,\n", + " inplace=True\n", + ")\n", "\n", - " # Additional modes to drop.\n", - " expanded_ct.drop(\n", - " index=expanded_ct.loc[expanded_ct.replaced_mode.isin(\n", - " # Remove all rows with air, boat, or weird answers.\n", - " ['houseboat', 'gondola', 'airline_flight', 'aircraft', 'zoo', 'air',\n", - " 'airplane', 'boat', 'flight', 'plane', 'meal', 'lunch']\n", - " )].index,\n", - " inplace=True\n", - " )\n", - " \n", - " expanded_ct.replaced_mode = expanded_ct.replaced_mode.apply(lambda x: REPLACED_MODE_DICT[CURRENT_DB][x])" + "expanded_ct.replaced_mode = expanded_ct.replaced_mode.apply(lambda x: REPLACED_MODE_DICT[CURRENT_DB][x])" ] }, { @@ -590,10 +582,58 @@ " survey_data = pd.concat([survey_data, v], axis=0, ignore_index=True)\n", "else:\n", " # Read the demographics.\n", - " survey_data = pd.read_csv('./viz_scripts/Can Do Colorado eBike Program - en.csv')\n", + " # Ensure that you have access to this survey file and that it is placed in the given destination.\n", + " survey_data = pd.read_csv('../viz_scripts/Can Do Colorado eBike Program - en.csv')\n", " survey_data.rename(columns={'Unique User ID (auto-filled, do not edit)': 'user_id'}, inplace=True)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "1aaedf66", + "metadata": {}, + "outputs": [], + "source": [ + "def get_section_durations(confirmed_trips: pd.DataFrame):\n", + " \n", + " import pandarallel\n", + "\n", + " # Initialize the parallel processing.\n", + " pandarallel.initialize(progress_bar=False)\n", + "\n", + " \"\"\"\n", + " Extract section-wise durations from trips for every trips.\n", + " \"\"\"\n", + "\n", + " # the inner function has access to these variables.\n", + " primary_key = 'analysis/inferred_section'\n", + " fallback_key = 'analysis/cleaned_section'\n", + "\n", + " def get_durations(user_id, trip_id):\n", + "\n", + " inferred_sections = esdt.get_sections_for_trip(key = primary_key,\n", + " user_id = user_id, trip_id = trip_id)\n", + "\n", + " if inferred_sections and len(inferred_sections) > 0:\n", + " return [x.data.duration for x in inferred_sections]\n", + " \n", + " print(\"Falling back to confirmed trips...\")\n", + "\n", + " cleaned_sections = esdt.get_sections_for_trip(key = fallback_key,\n", + " user_id = user_id, trip_id = trip_id)\n", + " \n", + " if cleaned_sections and len(cleaned_sections) > 0:\n", + " return [x.data.duration for x in cleaned_sections]\n", + "\n", + " return []\n", + "\n", + " confirmed_trips['section_durations'] = confirmed_trips.parallel_apply(\n", + " lambda x: get_durations(x.user_id, x.cleaned_trip), axis=1\n", + " )\n", + "\n", + " return confirmed_trips" + ] + }, { "cell_type": "code", "execution_count": null, @@ -611,9 +651,7 @@ " else:\n", " ## NOTE: Run this cell only if the cached CSV is not already available. It will take a LOT of time.\n", " ## Benchmark timing: ~12 hours on a MacBook Pro (2017 model) with pandarallel, 4 workers.\n", - " \n", - " importlib.reload(scaffolding)\n", - " expanded_ct = scaffolding.get_section_durations(expanded_ct)\n", + " expanded_ct = get_section_durations(expanded_ct)\n", " expanded_ct.to_csv('./data/cached_allceo_data.csv', index=False)" ] }, diff --git a/replacement_mode_modeling/README.md b/replacement_mode_modeling/README.md index d6f3ee73..628fd439 100644 --- a/replacement_mode_modeling/README.md +++ b/replacement_mode_modeling/README.md @@ -17,6 +17,9 @@ pip3 install seaborn==0.12.2 - Masscec - Ride2own - UPRM NICR + +- Additionally, please also procure the CanBikeCO survey CSV file and place it in the `viz_scripts/` directory. + - Once these data sources are procured and loaded in your Mongo container, you will need to add the inferred sections to the data. To do this, please run the [add_sections_and_summaries_to_trips.py](https://github.com/e-mission/e-mission-server/blob/master/bin/historical/migrations/add_sections_and_summaries_to_trips.py) script. **NOTE**: If you see a lot of errors in the log, try to re-run the script by modifying the following line from: ```language=python @@ -29,7 +32,7 @@ eps.dispatch(split_lists, skip_if_no_new_data=False, target_fn=None) This will trigger the intake pipeline for the current db and add the inferred section. -- Note 2: The script above did not work for the All CEO data for me. Therefore, I obtained the section durations using the `get_section_durations` method I've written in `scaffolding.py` (you do not have to call this method, it is already handled in the notebooks). Please note that running this script takes a long time and it is advised to cache the generated output. +- Note 2: The script above did not work for the All CEO data for me. Therefore, I obtained the section durations using the `get_section_durations` method I've written in the first notebook. Please note that running this script takes a long time and it is advised to cache the generated output. ## Running the experiments The order in which the experiments are to be run are denoted by the preceding number. The following is a brief summary about each notebook: From 1644db0343a0f56fddb13fed9b52331e98e7977b Mon Sep 17 00:00:00 2001 From: Rahul Kulhalli Date: Tue, 30 Apr 2024 18:33:23 -0400 Subject: [PATCH 4/6] Updated bugs in notebooks --- .../01_extract_db_data.ipynb | 68 +- .../03_user_level_models.ipynb | 497 ++++-- .../04_FeatureClustering.ipynb | 1505 ++++++++++++++--- 3 files changed, 1597 insertions(+), 473 deletions(-) diff --git a/replacement_mode_modeling/01_extract_db_data.ipynb b/replacement_mode_modeling/01_extract_db_data.ipynb index 1706837b..bef2545e 100644 --- a/replacement_mode_modeling/01_extract_db_data.ipynb +++ b/replacement_mode_modeling/01_extract_db_data.ipynb @@ -43,11 +43,12 @@ "metadata": {}, "outputs": [], "source": [ - "# Add path to your emission server here.\n", - "emission_path = Path(os.getcwd()).parent.parent / 'my_emission_server' / 'e-mission-server'\n", - "sys.path.append(str(emission_path))\n", + "# Add path to your emission server here. Uncommented because the notebooks are run in the server.\n", + "# If running locally, you need to point this to the e-mission server repo.\n", + "# emission_path = Path(os.getcwd()).parent.parent.parent / 'my_emission_server' / 'e-mission-server'\n", + "# sys.path.append(str(emission_path))\n", "\n", - "# Also add the home (viz_scripts) to the path\n", + "# # Also add the home (viz_scripts) to the path\n", "sys.path.append('../viz_scripts')" ] }, @@ -58,7 +59,6 @@ "metadata": {}, "outputs": [], "source": [ - "import scaffolding\n", "import emission.core.get_database as edb\n", "import emission.storage.timeseries.abstract_timeseries as esta" ] @@ -75,7 +75,6 @@ " \"openpath_prod_durham\", # Has composite trips\n", " \"openpath_prod_mm_masscec\", # Has composite trips\n", " \"openpath_prod_ride2own\", # Has composite trips\n", - "# \"openpath_prod_uprm_civic\", # No replaced mode (Excluded)\n", " \"openpath_prod_uprm_nicr\" # Has composite trips\n", "]" ] @@ -590,7 +589,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1aaedf66", + "id": "07922a00", "metadata": {}, "outputs": [], "source": [ @@ -683,16 +682,6 @@ "### Demographic data preprocessing" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "336508c2", - "metadata": {}, - "outputs": [], - "source": [ - "print(survey_data.columns.tolist())" - ] - }, { "cell_type": "code", "execution_count": null, @@ -714,9 +703,11 @@ "survey_data.loc[\n", " survey_data.n_motor_vehicles.isin(\n", " ['prefer_not_to_say', 'Prefer not to say / Prefiero no decir.']\n", - " ), 'n_motor_vehicles'\n", - "] = 0\n", - "survey_data.loc[survey_data.n_motor_vehicles.isin(['more_than_3', '4+', 'more_than_4']), 'n_motor_vehicles'] = 4\n", + " ), 'n_motor_vehicles'] = 0\n", + "\n", + "survey_data.loc[survey_data.n_motor_vehicles.isin(\n", + " ['more_than_3', '4+', 'more_than_4', 'more_than_3']\n", + "), 'n_motor_vehicles'] = 4\n", "survey_data.n_motor_vehicles = survey_data.n_motor_vehicles.astype(int)\n", "\n", "# gtg\n", @@ -724,22 +715,20 @@ " lambda x: 1 if str(x).lower() == 'yes' else 0\n", ")\n", "\n", - "survey_data.loc[survey_data.n_residents_u18 == 'prefer_not_to_say'] = 0\n", + "survey_data.loc[survey_data.n_residents_u18 == 'prefer_not_to_say', 'n_residents_u18'] = 0\n", "survey_data.n_residents_u18 = survey_data.n_residents_u18.astype(int)\n", "\n", - "survey_data.loc[survey_data.n_residence_members == 'prefer_not_to_say'] = 0\n", + "survey_data.loc[survey_data.n_residence_members == 'prefer_not_to_say', 'n_residence_members'] = 0\n", "survey_data.n_residence_members = survey_data.n_residence_members.astype(int)\n", "\n", "survey_data.loc[survey_data.n_residents_with_license == 'prefer_not_to_say'] = 0\n", - "survey_data.loc[survey_data.n_residents_with_license == 'more_than_4'] = 4\n", + "survey_data.loc[survey_data.n_residents_with_license == 'more_than_4', 'n_residents_with_license'] = 4\n", "survey_data.n_residents_with_license = survey_data.n_residents_with_license.astype(int)\n", "\n", - "# In allCEO, we see 50 & 9999. What??\n", + "# Handle abnormal inputs.\n", "survey_data = survey_data[\n", - " (survey_data.n_residence_members < 10) & (survey_data.n_residents_u18 < 10) & \n", - " (survey_data.n_residents_with_license < 10) & \n", - " (survey_data.n_residence_members - survey_data.n_residents_with_license > 0) &\n", - " (survey_data.n_residence_members - survey_data.n_residents_u18 > 0)\n", + " (survey_data.n_residence_members - survey_data.n_residents_with_license >= 0) &\n", + " (survey_data.n_residence_members - survey_data.n_residents_u18 >= 0)\n", "].reset_index(drop=True)\n", "\n", "# gtg\n", @@ -837,7 +826,7 @@ " \"professional__managerial__or_technical\": \"Professional, Manegerial, or Technical\",\n", " \"manufacturing__construction__maintenance\": \"Manufacturing, construction, maintenance, or farming\",\n", " \"clerical_or_administrative_support\": \"Clerical or administrative support\",\n", - " \"prefer_not_to_say\": \"Prefer not to say\",\n", + " \"prefer_not_to_say\": \"Prefer not to say\"\n", " }\n", " \n", " df.primary_job_description = df.primary_job_description.apply(\n", @@ -1616,7 +1605,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(f\"Done processing for {CURRENT_DB=}\")" + "print(f\"Done processing for {CURRENT_DB=}, Number of unique users: {len(filtered_trips.user_id.unique())}\")" ] }, { @@ -1633,16 +1622,6 @@ "filtered_trips.replace({'target': {t: ix+1 for ix, t in enumerate(targets)}}, inplace=True)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "50d3eaec", - "metadata": {}, - "outputs": [], - "source": [ - "display(filtered_trips.target.unique())" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1650,6 +1629,7 @@ "metadata": {}, "outputs": [], "source": [ + "# savepath = Path('./data/filtered_data')\n", "savepath = Path('./data/filtered_data')\n", "\n", "if not savepath.exists():\n", @@ -1657,6 +1637,14 @@ "\n", "filtered_trips.to_csv(savepath / f'preprocessed_data_{CURRENT_DB}.csv', index=False)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f16fb354", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/replacement_mode_modeling/03_user_level_models.ipynb b/replacement_mode_modeling/03_user_level_models.ipynb index da064680..616cd5e6 100644 --- a/replacement_mode_modeling/03_user_level_models.ipynb +++ b/replacement_mode_modeling/03_user_level_models.ipynb @@ -83,29 +83,61 @@ "metadata": {}, "outputs": [], "source": [ - "df = pd.read_csv('./data/filtered_data/preprocessed_data_Stage_database.csv')\n", - "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_durham.csv')\n", - "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_mm_masscec.csv')\n", - "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_ride2own.csv')\n", - "# df = pd.read_csv('./data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv')" + "DATA_SOURCE = [\n", + " ('./data/filtered_data/preprocessed_data_Stage_database.csv', 'allceo'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_durham.csv', 'durham'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_mm_masscec.csv', 'masscec'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_ride2own.csv', 'ride2own'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv', 'nicr')\n", + "]" ] }, { "cell_type": "code", "execution_count": null, - "id": "915e9d6f", + "id": "e3d9c5bd", "metadata": {}, "outputs": [], "source": [ - "df.groupby('user_id')['target'].apply(lambda x: x.value_counts().idxmax()).unique()" + "## CHANGE THE DB INDEX HERE.\n", + "DB_NUMBER = 0\n", + "\n", + "PATH = DATA_SOURCE[DB_NUMBER][0]\n", + "CURRENT_DB = DATA_SOURCE[DB_NUMBER][1]" ] }, { "cell_type": "code", "execution_count": null, - "id": "72793473", + "id": "e37f8922", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(PATH)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bfa6843", "metadata": {}, "outputs": [], + "source": [ + "not_needed = ['deprecatedID', 'data.key']\n", + "\n", + "for col in not_needed:\n", + " if col in df.columns:\n", + " df.drop(columns=[col], inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72793473", + "metadata": { + "scrolled": true + }, + "outputs": [], "source": [ "print(df.columns.tolist())" ] @@ -276,30 +308,124 @@ " trip_features_to_use = trip_kwargs.pop('trip_features', None)\n", " trip_group_key = trip_kwargs.pop('trip_grouping', 'section_mode_argmax')\n", " \n", - " demographics = [ \n", - " 'has_drivers_license', 'is_student', 'is_paid', 'income_category', 'n_residence_members', \n", - " 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles',\n", - " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'n_working_residents', \n", - " \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", - " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", - " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", - " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", - " 'primary_job_description_Education', 'primary_job_description_Food service', \n", - " 'primary_job_description_Linecook', \n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", - " 'primary_job_description_Medical/healthcare', 'primary_job_description_Non-profit program manager', \n", - " 'primary_job_description_Other', 'primary_job_description_Professional, managerial, or technical', \n", - " 'primary_job_description_Sales or service', 'primary_job_description_Self employed', \n", - " 'primary_job_description_food service', 'gender_Man', 'gender_Nonbinary/genderqueer/genderfluid', \n", - " 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", - " 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', 'age_31___35_years_old', \n", - " 'age_36___40_years_old', 'age_41___45_years_old', 'age_46___50_years_old', 'age_51___55_years_old', \n", - " 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old', 'av_transit', 'av_no_trip', \n", - " 'av_p_micro', 'av_s_micro', 'av_ridehail', 'av_unknown', 'av_walk', 'av_car', 'av_s_car', \n", - " ]\n", + " demographics = {\n", + " 'allceo': [\n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category',\n", + " 'n_residence_members', 'n_residents_u18', 'n_residents_with_license',\n", + " 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs', 'n_working_residents',\n", + " \"highest_education_Bachelor's degree\",\n", + " 'highest_education_Graduate degree or professional degree',\n", + " 'highest_education_High school graduate or GED',\n", + " 'highest_education_Less than a high school graduate',\n", + " 'highest_education_Prefer not to say',\n", + " 'highest_education_Some college or associates degree',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Custodial',\n", + " 'primary_job_description_Education',\n", + " 'primary_job_description_Food service',\n", + " 'primary_job_description_Linecook',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Medical/healthcare',\n", + " 'primary_job_description_Non-profit program manager',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, managerial, or technical',\n", + " 'primary_job_description_Sales or service',\n", + " 'primary_job_description_Self employed',\n", + " 'primary_job_description_food service', 'gender_Man',\n", + " 'gender_Nonbinary/genderqueer/genderfluid', 'gender_Prefer not to say',\n", + " 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", + " 'age_16___20_years_old', 'age_21___25_years_old',\n", + " 'age_26___30_years_old', 'age_31___35_years_old',\n", + " 'age_36___40_years_old', 'age_41___45_years_old',\n", + " 'age_46___50_years_old', 'age_51___55_years_old',\n", + " 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old',\n", + " 'av_transit', 'av_no_trip', 'av_p_micro', 'av_s_micro', 'av_ridehail',\n", + " 'av_unknown', 'av_walk', 'av_car', 'av_s_car'\n", + " ],\n", + " 'durham': [\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18',\n", + " 'n_residence_members', 'income_category',\n", + " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles',\n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs',\n", + " 'highest_education_bachelor_s_degree',\n", + " 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_some_college_or_associates_degree',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'primary_job_description_Sales or service', 'gender_man',\n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman',\n", + " 'age_16___20_years_old', 'age_21___25_years_old',\n", + " 'age_26___30_years_old', 'age_31___35_years_old',\n", + " 'age_36___40_years_old', 'age_41___45_years_old',\n", + " 'age_51___55_years_old', 'age_56___60_years_old', 'av_walk',\n", + " 'av_unknown', 'av_no_trip', 'av_p_micro', 'av_transit', 'av_car',\n", + " 'av_ridehail', 'av_s_micro', 'av_s_car'\n", + " ],\n", + " 'nicr': [\n", + " 'is_student', 'is_paid',\n", + " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", + " 'income_category', 'n_residents_with_license',\n", + " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_prefer_not_to_say', 'primary_job_description_Other',\n", + " 'gender_man', 'gender_woman', 'age_16___20_years_old', 'av_p_micro',\n", + " 'av_car', 'av_transit', 'av_ridehail', 'av_no_trip', 'av_s_car',\n", + " 'av_s_micro', 'av_unknown', 'av_walk'\n", + " ],\n", + " 'masscec': [\n", + " 'is_student', 'is_paid',\n", + " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", + " 'income_category', 'n_residents_with_license',\n", + " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree',\n", + " 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_prefer_not_to_say',\n", + " 'highest_education_some_college_or_associates_degree',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Prefer not to say',\n", + " 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'primary_job_description_Sales or service', 'gender_man',\n", + " 'gender_prefer_not_to_say', 'gender_woman', 'age_16___20_years_old',\n", + " 'age_21___25_years_old', 'age_26___30_years_old',\n", + " 'age_31___35_years_old', 'age_36___40_years_old',\n", + " 'age_41___45_years_old', 'age_46___50_years_old',\n", + " 'age_51___55_years_old', 'age_56___60_years_old',\n", + " 'age_61___65_years_old', 'age___65_years_old', 'av_p_micro', 'av_s_car',\n", + " 'av_s_micro', 'av_transit', 'av_car', 'av_no_trip', 'av_unknown',\n", + " 'av_ridehail', 'av_walk'\n", + " ],\n", + " 'ride2own': [\n", + " 'has_drivers_license', 'is_student',\n", + " 'is_paid', 'income_category', 'n_residence_members',\n", + " 'n_working_residents', 'n_residents_u18', 'n_residents_with_license',\n", + " 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs',\n", + " 'highest_education_bachelor_s_degree',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_some_college_or_associates_degree',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'gender_man', 'gender_woman', 'age_31___35_years_old',\n", + " 'age_36___40_years_old', 'age_41___45_years_old',\n", + " 'age_51___55_years_old', 'av_no_trip', 'av_s_micro', 'av_transit',\n", + " 'av_car', 'av_ridehail', 'av_p_micro', 'av_s_car', 'av_walk',\n", + " 'av_unknown'\n", + " ]\n", + " }\n", " \n", " # Retain only the first instance of each user and subset the columns.\n", - " filtered = df.groupby('user_id').first()[demographics]\n", + " filtered = df.groupby('user_id').first()[demographics[CURRENT_DB]]\n", " \n", " # Get the targets.\n", " targets = df.groupby('user_id')['target'].apply(lambda x: x.value_counts().idxmax())\n", @@ -315,10 +441,6 @@ " # Reaching here means that we need to include trip summaries\n", " # -----------------------------------------------------------\n", " \n", - " # If trip summaries are to be used, then re-use the preprocessed availability features.\n", - " availability = df[['user_id'] + [c for c in df.columns if 'av_' in c]]\n", - " availability = availability.groupby('user_id').first()\n", - " \n", " # For every user, generate the global trip-level summaries.\n", " global_aggs = df.groupby('user_id').agg({'duration': 'mean', 'distance': 'mean'})\n", " \n", @@ -339,7 +461,6 @@ " trip_features = trip_features.merge(right=global_aggs, left_index=True, right_index=True)\n", " \n", " # Finally, join with availability indicators and targets.\n", - " trip_features = trip_features.merge(right=availability, left_index=True, right_on='user_id')\n", " trip_features = trip_features.merge(right=targets, left_index=True, right_index=True)\n", " \n", " return trip_features.reset_index(drop=False)" @@ -387,12 +508,12 @@ "outputs": [], "source": [ "tsne_kwargs = {\n", - " 'perplexity': 6,\n", + " 'perplexity': min(len(demo_df)-1, 6),\n", " 'n_iter': 7500,\n", " 'metric': 'cosine'\n", "}\n", "\n", - "## PLOT BY THE WAY IN WHICH PEOPLE USE THE SAME REPLACED MODE AND CHECK THE SIMILARITY.\n", + "# ## PLOT BY THE WAY IN WHICH PEOPLE USE THE SAME REPLACED MODE AND CHECK THE SIMILARITY.\n", "\n", "projections = generate_tsne_plots(demo_df, **tsne_kwargs)" ] @@ -482,9 +603,14 @@ " \n", " elif metric == SimilarityMetric.KNN:\n", " \n", + " n_neighbors = metric_kwargs.pop('n_neighbors', 3)\n", + " \n", + " if n_neighbors >= len(tr):\n", + " return -1.\n", + " \n", " # Build the KNN classifier. By default, let it be 3.\n", " knn = KNeighborsClassifier(\n", - " n_neighbors=metric_kwargs.pop('n_neighbors', 3),\n", + " n_neighbors=n_neighbors,\n", " weights='distance',\n", " metric=metric_kwargs.pop('knn_metric', 'cosine'),\n", " n_jobs=os.cpu_count()\n", @@ -497,9 +623,14 @@ " \n", " elif metric == SimilarityMetric.KMEANS:\n", " \n", + " n_clusters = metric_kwargs.pop('n_clusters', 8)\n", + " \n", + " if n_clusters >= len(tr):\n", + " return -1\n", + " \n", " # Build the model.\n", " kmeans = KMeans(\n", - " n_clusters=metric_kwargs.pop('n_clusters', 8),\n", + " n_clusters=n_clusters,\n", " max_iter=metric_kwargs.pop('max_iter', 300),\n", " n_init='auto',\n", " random_state=SEED\n", @@ -632,6 +763,14 @@ " return best_model" ] }, + { + "cell_type": "markdown", + "id": "45fef6d1", + "metadata": {}, + "source": [ + "### Uncomment to run the model " + ] + }, { "cell_type": "code", "execution_count": null, @@ -639,7 +778,7 @@ "metadata": {}, "outputs": [], "source": [ - "model = estimate_using_model(train, test)" + "# model = estimate_using_model(train, test)" ] }, { @@ -677,7 +816,9 @@ "demo_plus_trips = get_demographic_data(\n", " df, \n", " trip_features=['mph', 'section_duration_argmax', 'section_distance_argmax', 'start_local_dt_hour', 'end_local_dt_hour']\n", - ")" + ")\n", + "\n", + "demo_plus_trips.fillna(0., inplace=True)" ] }, { @@ -732,6 +873,14 @@ "```" ] }, + { + "cell_type": "markdown", + "id": "85483fc4", + "metadata": {}, + "source": [ + "### Uncomment this to run the model" + ] + }, { "cell_type": "code", "execution_count": null, @@ -740,7 +889,7 @@ "outputs": [], "source": [ "# Now, we try with the model\n", - "estimate_using_model(train, test)" + "# estimate_using_model(train, test)" ] }, { @@ -805,7 +954,11 @@ }, "outputs": [], "source": [ - "_ = generate_tsne_plots(demo_plus_trips, perplexity=6, n_iter=7500)" + "_ = generate_tsne_plots(\n", + " demo_plus_trips, \n", + " perplexity=min(len(demo_plus_trips)-1, 6), \n", + " n_iter=7500\n", + ")" ] }, { @@ -813,7 +966,9 @@ "id": "c339fcc6", "metadata": {}, "source": [ - "# Multi-level modeling" + "# (Experimental) Multi-level modeling\n", + "\n", + "## The code below onwards is not tested." ] }, { @@ -836,26 +991,26 @@ "metadata": {}, "outputs": [], "source": [ - "def drop_columns(df: pd.DataFrame):\n", - " to_drop = [\n", - " 'source', 'end_ts', 'end_fmt_time', 'end_loc', 'raw_trip', 'start_ts', \n", - " 'start_fmt_time', 'start_loc', 'duration', 'distance', 'start_place', \n", - " 'end_place', 'cleaned_trip', 'inferred_labels', 'inferred_trip', 'expectation',\n", - " 'confidence_threshold', 'expected_trip', 'user_input', 'start:year', 'start:month', \n", - " 'start:day', 'start_local_dt_minute', 'start_local_dt_second', \n", - " 'start_local_dt_weekday', 'start_local_dt_timezone', 'end:year', 'end:month', 'end:day', \n", - " 'end_local_dt_minute', 'end_local_dt_second', 'end_local_dt_weekday', \n", - " 'end_local_dt_timezone', '_id', 'metadata_write_ts', 'additions', \n", - " 'mode_confirm', 'purpose_confirm', 'Mode_confirm', 'Trip_purpose', \n", - " 'original_user_id', 'program', 'opcode', 'Timestamp', 'birth_year', \n", - " 'available_modes', 'section_coordinates_argmax', 'section_mode_argmax'\n", - " ]\n", - " \n", - " # Drop section_mode_argmax and available_modes.\n", - " return df.drop(\n", - " columns=to_drop, \n", - " inplace=False\n", - " )" + "# def drop_columns(df: pd.DataFrame):\n", + "# to_drop = [\n", + "# 'source', 'end_ts', 'end_fmt_time', 'end_loc', 'raw_trip', 'start_ts', \n", + "# 'start_fmt_time', 'start_loc', 'duration', 'distance', 'start_place', \n", + "# 'end_place', 'cleaned_trip', 'inferred_labels', 'inferred_trip', 'expectation',\n", + "# 'confidence_threshold', 'expected_trip', 'user_input', 'start:year', 'start:month', \n", + "# 'start:day', 'start_local_dt_minute', 'start_local_dt_second', \n", + "# 'start_local_dt_weekday', 'start_local_dt_timezone', 'end:year', 'end:month', 'end:day', \n", + "# 'end_local_dt_minute', 'end_local_dt_second', 'end_local_dt_weekday', \n", + "# 'end_local_dt_timezone', '_id', 'metadata_write_ts', 'additions', \n", + "# 'mode_confirm', 'purpose_confirm', 'Mode_confirm', 'Trip_purpose', \n", + "# 'original_user_id', 'program', 'opcode', 'Timestamp', 'birth_year', \n", + "# 'available_modes', 'section_coordinates_argmax', 'section_mode_argmax'\n", + "# ]\n", + " \n", + "# # Drop section_mode_argmax and available_modes.\n", + "# return df.drop(\n", + "# columns=to_drop, \n", + "# inplace=False\n", + "# )" ] }, { @@ -865,32 +1020,32 @@ "metadata": {}, "outputs": [], "source": [ - "def construct_model_dictionary(train: pd.DataFrame):\n", - " \n", - " def train_on_user(user_id: str):\n", - " '''\n", - " Given the training set and the user ID to query, filter the dataset and\n", - " retain only the relevant trips. Then, create folds and optimize a model for this user.\n", - " Return the trained model instance.\n", - " '''\n", + "# def construct_model_dictionary(train: pd.DataFrame):\n", + " \n", + "# def train_on_user(user_id: str):\n", + "# '''\n", + "# Given the training set and the user ID to query, filter the dataset and\n", + "# retain only the relevant trips. Then, create folds and optimize a model for this user.\n", + "# Return the trained model instance.\n", + "# '''\n", " \n", - " user_data = train.loc[train.user_id == user_id, :].reset_index(drop=True)\n", + "# user_data = train.loc[train.user_id == user_id, :].reset_index(drop=True)\n", " \n", - " # Split user trips into train-test folds.\n", - " u_train, u_test = train_test_split(user_data, test_size=0.2, shuffle=True, random_state=SEED)\n", + "# # Split user trips into train-test folds.\n", + "# u_train, u_test = train_test_split(user_data, test_size=0.2, shuffle=True, random_state=SEED)\n", " \n", - " user_model = estimate_using_model(\n", - " u_train, u_test, \n", - " n_iter=100\n", - " )\n", + "# user_model = estimate_using_model(\n", + "# u_train, u_test, \n", + "# n_iter=100\n", + "# )\n", " \n", - " return user_model\n", + "# return user_model\n", " \n", - " for user in train.user_id.unique():\n", - " MODEL_DICT[user]['warm_start'] = train_on_user(user)\n", - " print(50*'=')\n", + "# for user in train.user_id.unique():\n", + "# MODEL_DICT[user]['warm_start'] = train_on_user(user)\n", + "# print(50*'=')\n", " \n", - " print(\"\\nDone!\")" + "# print(\"\\nDone!\")" ] }, { @@ -914,111 +1069,111 @@ "metadata": {}, "outputs": [], "source": [ - "class MultiLevelModel:\n", - " def __init__(self, model_dict: Dict, train: pd.DataFrame, test: pd.DataFrame, **model_kwargs):\n", + "# class MultiLevelModel:\n", + "# def __init__(self, model_dict: Dict, train: pd.DataFrame, test: pd.DataFrame, **model_kwargs):\n", " \n", - " self._demographics = [\n", - " 'primary_job_commute_time', 'income_category', 'n_residence_members', 'n_residents_u18', \n", - " 'n_residents_with_license', 'n_motor_vehicles', 'available_modes', 'age', 'gender_Man', \n", - " 'gender_Man;Nonbinary/genderqueer/genderfluid', 'gender_Nonbinary/genderqueer/genderfluid', \n", - " 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", - " 'has_drivers_license_No', 'has_drivers_license_Prefer not to say', 'has_drivers_license_Yes', \n", - " 'has_multiple_jobs_No', 'has_multiple_jobs_Prefer not to say', 'has_multiple_jobs_Yes', \n", - " \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", - " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", - " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", - " 'primary_job_type_Full-time', 'primary_job_type_Part-time', 'primary_job_type_Prefer not to say', \n", - " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", - " 'primary_job_description_Education', 'primary_job_description_Food service', \n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", - " 'primary_job_description_Medical/healthcare', 'primary_job_description_Other', \n", - " 'primary_job_description_Professional, managerial, or technical', \n", - " 'primary_job_description_Sales or service', 'primary_job_commute_mode_Active transport', \n", - " 'primary_job_commute_mode_Car transport', 'primary_job_commute_mode_Hybrid', \n", - " 'primary_job_commute_mode_Public transport', 'primary_job_commute_mode_Unknown', \n", - " 'primary_job_commute_mode_WFH', 'is_overnight_trip', 'n_working_residents'\n", - " ]\n", + "# self._demographics = [\n", + "# 'primary_job_commute_time', 'income_category', 'n_residence_members', 'n_residents_u18', \n", + "# 'n_residents_with_license', 'n_motor_vehicles', 'available_modes', 'age', 'gender_Man', \n", + "# 'gender_Man;Nonbinary/genderqueer/genderfluid', 'gender_Nonbinary/genderqueer/genderfluid', \n", + "# 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", + "# 'has_drivers_license_No', 'has_drivers_license_Prefer not to say', 'has_drivers_license_Yes', \n", + "# 'has_multiple_jobs_No', 'has_multiple_jobs_Prefer not to say', 'has_multiple_jobs_Yes', \n", + "# \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", + "# 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", + "# 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", + "# 'primary_job_type_Full-time', 'primary_job_type_Part-time', 'primary_job_type_Prefer not to say', \n", + "# 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + "# 'primary_job_description_Education', 'primary_job_description_Food service', \n", + "# 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + "# 'primary_job_description_Medical/healthcare', 'primary_job_description_Other', \n", + "# 'primary_job_description_Professional, managerial, or technical', \n", + "# 'primary_job_description_Sales or service', 'primary_job_commute_mode_Active transport', \n", + "# 'primary_job_commute_mode_Car transport', 'primary_job_commute_mode_Hybrid', \n", + "# 'primary_job_commute_mode_Public transport', 'primary_job_commute_mode_Unknown', \n", + "# 'primary_job_commute_mode_WFH', 'is_overnight_trip', 'n_working_residents'\n", + "# ]\n", " \n", - " assert all([c in test.columns for c in self._demographics]), \"[test] Demographic features are missing!\"\n", - " assert all([c in train.columns for c in self._demographics]), \"[train] Demographic features are missing!\"\n", + "# assert all([c in test.columns for c in self._demographics]), \"[test] Demographic features are missing!\"\n", + "# assert all([c in train.columns for c in self._demographics]), \"[train] Demographic features are missing!\"\n", " \n", - " self._mdict = model_dict\n", - " self._train = train\n", - " self._test = test\n", - " self.metric = model_kwargs.pop('metric', SimilarityMetric.COSINE)\n", + "# self._mdict = model_dict\n", + "# self._train = train\n", + "# self._test = test\n", + "# self.metric = model_kwargs.pop('metric', SimilarityMetric.COSINE)\n", " \n", " \n", - " def _phase1(self):\n", + "# def _phase1(self):\n", " \n", - " tr = self._train.copy()\n", - " te = self._test.copy()\n", + "# tr = self._train.copy()\n", + "# te = self._test.copy()\n", " \n", - " if tr.columns.isin(['user_id', 'target']).sum() == 2:\n", - " tr = tr.drop(columns=['user_id', 'target']).reset_index(drop=True)\n", + "# if tr.columns.isin(['user_id', 'target']).sum() == 2:\n", + "# tr = tr.drop(columns=['user_id', 'target']).reset_index(drop=True)\n", " \n", - " if te.columns.isin(['user_id', 'target']).sum() == 2:\n", - " te = te.drop(columns=['user_id', 'target']).reset_index(drop=True)\n", + "# if te.columns.isin(['user_id', 'target']).sum() == 2:\n", + "# te = te.drop(columns=['user_id', 'target']).reset_index(drop=True)\n", "\n", - " te_users = self._test.user_id.tolist()\n", + "# te_users = self._test.user_id.tolist()\n", "\n", - " if self.metric == SimilarityMetric.COSINE:\n", + "# if self.metric == SimilarityMetric.COSINE:\n", "\n", - " sim = cosine_similarity(te.values, tr.values)\n", + "# sim = cosine_similarity(te.values, tr.values)\n", "\n", - " # Compute the argmax across the train set.\n", - " argmax = np.argmax(sim, axis=1)\n", + "# # Compute the argmax across the train set.\n", + "# argmax = np.argmax(sim, axis=1)\n", "\n", - " # Retrieve the user_id at these indices.\n", - " train_users = self._train.loc[argmax, 'user_id']\n", + "# # Retrieve the user_id at these indices.\n", + "# train_users = self._train.loc[argmax, 'user_id']\n", "\n", - " elif self.metric == SimilarityMetric.EUCLIDEAN:\n", + "# elif self.metric == SimilarityMetric.EUCLIDEAN:\n", "\n", - " sim = euclidean_distances(te.values, tr.values)\n", + "# sim = euclidean_distances(te.values, tr.values)\n", "\n", - " # Compute the argmin here!\n", - " argmin = np.argmin(sim, axis=1)\n", + "# # Compute the argmin here!\n", + "# argmin = np.argmin(sim, axis=1)\n", "\n", - " # Retrieve the train user_ids.\n", - " train_users = self._train.loc[argmin, 'user_id']\n", + "# # Retrieve the train user_ids.\n", + "# train_users = self._train.loc[argmin, 'user_id']\n", "\n", - " return pd.DataFrame({'test_user_id': te_users, 'train_user_id': train_users})\n", + "# return pd.DataFrame({'test_user_id': te_users, 'train_user_id': train_users})\n", " \n", " \n", - " def _phase2(self, sim_df: pd.DataFrame, cold_start: bool):\n", + "# def _phase2(self, sim_df: pd.DataFrame, cold_start: bool):\n", " \n", - " prediction_df = list()\n", + "# prediction_df = list()\n", " \n", - " # Now, we use the sim_df to run inference based on whether \n", - " for ix, row in sim_df.iterrows():\n", - " train_user = row['train_user_id']\n", + "# # Now, we use the sim_df to run inference based on whether \n", + "# for ix, row in sim_df.iterrows():\n", + "# train_user = row['train_user_id']\n", " \n", - " # Retrieve the appropriate model.\n", - " user_models = self._mdict.get(train_user, None)\n", + "# # Retrieve the appropriate model.\n", + "# user_models = self._mdict.get(train_user, None)\n", " \n", - " start_type = 'cold_start' if cold_start else 'warm_start'\n", + "# start_type = 'cold_start' if cold_start else 'warm_start'\n", " \n", - " # which specific model?\n", - " sp_model = user_models.get(start_type, None)\n", + "# # which specific model?\n", + "# sp_model = user_models.get(start_type, None)\n", " \n", - " # Now get the test user data.\n", - " test_user = row['test_user_id']\n", + "# # Now get the test user data.\n", + "# test_user = row['test_user_id']\n", " \n", - " if cold_start:\n", - " test_data = self._test.loc[self._test.user_id == test_user, self._demographics]\n", - " test_data = test_data.iloc[0, :]\n", - " else:\n", - " test_data = self._test.loc[self._test.user_id == test_user, :]\n", + "# if cold_start:\n", + "# test_data = self._test.loc[self._test.user_id == test_user, self._demographics]\n", + "# test_data = test_data.iloc[0, :]\n", + "# else:\n", + "# test_data = self._test.loc[self._test.user_id == test_user, :]\n", " \n", - " predictions = sp_model.predict(test_data)\n", + "# predictions = sp_model.predict(test_data)\n", " \n", - " print(f\"test: [{test_user}], predictions: {predictions}\")\n", + "# print(f\"test: [{test_user}], predictions: {predictions}\")\n", " \n", " \n", - " def execute_pipeline(self, cold_start: bool = False):\n", - " # For each test user, get the most similar train user.\n", - " sim_df = self._phase1()\n", + "# def execute_pipeline(self, cold_start: bool = False):\n", + "# # For each test user, get the most similar train user.\n", + "# sim_df = self._phase1()\n", " \n", - " predictions = self._phase2(sim_df, cold_start)" + "# predictions = self._phase2(sim_df, cold_start)" ] }, { @@ -1028,11 +1183,11 @@ "metadata": {}, "outputs": [], "source": [ - "# FULL DATA.\n", - "train = df.loc[df.user_id.isin(TRAIN_USERS), :]\n", - "test = df.loc[df.user_id.isin(TEST_USERS), :]\n", + "# # FULL DATA.\n", + "# train = df.loc[df.user_id.isin(TRAIN_USERS), :]\n", + "# test = df.loc[df.user_id.isin(TEST_USERS), :]\n", "\n", - "train_counts = train.user_id.value_counts()" + "# train_counts = train.user_id.value_counts()" ] }, { @@ -1042,14 +1197,14 @@ "metadata": {}, "outputs": [], "source": [ - "## We only want to train on users who have a good number of trips.\n", - "good_users = train_counts[train_counts >= 100].index\n", + "# ## We only want to train on users who have a good number of trips.\n", + "# good_users = train_counts[train_counts >= 100].index\n", "\n", - "bad_users = train_counts[train_counts < 100].index\n", + "# bad_users = train_counts[train_counts < 100].index\n", "\n", - "print(f\"Number of users filtered out of training: {len(bad_users)}\")\n", + "# print(f\"Number of users filtered out of training: {len(bad_users)}\")\n", "\n", - "filtered_train = train.loc[train.user_id.isin(good_users), :]" + "# filtered_train = train.loc[train.user_id.isin(good_users), :]" ] }, { @@ -1059,10 +1214,10 @@ "metadata": {}, "outputs": [], "source": [ - "# Full data.\n", + "# # Full data.\n", "\n", - "train_df = drop_columns(filtered_train)\n", - "test_df = drop_columns(test)" + "# train_df = drop_columns(filtered_train)\n", + "# test_df = drop_columns(test)" ] }, { @@ -1072,7 +1227,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(train_df.shape, test_df.shape)" + "# print(train_df.shape, test_df.shape)" ] }, { @@ -1084,7 +1239,7 @@ }, "outputs": [], "source": [ - "model_dict = construct_model_dictionary(train_df)" + "# model_dict = construct_model_dictionary(train_df)" ] }, { diff --git a/replacement_mode_modeling/04_FeatureClustering.ipynb b/replacement_mode_modeling/04_FeatureClustering.ipynb index 094d84c6..1ee33f65 100644 --- a/replacement_mode_modeling/04_FeatureClustering.ipynb +++ b/replacement_mode_modeling/04_FeatureClustering.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "789df947", "metadata": {}, "outputs": [], @@ -39,16 +39,16 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "aea4dda7", "metadata": {}, "outputs": [], "source": [ - "DATA_SOURCES = [\n", + "DATA_SOURCE = [\n", " ('./data/filtered_data/preprocessed_data_Stage_database.csv', 'allceo'),\n", " ('./data/filtered_data/preprocessed_data_openpath_prod_durham.csv', 'durham'),\n", - " ('./data/filtered_data/preprocessed_data_openpath_prod_ride2own.csv', 'ride2own'),\n", " ('./data/filtered_data/preprocessed_data_openpath_prod_mm_masscec.csv', 'masscec'),\n", + " ('./data/filtered_data/preprocessed_data_openpath_prod_ride2own.csv', 'ride2own'),\n", " ('./data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv', 'nicr')\n", "]\n", "\n", @@ -58,31 +58,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "33ef3275", "metadata": {}, "outputs": [], "source": [ "# Change this name to something unique\n", - "CURRENT_DB = DATA_SOURCES[DB_NUMBER][1]\n", - "PATH = DATA_SOURCES[DB_NUMBER][0]\n", + "PATH = DATA_SOURCE[DB_NUMBER][0]\n", + "CURRENT_DB = DATA_SOURCE[DB_NUMBER][1]\n", "\n", "df = pd.read_csv(PATH)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "d0d884a3", + "execution_count": 4, + "id": "d6f69976", "metadata": {}, "outputs": [], "source": [ - "df.target.value_counts()" + "df.dropna(inplace=True)\n", + "\n", + "not_needed = ['deprecatedID', 'data.key']\n", + "\n", + "for col in not_needed:\n", + " if col in df.columns:\n", + " df.drop(columns=[col], inplace=True)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "b2281bdc", "metadata": {}, "outputs": [], @@ -95,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "9c22d6ac", "metadata": {}, "outputs": [], @@ -107,7 +113,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "063f6124", "metadata": {}, "outputs": [], @@ -117,7 +123,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "cef8d45b", "metadata": {}, "outputs": [], @@ -131,7 +137,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "68c6af2d", "metadata": {}, "outputs": [], @@ -141,7 +147,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "eff378a7", "metadata": {}, "outputs": [], @@ -151,7 +157,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "cffbd401", "metadata": {}, "outputs": [], @@ -161,7 +167,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "f1eb1633", "metadata": {}, "outputs": [], @@ -175,7 +181,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "d9cc0a0f", "metadata": { "scrolled": true @@ -191,7 +197,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "750fbd0c", "metadata": {}, "outputs": [], @@ -209,46 +215,270 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "1c3d1849", "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", + "
coverage_bicyclingcoverage_carcoverage_transitcoverage_unknowncoverage_walkingpct_distance_bicyclingpct_distance_carpct_distance_transitpct_distance_unknownpct_distance_walkingn_tripsstart:hourend:hour
user_id
0600d3df-c1aa-4ca2-83f2-1f6b8931280d0.0500000.8500000.00.0000000.1000000.0092820.9849540.00.0000000.0057640.0833330.4121180.650288
44eda4da-9223-4bb0-afd4-e7dd19fc6b270.0650410.7804880.00.0650410.0894310.0381800.9126930.00.0331710.0159570.7435900.1498770.149877
4c5436e9-4840-4872-9e8f-5d46ba81fe520.0000000.7142860.00.0000000.2857140.0000000.8472470.00.0000000.1527530.0000000.6502880.650288
7479810c-c602-4508-8ae2-da0bed87558d0.1162790.4534880.00.1279070.3023260.0155300.9264890.00.0270850.0308960.5064100.1498770.990607
7f7c9d3b-84ed-4c14-be8a-aa256daaed010.0175440.7719300.00.0350880.1754390.0051570.8543270.00.1100330.0304830.3205130.9906070.990607
\n", + "
" + ], + "text/plain": [ + " coverage_bicycling coverage_car \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.050000 0.850000 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.065041 0.780488 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 0.714286 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.116279 0.453488 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.017544 0.771930 \n", + "\n", + " coverage_transit coverage_unknown \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.0 0.000000 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.0 0.065041 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.0 0.000000 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.0 0.127907 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.0 0.035088 \n", + "\n", + " coverage_walking \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.100000 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.089431 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.285714 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.302326 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.175439 \n", + "\n", + " pct_distance_bicycling \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.009282 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.038180 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.015530 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.005157 \n", + "\n", + " pct_distance_car pct_distance_transit \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.984954 0.0 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.912693 0.0 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.847247 0.0 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.926489 0.0 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.854327 0.0 \n", + "\n", + " pct_distance_unknown \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.000000 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.033171 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.027085 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.110033 \n", + "\n", + " pct_distance_walking n_trips \\\n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.005764 0.083333 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.015957 0.743590 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.152753 0.000000 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.030896 0.506410 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.030483 0.320513 \n", + "\n", + " start:hour end:hour \n", + "user_id \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.412118 0.650288 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.149877 0.149877 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.650288 0.650288 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.149877 0.990607 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.990607 0.990607 " + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "figure1_df.head()" ] }, + { + "cell_type": "markdown", + "id": "aa9f5a04", + "metadata": {}, + "source": [ + "### Uncomment the following if you want to find the best eps." + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "598d82bc", "metadata": {}, "outputs": [], "source": [ - "epsilons = np.linspace(1e-3, 1., 1000)\n", + "# epsilons = np.linspace(1e-3, 1., 1000)\n", "\n", - "best_eps = -np.inf\n", - "best_score = -np.inf\n", + "# best_eps = -np.inf\n", + "# best_score = -np.inf\n", "\n", - "for eps in epsilons:\n", - " model = DBSCAN(eps=eps).fit(figure1_df)\n", + "# for eps in epsilons:\n", + "# model = DBSCAN(eps=eps).fit(figure1_df)\n", " \n", - " if len(np.unique(model.labels_)) < 2:\n", - " continue\n", + "# if len(np.unique(model.labels_)) < 2:\n", + "# continue\n", " \n", - " score = silhouette_score(figure1_df, model.labels_)\n", - " if score > best_score:\n", - " best_eps = eps\n", - " best_score = score\n", + "# score = silhouette_score(figure1_df, model.labels_)\n", + "# if score > best_score:\n", + "# best_eps = eps\n", + "# best_score = score\n", "\n", - "print(best_eps)" + "# print(best_eps)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "bc89a42d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Counter({0: 8, -1: 4})\n" + ] + } + ], "source": [ "'''\n", "AlLCEO: eps=0.542\n", @@ -263,12 +493,47 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "05c9a7c4", "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4 users in cluster -1\n" + ] + }, + { + "data": { + "image/png": "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v18333yzwsLC9OqrryokJERLly7VsGHD9Msvv+ipp56SdD4cxsTEyGq1as6cOapdu7aWLVvm8f6ApUuXasiQIerXr5/eeustWa1WvfHGG4qPj9dHH31U4g5mt9t1/PhxjRs3TvXq1VN+fr4+/vhj3X333Vq4cKGGDBni0n/16tXatGmTJk2apDp16igsLEzffPONevTo4QxfAQEBSk5O1tKlSz2OuXPnTiUmJmrChAkKDg7W1KlTdffddysxMVGffPKJ/vGPf8hisejpp59Wnz59dODAAedvhgcPHlTz5s117733qlatWsrJydHcuXN1ww036Ntvv1VoaKgsFouWLFmidu3aaeDAgdq0aZOsVqseeeQRHThwQF988YUCAwOLXSferPuLZWZm6p577tE999yjKVOmyM/PT4cOHdKnn34qSbr++uu1cOFCDR8+XM8884zzkkf9+vWdy8jPz9cdd9yhhx9+WH//+9917ty5Esdcs2aNNm7cqGnTpikwMFBz5szRoEGD5OPjowEDBpRa84VWrVqlAQMGKDg4WHPmzJF0/oxIcTIyMtSjRw+1adNG8+fPl81m05w5c9S3b1+9/fbbuueee1z6jxw5Ur1793YeK5588kk98MADzvXjyZw5c/T222/rueee08KFC9WiRQtdc801kqSkpCSNHz9egwYNUlJSko4dO6YpU6YoOjpa27Zt07XXXutcjrfrtSxK+7yl8yE4JiZGP/30k8aPH682bdpoz549mjRpknbt2qWPP/7YJeB42sdWrFihRx55RI899phmzpypKlWq6IcfftC3335b7trL81lI0kcffaS+ffsqKipKL7/8sho0aKCDBw9qw4YN5a7lQi+88IKmTJmiZ555Rl26dJHD4dC+ffucl2RGjhyp48eP67XXXtP777+v8PBwSVLLli0lSf/4xz/0zDPPOPex/Px8vfjii+rcubO+/PJLZz/pymwTV4xRSSxcuNCQZGzdutVwOBzGqVOnjA8//NCoU6eO0aVLF8PhcDj7tmjRwmjfvr1Lm2EYRp8+fYzw8HCjoKDAZZl33XWXS7/PP//ckGQ899xzzrahQ4caDRs2LLa+goICw+FwGIsXLzaqVq1qHD9+3DAMwzh16pQRFBRk3HrrrUZhYWGx85e15nvuucfw9/c3cnNznX3OnTtntGjRwpBkHDhwoNgxit6HJCMlJcXZ5nA4jGuuucaQZHz99dfO9mPHjhlVq1Y1EhISnG333nuvYbPZjOzsbJfl9uzZ0wgICDBOnDhhGIZhPP3004bFYjF27Njh0q9Hjx6GJGPjxo2GYRjG6dOnjVq1ahl9+/Z16VdQUGC0bdvWuPHGG0t8Pxc7d+6c4XA4jBEjRhjt27d3eU2SERwc7Pxsivztb38zAgMDjd9++81l/JYtW7qt04YNGxr+/v7GTz/95GzbsWOHIckIDw83Tp8+7WxfvXq1IclYs2ZNifX+8ccfRmBgoPHKK6+4vLZ582bDx8fHGDNmjLFgwQJDkjFv3rxS10FZ171huG/XM2fONCQ5P0dPtm3bZkgyFi5c6PZa0fa1YMECj69dvA9JKnZ7btq0qbNt8uTJhqfDWdE+fOFn1KpVKyMmJsat74EDB9zq7tSpkxEWFmacOnXKZfzWrVsb9evXd+6zReM88sgjLst84YUXDElGTk6O23ie6ty2bZuz7ffffzf8/f2NXr16ufTNzs42bDabcd999znbSlqvnhR3vLp4PZbl805KSjKqVKniUrthGMZ7771nSDJSU1OdbcXtY48++qhRo0aNMtV+MUnG5MmTndOX+lk0adLEaNKkifHnn38W28fTdtWwYUNj6NChbn1jYmJctrc+ffoY7dq1K7GGF1980ePxOjs72/Dx8TEee+wxl/ZTp04ZderUMQYOHOhs83abKKvAwECP7/NSVbrLNJ06dZLValX16tV1++23q2bNmvrggw/k43P+JNAPP/ygffv26f7775cknTt3zvnTq1cv5eTkaP/+/S7LLOpb5Oabb1bDhg21cePGEmvZvn277rjjDoWEhKhq1aqyWq0aMmSICgoK9N1330k6f6NSXl6eHnnkEY+nmb2teePGjYqNjVXt2rWd81etWtXtN7iSWCwW9erVyznt4+Ojpk2bKjw8XO3bt3e216pVS2FhYS6XED799FPFxsYqIiLCZZnDhg3TmTNnlJmZ6ayzVatWatu2rUu/++67z2V6y5YtOn78uIYOHeryvgsLC3X77bdr27ZtpV6SePfdd3XLLbeoWrVq8vHxkdVq1fz5891OdUtS9+7dVbNmTZe2jIwMde/eXaGhoc62KlWqaODAgR7Ha9eunerVq+ecjoqKknT+dO2F12uL2i9cf3/88YeefvppNW3aVD4+PvLx8VG1atV0+vRpt3pvueUWTZ8+XbNmzdL//u//6oEHHtCIESNKXBdS2de9J0WXYAYOHKh33nlHR44cKXUeT/r371/mvsVtzz/88IN++umnco1fFqdPn9YXX3yhAQMGqFq1ai7jDx48WD/99JPbseKOO+5wmW7Tpo0k18+4rDIzM/Xnn3+6namNiIhQ9+7dPV6m9Ga9lkVZPu9169apdevWateuncs+Gh8f7/HJOE/72I033qgTJ05o0KBB+uCDD3T06NFLrr08n8V3332nH3/8USNGjJCfn98l1+DJjTfeqJ07d+qRRx7RRx99pLy8vDLP+9FHH+ncuXMaMmSIy7r28/NTTEyMx6cQy7pNXLi8c+fOyTCMMtd1OVS6MLJ48WJt27ZNn376qR5++GHt3btXgwYNcr5edO/IuHHjZLVaXX4eeeQRSXLbEerUqeM2Tp06dXTs2LFi68jOzlbnzp115MgRvfLKK9q0aZO2bdum2bNnS5L+/PNPSdJvv/0myfU09sW8qfnYsWPF1ltWAQEBbjuir6+vatWq5dbX19dXZ8+edU4fO3bMeVrxQnXr1nW+7k2dRe99wIABbu/9+eefl2EYOn78eLHv5f3339fAgQNVr149LV26VJmZmdq2bZsefPBBl7qLeKr92LFjLv8ZFvHUJsltPRXdfV5c+4V13HfffXr99dc1cuRIffTRR/ryyy+1bds2XXPNNc5t5kL333+/fH19ZbfbndeZS3Mp20iXLl20evVq5wGxfv36at26td5+++0yjS2d376CgoLK3L+kWkvaBy/V77//LsMwyrQ9FwkJCXGZLroE5OmzK03Rsosb/+KxvV2vZVGWz/uXX37RN99847Z/Vq9eXYZhuB1PPb2fwYMHa8GCBTp06JD69++vsLAw3XTTTUpLSyt37eX5LMpyPL5UiYmJmjlzprZu3aqePXsqJCREsbGxbvePeVJ0PLzhhhvc1vfKlSvd1nVZt4mDBw+6LS8jI6N8b7CcKt09I1FRUc6bVrt166aCggLNmzdP7733ngYMGOD87TYxMVF33323x2U0b97cZTo3N9etT25urpo2bVpsHatXr9bp06f1/vvvq2HDhs72ix93LLo2XNJveN7UHBISUmy9f4WQkBDl5OS4tRfdOFb0XspaZ1H/1157rdi75osLBdL5+00aNWqklStXupx5stvtHvt7OjsVEhLidgO0p1ov1cmTJ7Vu3TpNnjxZf//7353tRfe9XKygoED333+/atasKZvNphEjRujzzz8v9dG7S91G+vXrp379+slut2vr1q1KSkrSfffdp8jISEVHR5c6f3FnAItTUq1F/+EUhWe73e5yD8il/IZds2ZNValSpUzb85VQ9N6KG//isb1Zr35+fh73AU/rq7TPOzQ0VP7+/i73wV2orHUOHz5cw4cP1+nTp/XZZ59p8uTJ6tOnj7777juXY+iVVJbjcXFKWqcXrgMfHx8lJCQoISFBJ06c0Mcff6zx48crPj5ehw8fLvFpl6LlvPfee2VaJ2XdJurWratt27a5tF38/+CVVunOjFzshRdeUM2aNTVp0iQVFhaqefPmuvbaa7Vz50517NjR48/Fz/cvW7bMZXrLli06dOiQyx3SFyvaCC48MBqGoX/9618u/W6++WYFBwcrOTm52NNi3tTcrVs3ffLJJy7/eRYUFGjlypWlr6zLIDY2Vp9++qnbXeuLFy9WQECAM1B069ZNe/bs0c6dO136XXyj7S233KIaNWro22+/Lfa9l/Sfr8Vicf4RqSK5ubken6YpTkxMjD799FOXA3VhYaHefffdMi+jLCwWiwzDcLuhct68eSooKHDrP3nyZG3atEnLli3TypUrtXPnzjKdHSnrui+NzWZTTEyMnn/+eUly3s1/KWcDPClue27SpInzN9iiJ0O++eYbl3nXrl3rse6y1BYYGKibbrpJ77//vkv/wsJCLV26VPXr13e5Mf5yi46Olr+/v9uN0j/99JPzcmh5RUZG6tdff3VZr/n5+froo4+Knae4z7tPnz768ccfFRIS4nH/9PaP5gUGBqpnz56aMGGC8vPznY89/xWaNWumJk2aaMGCBcX+wlKcyMhIt+3vu+++c7uUd6EaNWpowIABGj16tI4fP+586qu4fSg+Pl4+Pj768ccfiz0eloevr2+p/w9eaZXuzMjFatasqcTERD311FNavny5HnjgAb3xxhvq2bOn4uPjNWzYMNWrV0/Hjx/X3r179fXXX7v9J5OVlaWRI0fqb3/7mw4fPqwJEyaoXr16zksknvTo0UO+vr4aNGiQnnrqKZ09e1Zz5851++Nr1apV00svvaSRI0fqtttu00MPPaTatWvrhx9+0M6dO/X6669LUplrfuaZZ7RmzRp1795dkyZNUkBAgGbPnl3qfRWXy+TJk7Vu3Tp169ZNkyZNUq1atbRs2TKtX79eL7zwgoKDgyVJY8aM0YIFC9S7d28999xzzic69u3b57Z+XnvtNQ0dOlTHjx/XgAEDFBYWpt9++007d+7Ub7/9prlz5xZbT58+ffT+++/rkUce0YABA3T48GE9++yzCg8PL/Nf5p0wYYLWrl2r2NhYTZgwQf7+/kpOTnau08v12FtQUJC6dOmiF198UaGhoYqMjFRGRobmz5/v9tRWWlqakpKSNHHiROd/SklJSRo3bpy6du2qu+66q9hxyrruPZk0aZJ++uknxcbGqn79+jpx4oReeeUVWa1WxcTESDr/t0n8/f21bNkyRUVFqVq1aqpbt67z0oa3QkND1b17d02cONH5NM2+fftcHu/t1auXatWqpREjRmjatGny8fHRokWLdPjwYbflXXfddVqxYoVWrlypxo0by8/PT9ddd53HsZOSktSjRw9169ZN48aNk6+vr+bMmaPdu3fr7bff9vosjzdq1KihiRMnavz48RoyZIgGDRqkY8eOaerUqfLz89PkyZPLvex77rlHkyZN0r333qsnn3xSZ8+e1auvvuoWesvyeY8ZM0YpKSnq0qWLxo4dqzZt2qiwsFDZ2dnasGGDnnjiCd10000l1vPQQw/J399ft9xyi8LDw5Wbm6ukpCQFBwc771v5q8yePVt9+/ZVp06dNHbsWDVo0EDZ2dn66KOP3H4xvdDgwYP1wAMP6JFHHlH//v116NAhvfDCC86zLUX69u3r/HtY11xzjQ4dOqRZs2apYcOGzqejirbHV155RUOHDpXValXz5s0VGRmpadOmacKECfrPf/7jvC/yl19+0ZdffqnAwEBNnTr1sq+TjIwM5yWsgoICHTp0SO+9956k87+sXfwey+Wy3xJrEk93oxf5888/jQYNGhjXXnutce7cOcMwDGPnzp3GwIEDjbCwMMNqtRp16tQxunfvbiQnJ7stc8OGDcbgwYONGjVqOO9u//77713G8HR3+tq1a422bdsafn5+Rr169Ywnn3zS+Pe//+32xIJhGEZqaqoRExNjBAYGGgEBAUbLli2N559/3qVPWWo2jPNP+3Tq1Mmw2WxGnTp1jCeffNJ48803y/w0TWBgoFt7TEyM0apVK7f2hg0bGr1793Zp27Vrl9G3b18jODjY8PX1Ndq2bevx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O2Z2CcBV79SpU5IkwzBK7OdVGClisbgeMAzDcGsrrb+n9iJJSUmaOnWqW3ujRo28LRUArojQl8yuAKg4Tp06peDg4GJf9yqMhIaGqmrVqm5nQX799Ve3sx9F6tSp47G/j4+PQkJCPM6TmJiohIQE53RhYaGOHz+ukJCQEkMPgIonLy9PEREROnz4sIKCgswuB8BlZBiGTp06pbp165bYz6sw4uvrqw4dOigtLU133XWXsz0tLU39+vXzOE90dLTWrl3r0rZhwwZ17NhRVqvV4zw2m002m82lrUaNGt6UCqCCCQoKIowAlVBJZ0SKeP00TUJCgubNm6cFCxZo7969Gjt2rLKzszVq1ChJ589qDBkyxNl/1KhROnTokBISErR3714tWLBA8+fP17hx47wdGgAAVEJe3zNyzz336NixY5o2bZpycnLUunVrpaamqmHDhpKknJwcl7850qhRI6Wmpmrs2LGaPXu26tatq1dffVX9+/e/fO8CAABUWBajtFtcAeAKstvtSkpKUmJiotvlWQD/HQgjAADAVHxRHgAAMBVhBAAAmIowAgAATEUYAXBZpKeny2Kx6MSJE2aXAqCCIYwAAABTEUYAAICpCCMAJEmRkZGaNWuWS1u7du00ZcoUSee/2HLevHm66667FBAQoGuvvVZr1qwpdnl//vmnevfurU6dOun48eM6ePCgLBaL3n//fXXr1k0BAQFq27atMjMzXeZLSUlRq1atZLPZFBkZqZde+v/fSPfaa6/puuuuc06vXr1aFotFs2fPdrbFx8crMTFRkjRlyhS1a9dOS5YsUWRkpIKDg3Xvvfc6v0kUwNWBMAKgzKZOnaqBAwfqm2++Ua9evXT//ffr+PHjbv1OnjypuLg45efn65NPPlGtWrWcr02YMEHjxo3Tjh071KxZMw0aNEjnzp2TJH311VcaOHCg7r33Xu3atUtTpkzRxIkTtWjRIklS165dtWfPHh09elSSlJGRodDQUGVkZEiSzp07py1btigmJsY53o8//qjVq1dr3bp1WrdunTIyMjRjxowrtYoAlANhBECZDRs2TIMGDVLTpk31j3/8Q6dPn9aXX37p0ueXX35RTEyMwsLCtH79egUGBrq8Pm7cOPXu3VvNmjXT1KlTdejQIf3www+SpJdfflmxsbGaOHGimjVrpmHDhunRRx/Viy++KElq3bq1QkJCnOEjPT1dTzzxhHN627ZtOnv2rG699VbneIWFhVq0aJFat26tzp07a/Dgwfrkk0+u2DoC4D3CCIAya9OmjfPfgYGBql69un799VeXPrfddpsaN26sd955R76+viUuIzw8XJKcy9i7d69uueUWl/633HKLvv/+exUUFMhisahLly5KT0/XiRMntGfPHo0aNUoFBQXau3ev0tPTdf3116tatWrO+SMjI1W9enWXMS+uGYC5CCMAJElVqlTRxd8O4XA4XKatVqvLtMViUWFhoUtb7969tWnTJn377bcex7lwGRaLRZKcyzAMw9lW5OKaunbtqvT0dG3atElt27ZVjRo11KVLF2VkZCg9PV1du3b1umYA5iKMAJAkXXPNNcrJyXFO5+Xl6cCBA14vZ8aMGRo6dKhiY2OLDSTFadmypTZv3uzStmXLFjVr1kxVq1aV9P/vG3nvvfecwSMmJkYff/yx2/0iACoGwggASVL37t21ZMkSbdq0Sbt379bQoUOdAcBbM2fO1P3336/u3btr3759ZZ7viSee0CeffKJnn31W3333nd566y29/vrrGjdunLNP0X0jy5Ytc4aRrl27avXq1frzzz9d7hcBUDH4mF0AgKtDYmKi/vOf/6hPnz4KDg7Ws88+W64zI0X++c9/qqCgQN27d1d6errH+0cudv311+udd97RpEmT9Oyzzyo8PFzTpk3TsGHDnH0sFotiYmK0evVqde7cWdL5+1CCg4PVuHFjBQUFlbtmAOawGBdfkAUAAPgLcZkGAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGAqwggAADAVYQRAmVkslhJ/LvxLqX+1yMhIzZo1y7TxAZQffw4eQJld+EV6K1eu1KRJk7R//35nm7+/v1fLy8/PL9OfiQdQuXFmBECZ1alTx/kTHBwsi8XinLZarRo1apTq16+vgIAAXXfddXr77bdd5u/ataseffRRJSQkKDQ0VD169JAkrVmzRtdee638/f3VrVs3vfXWW7JYLDpx4oRz3i1btqhLly7y9/dXRESEHn/8cZ0+fdq53EOHDmns2LHOszQAKg7CCIDL4uzZs+rQoYPWrVun3bt363/+5380ePBgffHFFy793nrrLfn4+Ojzzz/XG2+8oYMHD2rAgAG68847tWPHDj388MOaMGGCyzy7du1SfHy87r77bn3zzTdauXKlNm/erEcffVSS9P7776t+/fqaNm2acnJyXM7gALj68UV5AMpl0aJFGjNmjMvZi4v17t1bUVFRmjlzpqTzZzBOnjyp7du3O/v8/e9/1/r167Vr1y5n2zPPPKPp06fr999/V40aNTRkyBD5+/vrjTfecPbZvHmzYmJidPr0afn5+SkyMlJjxozRmDFjLvt7BXBlcc8IgMuioKBAM2bM0MqVK3XkyBHZ7XbZ7XYFBga69OvYsaPL9P79+3XDDTe4tN14440u01999ZV++OEHLVu2zNlmGIYKCwt14MABRUVFXeZ3A+CvRBgBcFm89NJL+uc//6lZs2bpuuuuU2BgoMaMGaP8/HyXfheHE8Mw3O7xuPiEbWFhoR5++GE9/vjjbuM2aNDgMr0DAGYhjAC4LDZt2qR+/frpgQcekHQ+QHz//felnrVo0aKFUlNTXdqysrJcpq+//nrt2bNHTZs2LXY5vr6+KigoKGf1AMzEDawALoumTZsqLS1NW7Zs0d69e/Xwww8rNze31Pkefvhh7du3T08//bS+++47vfPOO1q0aJEkOc+YPP3008rMzNTo0aO1Y8cOff/991qzZo0ee+wx53IiIyP12Wef6ciRIzp69OgVeY8ArgzCCIDLYuLEibr++usVHx+vrl27qk6dOrrzzjtLna9Ro0Z677339P7776tNmzaaO3eu82kam80mSWrTpo0yMjL0/fffq3Pnzmrfvr0mTpyo8PBw53KmTZumgwcPqkmTJrrmmmuuyHsEcGXwNA2Aq8706dOVnJysw4cPm10KgL8A94wAMN2cOXN0ww03KCQkRJ9//rlefPFF598QAVD5EUYAmO7777/Xc889p+PHj6tBgwZ64oknlJiYaHZZAP4iXKYBAACm4gZWAABgKsIIAAAwFWEEAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGCq/wd9UcKr1s6aGAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8 users in cluster 0\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAHFCAYAAACuBbDPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA6QElEQVR4nO3dd3RU1f7+8Wcgk0khCSQh0gKhiISOgjQlFAFpYkGaIiD60wvqRUQRaQmisV+8KqCigFLEgoiISlBBEFDwSlUElCqgApIgyDAk+/eHK/NlmLSJO4bg+7UWa3F29jn7M2fOOXlyyozDGGMEAABgQaniLgAAAFw4CBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAa877YDFz5kw5HA7vv6CgIFWsWFF9+/bVjh07inz8QYMGKSEhocjHKazs9bN79+7iLiVPy5cvl8Ph0PLly4u7lH+cnNZ9YbbrAwcOKDk5WRs2bAhovpzGcjgcuuuuuwJaTn6mTJmimTNn+rXv3r1bDocjx5/9HZ577jnVqlVLwcHBcjgcOnbsWLHUUdI4HA4lJyf/rWMW9fF09erVSk5O/tu3gd9//13Dhw9XpUqVFBISosaNG+uNN94osvHO+2CRbcaMGVqzZo2WLVumu+66S4sWLdIVV1yh3377rbhLA0qccePG6d133w1ongMHDiglJSXgYFGYsQojt2BRsWJFrVmzRt26dSvyGs61YcMG3XPPPWrXrp0+/fRTrVmzRhEREX97HSXRmjVrdNtttxV3GVatXr1aKSkpf3uwuP766zVr1ixNmDBBH374oZo1a6Z+/fpp7ty5RTJeUJEstQjUr19fTZs2lSS1bdtWmZmZmjBhghYuXKjBgwcXc3UoSYwxOnXqlEJDQ4u7lGJTs2bNIh/j5MmTCgsL+1vGyovL5VKLFi2KZeytW7dKkm6//XZdfvnlVpaZvV7PZzb2seJ6z0qivLaJJUuWKC0tTXPnzlW/fv0kSe3atdOePXt0//33q0+fPipdurTVekrMGYtzZYeMn3/+2ad9/fr1uuaaaxQdHa2QkBA1adJEb775pk+f7NNdaWlpGjx4sKKjoxUeHq4ePXroxx9/zHfsF154QW3atFFcXJzCw8PVoEEDPfHEE/J4PH59P/roI3Xo0EFRUVEKCwtTYmKiUlNTA65ZktauXavWrVsrJCRElSpV0ujRo3McMyeDBg1SmTJltG3bNnXu3Fnh4eGqWLGiHnvsMe+yr7jiCoWHh6t27dqaNWuW3zK2bNminj17qly5ct7TaTn127Ztm66++mqFhYUpNjZWd955p44fP55jXcuWLVOHDh0UGRmpsLAwtW7dWp988km+r+fUqVO677771LhxY0VFRSk6OlotW7bUe++959c3+7T7tGnTlJiYKJfL5a171apVatmypUJCQlS5cmWNGzdO06dP9zsdmpCQoO7du2vx4sVq0qSJQkNDlZiYqMWLF0v6c5tKTExUeHi4Lr/8cq1fv96nhvXr16tv375KSEhQaGioEhIS1K9fP+3Zs8fbxxijrl27KiYmRnv37vW2nzx5UvXq1VNiYqJOnDiR53op6LrP6fLEW2+9pebNm3u31Ro1aujWW2+V9OfllGbNmkmSBg8e7L00mX2qOnv72rx5szp16qSIiAh16NAh17Gyvfjii6pdu7ZcLpfq1q3rd3o2OTlZDofDb75zT1knJCRo69atWrFihbe27DFzuxSyatUqdejQQREREQoLC1OrVq30wQcf5DjOZ599pn/961+KjY1VTEyMrr/+eh04cCDH15Stbdu2uvnmmyVJzZs3l8Ph0KBBg7w/f/XVV9WoUSOFhIQoOjpa1113nb777jufZeS1XnOS27rOaT3m9X5ny8jI0MiRI1W9enUFBwercuXKGj58uN92mNc+NnXqVDVq1EhlypRRRESE6tSpo4ceeijPdZe9zLMvhfyV9yLbl19+qR49eigmJkYhISGqWbOmhg8fnuc8CQkJPu9btrZt26pt27be6aysLE2aNEmXXHKJQkNDVbZsWTVs2FDPPvuspD/fg/vvv1+SVL16de92evYlyvnz56tly5YKDw9XmTJl1LlzZ33zzTc+4wa6Tbz77rsqU6aMbrzxRp/2wYMH68CBA/ryyy/zfP2FUWLOWJxr165dkqTatWt72z777DNdffXVat68uaZNm6aoqCi98cYb6tOnj06ePOm3cQwZMkQdO3bU3LlztW/fPo0dO1Zt27bVpk2bVLZs2VzH/uGHH9S/f3/vzrZx40Y98sgj2rZtm1599VVvv1deeUW33367kpKSNG3aNMXFxWn79u3asmVLwDV/++236tChgxISEjRz5kyFhYVpypQpAZ3K8ng8uv7663XnnXfq/vvv19y5czV69GhlZGTonXfe0ahRo1SlShU999xzGjRokOrXr6/LLrtMkvT999+rVatWiouL03//+1/FxMRo9uzZGjRokH7++Wc98MADkv4MeklJSXI6nZoyZYouuugizZkzJ8fr6bNnz9Ytt9yinj17atasWXI6nXrxxRfVuXNnffzxx3nuLG63W0ePHtXIkSNVuXJlnT59WsuWLdP111+vGTNm6JZbbvHpv3DhQq1cuVLjx49XhQoVFBcXp02bNqljx47eIBUWFqZp06Zp9uzZOY65ceNGjR49WmPGjFFUVJRSUlJ0/fXXa/To0frkk0/06KOPyuFwaNSoUerevbt27drl/Ytt9+7duuSSS9S3b19FR0fr4MGDmjp1qpo1a6Zvv/1WsbGxcjgcev3119W4cWP17t1bK1eulNPp1NChQ7Vr1y59+eWXCg8Pz3WdBLLuz7VmzRr16dNHffr0UXJyskJCQrRnzx59+umnkqRLL71UM2bM0ODBgzV27FjvZYUqVap4l3H69Gldc801uuOOO/Tggw/qzJkzeY65aNEiffbZZ5o4caLCw8M1ZcoU9evXT0FBQerVq1e+NZ/t3XffVa9evRQVFaUpU6ZI+vNMRW5WrFihjh07qmHDhnrllVfkcrk0ZcoU9ejRQ/PmzVOfPn18+t92223q1q2b91hx//336+abb/aun5xMmTJF8+bN06RJkzRjxgzVqVNH5cuXlySlpqbqoYceUr9+/ZSamqojR44oOTlZLVu21Lp163TxxRd7lxPoei2I/N5v6c9Am5SUpP379+uhhx5Sw4YNtXXrVo0fP16bN2/WsmXLfMJKTvvYG2+8oaFDh+ruu+/WU089pVKlSmnnzp369ttvC117Yd4LSfr444/Vo0cPJSYm6plnnlHVqlW1e/duLV26tNC1nO2JJ55QcnKyxo4dqzZt2sjj8Wjbtm3eyx633Xabjh49queee04LFixQxYoVJUl169aVJD366KMaO3asdx87ffq0nnzySV155ZX66quvvP2kwLaJLVu2KDExUUFBvr/uGzZs6P15q1atrKwDL3OemzFjhpFk1q5dazwejzl+/Lj56KOPTIUKFUybNm2Mx+Px9q1Tp45p0qSJT5sxxnTv3t1UrFjRZGZm+izzuuuu8+n3xRdfGElm0qRJ3raBAweaatWq5Vpf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X6/bbrtNN954o/bt26cxY8aocuXK3ssQOenYsaOCg4PVr18/PfDAAzp16pSmTp3q90FdZcqU0dNPP63bbrtNV111lW6//XZddNFF2rlzpzZu3Kjnn39ekgpc89ixY7Vo0SK1b99e48ePV1hYmF544YV870OwZcKECVq8eLHatWun8ePHKzo6WnPmzNEHH3ygJ554QlFRUZKk4cOH69VXX1W3bt00adIk75MJ27Zt81s/zz33nAYOHKijR4+qV69eiouL06+//qqNGzfq119/1dSpU3Otp3v37lqwYIGGDh2qXr16ad++fXr44YdVsWLFAn8i65gxY/T++++rQ4cOGjNmjEJDQzVt2jTvOi1Vyk7ujoyMVJs2bfTkk08qNjZWCQkJWrFihV555RW/p4/S0tKUmpqqcePGeX/BpKamauTIkWrbtq2uu+66XMcp6LrPyfjx47V//3516NBBVapU0bFjx/Tss8/K6XQqKSlJ0p+ffREaGqo5c+YoMTFRZcqUUaVKlbyXDwIVGxur9u3ba9y4cd6nQrZt2+bzyGnXrl0VHR2tIUOGaOLEiQoKCtLMmTO1b98+v+U1aNBAb7zxhubPn68aNWooJCREDRo0yHHs1NRUdezYUe3atdPIkSMVHBysKVOmaMuWLZo3b16RXHfOVrZsWY0bN04PPfSQbrnlFvXr109HjhxRSkqKQkJCNGHChEIvu0+fPho/frz69u2r+++/X6dOndJ///tfvwBbkPd7+PDheuedd9SmTRvde++9atiwobKysrR3714tXbpU9913X76/lG6//XaFhoaqdevWqlixog4dOqTU1FRFRUV57/P4u7zwwgvq0aOHWrRooXvvvVdVq1bV3r179fHHH/v9kXm2AQMG6Oabb9bQoUN1ww03aM+ePXriiSe8Z0Gy9ejRw/t5S+XLl9eePXs0efJkVatWzfuUT/b2+Oyzz2rgwIFyOp265JJLlJCQoIkTJ2rMmDH68ccfvfcR/vzzz/rqq68UHh6ulJSUQr3uLl26qGPHjvrXv/6ljIwM1apVS/PmzdNHH32k2bNnW/8MC0kl56mQc+9MNsaYP/74w1StWtVcfPHF5syZM8YYYzZu3Gh69+5t4uLijNPpNBUqVDDt27c306ZN81vm0qVLzYABA0zZsmW9d2nv2LHDZ4yc7rJ+//33TaNGjUxISIipXLmy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AAAAawgWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAa/5SsEhNTZXD4dDw4cMtlQMAAEqyQgeLdevW6aWXXlLDhg1t1gMAAEqwQgWL33//XTfddJNefvlllStXznZNAACghCpUsBg2bJi6deumq666ynY9AACgBAsKdIY33nhD//vf/7Ru3boC9Xe73XK73d7pjIwMSZLH45HH4wl0eADnsex92lXKFHMlgeFYBOSvoPtJQMFi3759+ve//62lS5cqJCSkQPOkpqYqJSXFr33p0qUKCwsLZHgAJcTDTbOKu4SALFmypLhLAM57J0+eLFA/hzGmwH9aLFy4UNddd51Kly7tbcvMzJTD4VCpUqXkdrt9fiblfMYiPj5ehw8fVmRkZEGHBlACeDwepaWladz6UnJnOYq7nALbkty5uEsAznsZGRmKjY1Venp6nr+/Azpj0aFDB23evNmnbfDgwapTp45GjRrlFyokyeVyyeVy+bU7nU45nc5AhgdQQrizHHJnlpxgwbEIyF9B95OAgkVERITq16/v0xYeHq6YmBi/dgAA8M/DJ28CAABrAn4q5FzLly+3UAYAALgQcMYCAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWBNQsJg6daoaNmyoyMhIRUZGqmXLlvrwww+LqjYAAFDCBBQsqlSposcee0zr16/X+vXr1b59e/Xs2VNbt24tqvoAAEAJEhRI5x49evhMP/LII5o6darWrl2revXqWS0MAACUPAEFi7NlZmbqrbfe0okTJ9SyZUubNQEAgBIq4GCxefNmtWzZUqdOnVKZMmX07rvvqm7durn2d7vdcrvd3umMjAxJksfjkcfjKUTJAM5X2fu0q5Qp5koCw7EIyF9B9xOHMSagI8Dp06e1d+9eHTt2TO+8846mT5+uFStW5BoukpOTlZKS4tc+d+5chYWFBTI0AAAoJidPnlT//v2Vnp6uyMjIXPsFHCzOddVVV6lmzZp68cUXc/x5Tmcs4uPjdfjw4TwLA1DyeDwepaWladz6UnJnOYq7nALbkty5uEsAznsZGRmKjY3NN1gU+h6LbMYYn+BwLpfLJZfL5dfudDrldDr/6vAAzkPuLIfcmSUnWHAsAvJX0P0koGDx0EMPqUuXLoqPj9fx48f1xhtvaPny5froo48KVSQAALiwBBQsfv75Zw0YMEAHDx5UVFSUGjZsqI8++kgdO3YsqvoAAEAJElCweOWVV4qqDgAAcAHgu0IAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQEFi9TUVDVr1kwRERGKi4vTtddeq++//76oagMAACVMQMFixYoVGjZsmNauXau0tDSdOXNGnTp10okTJ4qqPgAAUIIEBdL5o48+8pmeMWOG4uLi9PXXX6tNmzZWCwMAACXPX7rHIj09XZIUHR1tpRgAAFCyBXTG4mzGGI0YMUJXXHGF6tevn2s/t9stt9vtnc7IyJAkeTweeTyewg4P4DyUvU+7SpliriQwHIuA/BV0Pyl0sLjrrru0adMmrVq1Ks9+qampSklJ8WtfunSpwsLCCjs8gPPYw02ziruEgCxZsqS4SwDOeydPnixQP4cxJuA/Le6++24tXLhQn3/+uapXr55n35zOWMTHx+vw4cOKjIwMdGgA5zGPx6O0tDSNW19K7ixHcZdTYFuSOxd3CcB5LyMjQ7GxsUpPT8/z93dAZyyMMbr77rv17rvvavny5fmGCklyuVxyuVx+7U6nU06nM5DhAZQQ7iyH3JklJ1hwLALyV9D9JKBgMWzYMM2dO1fvvfeeIiIidOjQIUlSVFSUQkNDA68SAABcUAJ6KmTq1KlKT09X27ZtVbFiRe+/+fPnF1V9AACgBAn4UggAAEBu+K4QAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYE3AweLzzz9Xjx49VKlSJTkcDi1cuLAIygIAACVRwMHixIkTatSokZ5//vmiqAcAAJRgQYHO0KVLF3Xp0qUoagEAACUc91gAAABrAj5jESi32y232+2dzsjIkCR5PB55PJ6iHh7A3yh7n3aVMsVcSWA4FgH5K+h+UuTBIjU1VSkpKX7tS5cuVVhYWFEPD6AYPNw0q7hLCMiSJUuKuwTgvHfy5MkC9XMYYwr9p4XD4dC7776ra6+9Ntc+OZ2xiI+P1+HDhxUZGVnYoQGchzwej9LS0jRufSm5sxzFXU6BbUnuXNwlAOe9jIwMxcbGKj09Pc/f30V+xsLlcsnlcvm1O51OOZ3Ooh4eQDFwZznkziw5wYJjEZC/gu4nAQeL33//XTt37vRO79q1Sxs2bFB0dLSqVq0a6OIAAMAFJOBgsX79erVr1847PWLECEnSwIEDNXPmTGuFAQCAkifgYNG2bVv9hdsyAADABYzPsQAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWFCpYTJkyRdWrV1dISIguu+wyrVy50nZdAACgBAo4WMyfP1/Dhw/XmDFj9M033+jKK69Uly5dtHfv3qKoDwAAlCABB4tnnnlGQ4YM0W233abExERNnjxZ8fHxmjp1alHUBwAASpCAgsXp06f19ddfq1OnTj7tnTp10urVq60WBgAASp6gQDofPnxYmZmZuuiii3zaL7roIh06dCjHedxut9xut3c6PT1dknT06FF5PJ5A6wVwHvN4PDp58qSCPKWUmeUo7nIK7MiRI8VdAnDeO378uCTJGJNnv4CCRTaHw/eAYYzxa8uWmpqqlJQUv/bq1asXZmgAsC726eKuACg5jh8/rqioqFx/HlCwiI2NVenSpf3OTvzyyy9+ZzGyjR49WiNGjPBOZ2Vl6ejRo4qJick1jAAomTIyMhQfH699+/YpMjKyuMsBYJExRsePH1elSpXy7BdQsAgODtZll12mtLQ0XXfddd72tLQ09ezZM8d5XC6XXC6XT1vZsmUDGRZACRMZGUmwAC5AeZ2pyBbwpZARI0ZowIABatq0qVq2bKmXXnpJe/fu1Z133lmoIgEAwIUj4GDRp08fHTlyRBMnTtTBgwdVv359LVmyRNWqVSuK+gAAQAniMPnd3gkABeR2u5WamqrRo0f7XQIF8M9AsAAAANbwJWQAAMAaggUAALCGYAEAAKwhWADws3z5cjkcDh07dqy4SwFQwhAsAACANQQLAABgDcECuAAlJCRo8uTJPm2NGzdWcnKypD+/SHD69Om67rrrFBYWposvvliLFi3KdXl//PGHunXrphYtWujo0aPavXu3HA6HFixYoHbt2iksLEyNGjXSmjVrfOZ75513VK9ePblcLiUkJOjpp//v276ee+45NWjQwDu9cOFCORwOvfDCC962zp07a/To0ZKk5ORkNW7cWK+//roSEhIUFRWlvn37er9xEcD5gWAB/EOlpKSod+/e2rRpk7p27aqbbrpJR48e9euXnp6uTp066fTp0/rkk08UHR3t/dmYMWM0cuRIbdiwQbVr11a/fv105swZSdLXX3+t3r17q2/fvtq8ebOSk5M1btw4zZw5U5LUtm1bbd26VYcPH5YkrVixQrGxsVqxYoUk6cyZM1q9erWSkpK84/3www9auHChFi9erMWLF2vFihV67LHHimoVASgEggXwDzVo0CD169dPtWrV0qOPPqoTJ07oq6++8unz888/KykpSXFxcfrggw8UHh7u8/ORI0eqW7duql27tlJSUrRnzx7t3LlTkvTMM8+oQ4cOGjdunGrXrq1Bgwbprrvu0pNPPilJql+/vmJiYrxBYvny5brvvvu80+vWrdOpU6d0xRVXeMfLysrSzJkzVb9+fV155ZUaMGCAPvnkkyJbRwACR7AA/qEaNmzo/X94eLgiIiL0yy+/+PS56qqrVKNGDb355psKDg7OcxkVK1aUJO8yvvvuO7Vu3dqnf+vWrbVjxw5lZmbK4XCoTZs2Wr58uY4dO6atW7fqzjvvVGZmpr777jstX75cl156qcqUKeOdPyEhQRERET5jnlszgOJFsAAuQKVKldK5n9bv8Xh8pp1Op8+0w+FQVlaWT1u3bt20cuVKffvttzmOc/YyHA6HJHmXYYzxtmU7t6a2bdtq+fLlWrlypRo1aqSyZcuqTZs2WrFihZYvX662bdsGXDOA4kWwAC5A5cuX18GDB73TGRkZ2rVrV8DLeeyxxzRw4EB16NAh13CRm7p162rVqlU+batXr1bt2rVVunRpSf93n8Xbb7/tDRFJSUlatmyZ3/0VAEoGggVwAWrfvr1ef/11rVy5Ulu2bNHAgQO9v8wD9dRTT+mmm25S+/bttW3btgLPd9999+mTTz7Rww8/rO3bt2vWrFl6/vnnNXLkSG+f7Pss5syZ4w0Wbdu21cKFC/XHH3/43F8BoGQIKu4CANg3evRo/fjjj+revbuioqL08MMPF+qMRbb//Oc/yszMVPv27bV8+fIc77c416WXXqo333xT48eP18MPP6yKFStq4sSJGjRokLePw+FQUlKSFi5cqCuvvFLSn/dtREVFqUaNGoqMjCx0zQCKB1+bDgAArOFSCAAAsIZgAQAArCFYAAAAawgWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggXwD+VwOPL8d/YnZP7dEhISNHny5GIbH0Dh8ZHewD/U2V9SNn/+fI0fP17ff/+9ty00NDSg5Z0+fbpAH/UN4MLGGQvgH6pChQref1FRUXI4HN5pp9OpO++8U1WqVFFYWJgaNGigefPm+czftm1b3XXXXRoxYoRiY2PVsWNHSdKiRYt08cUXKzQ0VO3atdOsWbPkcDh07Ngx77yrV69WmzZtFBoaqvj4eN1zzz06ceKEd7l79uzRvffe6z17AqDkIFgA8HPq1ClddtllWrx4sbZs2aL/9//+nwYMGKAvv/zSp9+sWbMUFBSkL774Qi+++KJ2796tXr166dprr9WGDRt0xx13aMyYMT7zbN68WZ07d9b111+vTZs2af78+Vq1apXuuusuSdKCBQtUpUoVTZw4UQcPHvQ5swLg/MeXkAHQzJkzNXz4cJ+zCufq1q2bEhMT9dRTT0n688xCenq6vvnmG2+fBx98UB988IE2b97sbRs7dqweeeQR/fbbbypbtqxuueUWhYaG6sUXX/T2WbVqlZKSknTixAmFhIQoISFBw4cP1/Dhw62/VgBFi3ssAPjJzMzUY489pvnz5+unn36S2+2W2+1WeHi4T7+mTZv6TH///fdq1qyZT9vll1/uM/31119r586dmjNnjrfNGKOsrCzt2rVLiYmJll8NgL8TwQKAn6efflr/+c9/NHnyZDVo0EDh4eEaPny4Tp8+7dPv3KBhjPG7J+Lck6JZWVm64447dM899/iNW7VqVUuvAEBxIVgA8LNy5Ur17NlTN998s6Q/w8COHTvyPZtQp04dLVmyxKdt/fr1PtOXXnqptm7dqlq1auW6nODgYGVmZhayegDFiZs3AfipVauW0tLStHr1an333Xe64447dOjQoXznu+OOO7Rt2zaNGjVK27dv15tvvqmZM2dKkvdMxqhRo7RmzRoNGzZMGzZs0I4dO7Ro0SLdfffd3uUkJCTo888/108//aTDhw8XyWsEUDQIFgD8jBs3Tpdeeqk6d+6stm3bqkKFCrr22mvzna969ep6++23tWDBAjVs2FBTp071PhXicrkkSQ0bNtSKFSu0Y8cOXXnllWrSpInGjRunihUrepczceJE7d69WzVr1lT58uWL5DUCKBo8FQKgSD3yyCOaNm2a9u3bV9ylAPgbcI8FAKumTJmiZs2aKSYmRl988YWefPJJ72dUALjwESwAWLVjxw5NmjRJR48eVdWqVXXfffdp9OjRxV0WgL8Jl0IAAIA13LwJAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArPn/eYRvP2HTV5MAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# After clustering, we would like to see what the replaced mode argmax distribution in each cluster is.\n", "\n", @@ -297,7 +562,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "f2e8e117", "metadata": {}, "outputs": [], @@ -314,7 +579,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "99369dba", "metadata": {}, "outputs": [], @@ -324,7 +589,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "6cca3671", "metadata": {}, "outputs": [], @@ -345,7 +610,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "18093734", "metadata": {}, "outputs": [], @@ -358,10 +623,200 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "id": "8001a140", "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", + "
pct_trips_unknownpct_trips_cardistance_unknowndistance_carduration_carduration_unknown
0600d3df-c1aa-4ca2-83f2-1f6b8931280d1.00.00.1669780.00.00.031289
44eda4da-9223-4bb0-afd4-e7dd19fc6b271.00.00.3763080.00.00.362037
4c5436e9-4840-4872-9e8f-5d46ba81fe521.00.00.0000000.00.00.000000
7479810c-c602-4508-8ae2-da0bed87558d1.00.00.8021320.00.00.447344
7f7c9d3b-84ed-4c14-be8a-aa256daaed011.00.00.2093200.00.00.172709
892088f9-4a27-4f39-91fb-0f5e48d189821.00.00.9825190.00.00.705049
993af3be-5011-44ad-b9cd-d4df7f0e67ad1.00.00.6593890.00.01.000000
c8158323-957d-43c7-bde6-193b99ee72b51.00.00.1004480.00.00.030035
cbed6b7b-555d-43a0-aadc-4a42540a024e1.00.00.3736100.00.00.228214
de83c290-7708-4f8b-8ca3-656072164ef60.01.00.5359491.01.00.700681
f3b93934-09ca-4b90-9089-51b5777bb9e71.00.01.0000000.00.00.740508
f8260067-8ba9-44ea-9c39-cd3e1bd003dd1.00.00.2326130.00.00.250613
\n", + "
" + ], + "text/plain": [ + " pct_trips_unknown pct_trips_car \\\n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 1.0 0.0 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 1.0 0.0 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 1.0 0.0 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 1.0 0.0 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 1.0 0.0 \n", + "892088f9-4a27-4f39-91fb-0f5e48d18982 1.0 0.0 \n", + "993af3be-5011-44ad-b9cd-d4df7f0e67ad 1.0 0.0 \n", + "c8158323-957d-43c7-bde6-193b99ee72b5 1.0 0.0 \n", + "cbed6b7b-555d-43a0-aadc-4a42540a024e 1.0 0.0 \n", + "de83c290-7708-4f8b-8ca3-656072164ef6 0.0 1.0 \n", + "f3b93934-09ca-4b90-9089-51b5777bb9e7 1.0 0.0 \n", + "f8260067-8ba9-44ea-9c39-cd3e1bd003dd 1.0 0.0 \n", + "\n", + " distance_unknown distance_car \\\n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.166978 0.0 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.376308 0.0 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 0.0 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.802132 0.0 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.209320 0.0 \n", + "892088f9-4a27-4f39-91fb-0f5e48d18982 0.982519 0.0 \n", + "993af3be-5011-44ad-b9cd-d4df7f0e67ad 0.659389 0.0 \n", + "c8158323-957d-43c7-bde6-193b99ee72b5 0.100448 0.0 \n", + "cbed6b7b-555d-43a0-aadc-4a42540a024e 0.373610 0.0 \n", + "de83c290-7708-4f8b-8ca3-656072164ef6 0.535949 1.0 \n", + "f3b93934-09ca-4b90-9089-51b5777bb9e7 1.000000 0.0 \n", + "f8260067-8ba9-44ea-9c39-cd3e1bd003dd 0.232613 0.0 \n", + "\n", + " duration_car duration_unknown \n", + "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.0 0.031289 \n", + "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.0 0.362037 \n", + "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.0 0.000000 \n", + "7479810c-c602-4508-8ae2-da0bed87558d 0.0 0.447344 \n", + "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.0 0.172709 \n", + "892088f9-4a27-4f39-91fb-0f5e48d18982 0.0 0.705049 \n", + "993af3be-5011-44ad-b9cd-d4df7f0e67ad 0.0 1.000000 \n", + "c8158323-957d-43c7-bde6-193b99ee72b5 0.0 0.030035 \n", + "cbed6b7b-555d-43a0-aadc-4a42540a024e 0.0 0.228214 \n", + "de83c290-7708-4f8b-8ca3-656072164ef6 1.0 0.700681 \n", + "f3b93934-09ca-4b90-9089-51b5777bb9e7 0.0 0.740508 \n", + "f8260067-8ba9-44ea-9c39-cd3e1bd003dd 0.0 0.250613 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "target_df = user_target_pct.merge(right=target_distance, left_index=True, right_index=True).merge(\n", " right=target_duration, left_index=True, right_index=True\n", @@ -378,47 +833,66 @@ "display(target_df)" ] }, + { + "cell_type": "markdown", + "id": "eba4f246", + "metadata": {}, + "source": [ + "### Uncomment if you want to find the best eps" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "31fecc00", "metadata": {}, "outputs": [], "source": [ - "epsilons = np.linspace(5e-3, 1., 1500)\n", - "best_score = -np.inf\n", - "best_eps = None\n", - "best_n = None\n", - "# alpha = 0.7\n", - "beta = 0.05\n", - "\n", - "for eps in epsilons:\n", - " for n in range(2, 30):\n", - " labels = DBSCAN(eps=eps, min_samples=n).fit(target_df).labels_\n", + "# epsilons = np.linspace(5e-3, 1., 1500)\n", + "# best_score = -np.inf\n", + "# best_eps = None\n", + "# best_n = None\n", + "# # alpha = 0.7\n", + "# beta = 0.05\n", + "\n", + "# for eps in epsilons:\n", + "# for n in range(2, 30):\n", + "# labels = DBSCAN(eps=eps, min_samples=n).fit(target_df).labels_\n", " \n", - " n_unique = np.unique(labels)\n", - " n_outliers = len(labels[labels == -1])\n", + "# n_unique = np.unique(labels)\n", + "# n_outliers = len(labels[labels == -1])\n", " \n", - " if n_outliers == len(labels) or len(n_unique) < 2:\n", - " continue\n", + "# if n_outliers == len(labels) or len(n_unique) < 2:\n", + "# continue\n", " \n", - " # Encourage more clustering and discourage more outliers.\n", - " score = silhouette_score(target_df, labels) + (len(labels) - n_outliers)/n_outliers\n", + "# # Encourage more clustering and discourage more outliers.\n", + "# score = silhouette_score(target_df, labels) + (len(labels) - n_outliers)/n_outliers\n", " \n", - " if score > best_score:\n", - " best_score = score\n", - " best_eps = eps\n", - " best_n = n\n", + "# if score > best_score:\n", + "# best_score = score\n", + "# best_eps = eps\n", + "# best_n = n\n", "\n", - "print(f\"{best_score=}, {best_n=}, {best_eps=}\")" + "# print(f\"{best_score=}, {best_n=}, {best_eps=}\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "id": "e39b41ba", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Counter({0: 11, -1: 1})" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# 0.35 is a good value\n", "\n", @@ -428,7 +902,7 @@ "masscec: min_samples=2, eps=0.986724482988659\n", "'''\n", "\n", - "cl2 = DBSCAN(eps=best_eps, min_samples=2).fit(target_df)\n", + "cl2 = DBSCAN(eps=0.6, min_samples=2).fit(target_df)\n", "# cl2 = KMeans(n_clusters=5).fit(target_df)\n", "\n", "Counter(cl2.labels_)" @@ -436,10 +910,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "1dbf8763", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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v//7v/U/f/HFF9q6datSU1PVtWtX3jsRFOxrw/smikT2YjbY2ZNPPmm6detmEhISzODBg837779fP3fDDTeYH/zgBw3Wv/fee2bQoEEmISHBdO/e3SxYsCDMie0lmNfn4YcfNj179jSJiYmmQ4cO5nvf+57585//HIHUrd/Jy7G/+7jhhhuMMbx3IinY14b3TfSwjPm/M+kAAABsiHOGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAOAMWJal119/PdIxAJwByhCAkJo4caJGjx592tsvWrRIKSkpIcvzbYFmmzhxoizLkmVZio+PV2Zmpn74wx/qhRdekM/na7C2tLRUo0aNCnnWkpISXXXVVUpKSlJ6erpuvfVW1dTUhPz3AKAMAYBfI0eOVGlpqXbt2qW33npLF198sW677TZdeeWVqqurq1/XsWNHuVyukP5ur9erK664QkeOHNG6dev0xz/+UcuWLdPtt98e0t8D4ATKEICweuyxxzRgwAAlJSUpKytLP//5z1VVVSVJeu+99zRp0iR5PJ76PTOzZ8+WJNXU1OjOO+9Uly5dlJSUpKFDh+q9996rf96Te5Tefvtt9e3bV+3atasvNJI0e/Zsvfjii3rjjTfqn/vb23+Xy+VSx44d1aVLFw0ePFh333233njjDb311ltatGhR/bpvHybbtWuXLMvSq6++quHDh6tNmzb6l3/5F3322Wf661//qiFDhtTn+vrrr5v83e+88462b9+ul19+WYMGDdJll12mRx99VM8++6wqKytP6787gKZRhgCElcPh0BNPPKG//e1vevHFF7Vq1SrdeeedkqS8vDzNmzdPycnJKi0tVWlpqWbMmCFJmjRpkj744AP98Y9/1LZt2/TjH/9YI0eO1Oeff17/3EePHtUjjzyil156SWvWrFFJSUn99jNmzNCYMWPqC1Jpaany8vKCyn7JJZdo4MCBWr58ebPr7r//ft1777366KOPFBcXp+uuu0533nmnHn/8ca1du1Y7d+7Ufffd1+T2GzZsUP/+/dW5c+f6sREjRqi6ulqbN28OKjOAU4uLdAAA9jJ16tT6f2dnZ+uBBx7Qz372M82fP18JCQlyu92yLEsdO3asX7dz50698sor+uqrr+oLwowZM7Ry5UotXLhQDz30kCSptrZWTz31lHr27ClJmjJliubOnStJateundq0aaPq6uoGzx2sPn36aNu2bc2umTFjhkaMGCFJuu2223Tdddfp3Xff1UUXXSRJuummmxrsXfqusrIyZWZmNhjr0KGDEhISVFZWdtrZAfhHGQIQVqtXr9ZDDz2k7du3q7KyUnV1dTp+/LiOHDmipKQkv9t89NFHMsbo3HPPbTBeXV2ttLS0+p/btm1bX4QkqVOnTiovLw9pfmOMLMtqds35559f/++TpWbAgAENxk6Vy9/vCOR3AwgeZQhA2Hz55Ze6/PLLVVhYqAceeECpqalat26dbrrpJtXW1ja5nc/nk9Pp1ObNm+V0OhvMtWvXrv7f8fHxDeYsy5IxJqR/w44dO5Sdnd3smm/nOFlevjv23avSvq1jx47auHFjg7GDBw+qtra20R4jAGeOMgQgbDZt2qS6ujo9+uijcjhOnLL46quvNliTkJAgr9fbYGzQoEHyer0qLy/X8OHDT/v3+3vuYKxatUqffPKJpk2bdtrPEYjc3Fz9+te/VmlpqTp16iTpxEnVLpdLOTk5Lfq7ATuiDAEIOY/Ho61btzYYS01NVc+ePVVXV6ff/e53uuqqq/TBBx/oqaeearCue/fuqqqq0rvvvquBAweqbdu2Ovfcc3X99ddrwoQJevTRRzVo0CBVVFRo1apVGjBggC6//PKAcnXv3l1vv/22Pv30U6Wlpcntdjfam3RSdXW1ysrK5PV6tW/fPq1cuVJFRUW68sorNWHChNP67xKo/Px8nXfeeSooKNBvf/tbHThwQDNmzNDkyZOVnJzcor8bsCOuJgMQcu+9954GDRrU4HHffffpggsu0GOPPaaHH35Y/fv315IlS1RUVNRg27y8PBUWFmrs2LE666yz9Jvf/EaStHDhQk2YMEG33367evfurauvvlobN25UVlZWwLkmT56s3r17a8iQITrrrLP0wQcfNLl25cqV6tSpk7p3766RI0dq9erVeuKJJ/TGG280OlQXak6nU3/+85+VmJioiy66SGPGjNHo0aP1yCOPtOjvBezKMqE+oA4AABBD2DMEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABs7f8Di5ufrJdoRg0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "from sklearn.decomposition import PCA\n", "\n", @@ -454,17 +939,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "id": "1e444316", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['duration', 'distance', 'start:hour', 'end:hour', 'user_id', 'target', 'section_mode_argmax', 'section_distance_argmax', 'section_duration_argmax', 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', 'income_category', 'available_modes', 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', 'highest_education_high_school_graduate_or_ged', 'highest_education_prefer_not_to_say', 'highest_education_some_college_or_associates_degree', 'primary_job_description_Clerical or administrative support', 'primary_job_description_Other', 'gender_man', 'gender_woman', 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', 'av_ridehail', 'av_p_micro', 'av_walk', 'av_transit', 'av_car', 'av_s_micro', 'av_s_car', 'av_unknown', 'av_no_trip', 'cost_ridehail', 'cost_p_micro', 'cost_walk', 'cost_transit', 'cost_car', 'cost_s_micro', 'cost_s_car', 'cost_unknown', 'cost_no_trip', 'mph']\n" + ] + } + ], "source": [ "print(df.columns.tolist())" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "id": "f0bc09b9", "metadata": {}, "outputs": [], @@ -479,57 +972,119 @@ "\n", "\n", "demographic_cols = {\n", - " 'Stage_database': [\n", - " 'has_drivers_license', 'is_student', 'is_paid', \n", - " 'income_category', 'n_residence_members', 'n_residents_u18', 'n_residents_with_license', \n", - " 'n_motor_vehicles', 'has_medical_condition', 'ft_job', 'multiple_jobs', \n", - " 'n_working_residents', \"highest_education_Bachelor's degree\", \n", - " 'highest_education_Graduate degree or professional degree', \n", - " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", - " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", - " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", - " 'primary_job_description_Education', 'primary_job_description_Food service', \n", - " 'primary_job_description_Linecook', \n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", - " 'primary_job_description_Medical/healthcare', 'primary_job_description_Non-profit program manager', \n", - " 'primary_job_description_Other', 'primary_job_description_Professional, managerial, or technical', \n", - " 'primary_job_description_Sales or service', 'primary_job_description_Self employed', \n", - " 'primary_job_description_food service', 'gender_Man', 'gender_Nonbinary/genderqueer/genderfluid', \n", - " 'gender_Prefer not to say', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", - " 'av_transit', 'av_no_trip', 'av_p_micro', 'av_s_micro', 'av_ridehail', 'av_unknown', 'av_walk', 'av_car', \n", - " 'av_s_car'\n", - " ] + [c for c in df.columns if 'age' in c],\n", - " 'durham': [\n", - " 'is_student', 'is_paid', 'has_drivers_license', \n", - " 'n_residents_u18', 'n_residence_members', 'income_category',\n", - " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition', \n", - " 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", - " 'highest_education_graduate_degree_or_professional_degree', \n", - " 'highest_education_high_school_graduate_or_ged', 'highest_education_less_than_a_high_school_graduate', \n", - " 'highest_education_some_college_or_associates_degree', \n", - " 'primary_job_description_Clerical or administrative support', \n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", - " 'primary_job_description_Other', 'primary_job_description_Professional, Manegerial, or Technical', \n", - " 'primary_job_description_Sales or service', 'gender_man', \n", - " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman', \n", - " 'av_walk', 'av_unknown', 'av_no_trip', 'av_p_micro', 'av_transit', 'av_car', 'av_ridehail', \n", - " 'av_s_micro', 'av_s_car'\n", - " ] + [c for c in df.columns if 'age' in c],\n", - " 'masscec': [\n", - " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', \n", - " 'income_category', 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', \n", - " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", - " 'highest_education_graduate_degree_or_professional_degree', \n", - " 'highest_education_high_school_graduate_or_ged', 'highest_education_less_than_a_high_school_graduate', \n", - " 'highest_education_prefer_not_to_say', 'highest_education_some_college_or_associates_degree', \n", - " 'primary_job_description_Clerical or administrative support', \n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", - " 'primary_job_description_Other', 'primary_job_description_Prefer not to say', \n", - " 'primary_job_description_Professional, Manegerial, or Technical', \n", - " 'primary_job_description_Sales or service', 'gender_man', 'gender_prefer_not_to_say', 'gender_woman', \n", - " 'av_p_micro', 'av_s_car', 'av_s_micro', 'av_transit', 'av_car', 'av_no_trip', 'av_unknown', \n", - " 'av_ridehail', 'av_walk'\n", - " ] + [c for c in df.columns if 'age' in c],\n", + " 'allceo': [\n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category',\n", + " 'n_residence_members', 'n_residents_u18', 'n_residents_with_license',\n", + " 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs', 'n_working_residents',\n", + " \"highest_education_Bachelor's degree\",\n", + " 'highest_education_Graduate degree or professional degree',\n", + " 'highest_education_High school graduate or GED',\n", + " 'highest_education_Less than a high school graduate',\n", + " 'highest_education_Prefer not to say',\n", + " 'highest_education_Some college or associates degree',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Custodial',\n", + " 'primary_job_description_Education',\n", + " 'primary_job_description_Food service',\n", + " 'primary_job_description_Linecook',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Medical/healthcare',\n", + " 'primary_job_description_Non-profit program manager',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, managerial, or technical',\n", + " 'primary_job_description_Sales or service',\n", + " 'primary_job_description_Self employed',\n", + " 'primary_job_description_food service', 'gender_Man',\n", + " 'gender_Nonbinary/genderqueer/genderfluid', 'gender_Prefer not to say',\n", + " 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", + " 'age_16___20_years_old', 'age_21___25_years_old',\n", + " 'age_26___30_years_old', 'age_31___35_years_old',\n", + " 'age_36___40_years_old', 'age_41___45_years_old',\n", + " 'age_46___50_years_old', 'age_51___55_years_old',\n", + " 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old',\n", + " 'av_transit', 'av_no_trip', 'av_p_micro', 'av_s_micro', 'av_ridehail',\n", + " 'av_unknown', 'av_walk', 'av_car', 'av_s_car'\n", + " ],\n", + " 'durham': [\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18',\n", + " 'n_residence_members', 'income_category',\n", + " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles',\n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs',\n", + " 'highest_education_bachelor_s_degree',\n", + " 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_some_college_or_associates_degree',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'primary_job_description_Sales or service', 'gender_man',\n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman',\n", + " 'age_16___20_years_old', 'age_21___25_years_old',\n", + " 'age_26___30_years_old', 'age_31___35_years_old',\n", + " 'age_36___40_years_old', 'age_41___45_years_old',\n", + " 'age_51___55_years_old', 'age_56___60_years_old', 'av_walk',\n", + " 'av_unknown', 'av_no_trip', 'av_p_micro', 'av_transit', 'av_car',\n", + " 'av_ridehail', 'av_s_micro', 'av_s_car'\n", + " ],\n", + " 'nicr': [\n", + " 'is_student', 'is_paid',\n", + " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", + " 'income_category', 'n_residents_with_license',\n", + " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_prefer_not_to_say', 'primary_job_description_Other',\n", + " 'gender_man', 'gender_woman', 'age_16___20_years_old', 'av_p_micro',\n", + " 'av_car', 'av_transit', 'av_ridehail', 'av_no_trip', 'av_s_car',\n", + " 'av_s_micro', 'av_unknown', 'av_walk'\n", + " ],\n", + " 'masscec': [\n", + " 'is_student', 'is_paid',\n", + " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", + " 'income_category', 'n_residents_with_license',\n", + " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree',\n", + " 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_prefer_not_to_say',\n", + " 'highest_education_some_college_or_associates_degree',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Prefer not to say',\n", + " 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'primary_job_description_Sales or service', 'gender_man',\n", + " 'gender_prefer_not_to_say', 'gender_woman', 'age_16___20_years_old',\n", + " 'age_21___25_years_old', 'age_26___30_years_old',\n", + " 'age_31___35_years_old', 'age_36___40_years_old',\n", + " 'age_41___45_years_old', 'age_46___50_years_old',\n", + " 'age_51___55_years_old', 'age_56___60_years_old',\n", + " 'age_61___65_years_old', 'age___65_years_old', 'av_p_micro', 'av_s_car',\n", + " 'av_s_micro', 'av_transit', 'av_car', 'av_no_trip', 'av_unknown',\n", + " 'av_ridehail', 'av_walk'\n", + " ],\n", + " 'ride2own': [\n", + " 'has_drivers_license', 'is_student',\n", + " 'is_paid', 'income_category', 'n_residence_members',\n", + " 'n_working_residents', 'n_residents_u18', 'n_residents_with_license',\n", + " 'n_motor_vehicles', 'has_medical_condition',\n", + " 'ft_job', 'multiple_jobs',\n", + " 'highest_education_bachelor_s_degree',\n", + " 'highest_education_high_school_graduate_or_ged',\n", + " 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_some_college_or_associates_degree',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'gender_man', 'gender_woman', 'age_31___35_years_old',\n", + " 'age_36___40_years_old', 'age_41___45_years_old',\n", + " 'age_51___55_years_old', 'av_no_trip', 'av_s_micro', 'av_transit',\n", + " 'av_car', 'av_ridehail', 'av_p_micro', 'av_s_car', 'av_walk',\n", + " 'av_unknown'\n", + " ]\n", "}\n", "\n", "\n", @@ -540,12 +1095,191 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "id": "5a3c6355", "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For cluster -1:\n" + ] + }, + { + "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", + "
featurech
0is_student-0.0
24av_s_micro-0.0
23av_s_car-0.0
22av_no_trip-0.0
\n", + "
" + ], + "text/plain": [ + " feature ch\n", + "0 is_student -0.0\n", + "24 av_s_micro -0.0\n", + "23 av_s_car -0.0\n", + "22 av_no_trip -0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "image/png": "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AQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAyRV0KbVx48a47rrrolevXlFWVha9e/eOH/3oR7F58+b6Y7Isi5qamqiqqoqysrIYMGBALFy4MI9TAwDklwwFALQFBV1K3XjjjTFx4sSYMGFCvPTSSzF27Nj4yU9+EjfffHP9MWPHjo1x48bFhAkTYu7cuVFZWRkDBw6M1atX53FyAID8kaEAgLagJN8DfJRnnnkmvvrVr8Ypp5wSERH77rtvTJ06NZ577rmI+OATvvHjx8e1114bZ555ZkRE3HXXXVFRURFTpkyJoUOHbvN16+rqoq6urv7+qlWrWvmdAACk0xoZSn4CAFpaQZ8p9cUvfjEee+yxePnllyMi4s9//nPMnj07Tj755IiIWLx4cdTW1sagQYPqn1NaWhr9+/ePOXPmbPd1x4wZE127dq2/9ezZs3XfCABAQq2RoeQnAKClFfSZUldffXWsXLky9t9//2jXrl1s2rQpbrjhhvjWt74VERG1tbUREVFRUdHgeRUVFfHaa69t93VHjhwZl19+ef39VatWCVYAQNFojQwlPwEALa2gS6l77703fvOb38SUKVPioIMOigULFsTw4cOjqqoqzjvvvPrjcrlcg+dlWdZo7cNKS0ujtLS01eYGAMin1shQ8hMA0NIKupS66qqr4pprrolvfvObERFxyCGHxGuvvRZjxoyJ8847LyorKyPig0/7evToUf+85cuXN/rkDwBgRyFDAQBtQUFfU2rt2rWx004NR2zXrl39jzPu1atXVFZWxowZM+ofX79+fcyaNSv69euXdFYAgEIhQwEAbUFBnyl12mmnxQ033BB77713HHTQQTF//vwYN25cfOc734mID045Hz58eIwePTqqq6ujuro6Ro8eHZ06dYrBgwfneXoAgPyQoQCAtqCgS6mbb745fvCDH8SwYcNi+fLlUVVVFUOHDo0f/vCH9ceMGDEi1q1bF8OGDYsVK1bEUUcdFdOnT4/y8vI8Tg4AkD8yFADQFhR0KVVeXh7jx4+P8ePHb/eYXC4XNTU1UVNTk2wuAIBCJkMBAG1BQV9TCgAAAIDipJQCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOQKvpR644034pxzzolu3bpFp06d4vDDD4958+bVP55lWdTU1ERVVVWUlZXFgAEDYuHChXmcGAAg/2QoAKDQFXQptWLFijjmmGOiffv28fDDD8eLL74YP/3pT2OXXXapP2bs2LExbty4mDBhQsydOzcqKytj4MCBsXr16vwNDgCQRzIUANAWlOR7gI9y4403Rs+ePWPSpEn1a/vuu2/9f2dZFuPHj49rr702zjzzzIiIuOuuu6KioiKmTJkSQ4cO3ebr1tXVRV1dXf39VatWtc4bAADIg9bIUPITANDSCvpMqQcffDD69u0b3/jGN2KPPfaIz33uc3H77bfXP7548eKora2NQYMG1a+VlpZG//79Y86cOdt93TFjxkTXrl3rbz179mzV9wEAkFJrZCj5CQBoaQVdSr3yyitx6623RnV1dTz66KNx8cUXx6WXXhr//u//HhERtbW1ERFRUVHR4HkVFRX1j23LyJEjY+XKlfW3pUuXtt6bAABIrDUylPwEALS0gv72vc2bN0ffvn1j9OjRERHxuc99LhYuXBi33nprfPvb364/LpfLNXhelmWN1j6stLQ0SktLW2doAIA8a40MJT8BAC2toM+U6tGjRxx44IEN1g444IBYsmRJRERUVlZGRDT6RG/58uWNPvkDANhRyFAAQFtQ0KXUMcccE4sWLWqw9vLLL8c+++wTERG9evWKysrKmDFjRv3j69evj1mzZkW/fv2SzgoAUChkKACgLSjob9/7/ve/H/369YvRo0fHWWedFX/605/itttui9tuuy0iPjjlfPjw4TF69Oiorq6O6urqGD16dHTq1CkGDx6c5+kBAPJDhgIA2oKCLqWOOOKIuP/++2PkyJHxox/9KHr16hXjx4+PIUOG1B8zYsSIWLduXQwbNixWrFgRRx11VEyfPj3Ky8vzODkAQP7IUABAW1DQpVRExKmnnhqnnnrqdh/P5XJRU1MTNTU16YYCAChwMhQAUOgK+ppSAAAAABSnZpVS7dq1i+XLlzdaf/vtt6Ndu3afeigAgGIkQwEAbNWsUirLsm2u19XVRYcOHT7VQAAAxUqGAgDYqknXlPr5z38eER9cg+BXv/pV7LzzzvWPbdq0KZ588snYf//9W3ZCAIA2ToYCAGisSaXUTTfdFBEffMo3ceLEBqeZd+jQIfbdd9+YOHFiy04IANDGyVAAAI01qZRavHhxREQcf/zxMW3atNh1111bZSgAgGIiQwEANNakUmqLmTNntvQcAABFT4YCANiqWaXUpk2bYvLkyfHYY4/F8uXLY/PmzQ0ef/zxx1tkOACAYiJDAQBs1axS6rLLLovJkyfHKaecEgcffHDkcrmWngsAoOjIUAAAWzWrlLrnnnviP/7jP+Lkk09u6XkAAIqWDAUAsNVOzXlShw4d4jOf+UxLzwIAUNRkKACArZpVSl1xxRXxs5/9LLIsa+l5AACKlgwFALBVs759b/bs2TFz5sx4+OGH46CDDor27ds3eHzatGktMhwAQDGRoQAAtmpWKbXLLrvEGWec0dKzAAAUNRkKAGCrZpVSkyZNauk5AACKngwFALBVs64pFRGxcePG+K//+q/45S9/GatXr46IiDfffDPWrFnTYsMBABQbGQoA4APNOlPqtddeiy9/+cuxZMmSqKuri4EDB0Z5eXmMHTs23n///Zg4cWJLzwkA0ObJUAAAWzXrTKnLLrss+vbtGytWrIiysrL69TPOOCMee+yxFhsOAKCYyFAAAFs1+6fvPf3009GhQ4cG6/vss0+88cYbLTIYAECxkaEAALZq1plSmzdvjk2bNjVaf/3116O8vPxTDwUAUIxkKACArZpVSg0cODDGjx9ffz+Xy8WaNWvi+uuvj5NPPrmlZgMAKCoyFADAVs369r2bbropjj/++DjwwAPj/fffj8GDB8df//rX6N69e0ydOrWlZwQAKAoyFADAVs0qpaqqqmLBggVxzz33xLx582Lz5s1x4YUXxpAhQxpctBMAgK1kKACArZpVSkVElJWVxQUXXBAXXHBBS84DAFDUZCgAgA8065pSY8aMiTvvvLPR+p133hk33njjpx4KAKAYyVAAAFs1q5T65S9/Gfvvv3+j9YMOOigmTpz4qYcCAChGMhQAwFbNKqVqa2ujR48ejdZ33333WLZs2aceCgCgGMlQAABbNauU6tmzZzz99NON1p9++umoqqr61EMBABQjGQoAYKtmXej8oosuiuHDh8eGDRviS1/6UkREPPbYYzFixIi44oorWnRAAIBiIUMBAGzVrFJqxIgR8c4778SwYcNi/fr1ERHRsWPHuPrqq2PkyJEtOiAAQLGQoQAAtmpyKbVp06aYPXt2XH311fGDH/wgXnrppSgrK4vq6uooLS1tjRkBANo8GQoAoKEml1Lt2rWLk046KV566aXo1atXHHHEEa0xFwBAUZGhAAAaataFzg855JB45ZVXWnoWAICiJkMBAGzVrFLqhhtuiCuvvDL+8Ic/xLJly2LVqlUNbgAANCZDAQBs1awLnX/5y1+OiIjTTz89crlc/XqWZZHL5WLTpk0tMx0AQBGRoQAAtmpWKTVz5syWngMAoOjJUAAAWzWrlOrfv39LzwEAUPRkKACArZp1TamIiKeeeirOOeec6NevX7zxxhsREfHrX/86Zs+e3WLDAQAUGxkKAOADzSqlfve738VJJ50UZWVl8fzzz0ddXV1ERKxevTpGjx7dogMCABQLGQoAYKtmlVI//vGPY+LEiXH77bdH+/bt69f79esXzz//fIsNBwBQTGQoAICtmlVKLVq0KI477rhG6126dIl33333084EAFCUZCgAgK2aVUr16NEj/va3vzVanz17dvTu3ftTDwUAUIxkKACArZpVSg0dOjQuu+yyePbZZyOXy8Wbb74Zd999d1x55ZUxbNiwlp4RAKAoyFAAAFuVNOdJI0aMiFWrVsXxxx8f77//fhx33HFRWloaV155ZVxyySUtPSMAQFGQoQAAtmpSKbV27dq46qqr4oEHHogNGzbEaaedFldccUVERBx44IGx8847t8qQAABtmQwFANBYk0qp66+/PiZPnhxDhgyJsrKymDJlSmzevDnuu+++1poPAKDNk6EAABprUik1bdq0uOOOO+Kb3/xmREQMGTIkjjnmmNi0aVO0a9euVQYEAGjrZCgAgMaadKHzpUuXxrHHHlt//8gjj4ySkpJ48803W3wwAIBiIUMBADTWpFJq06ZN0aFDhwZrJSUlsXHjxhYdCgCgmMhQAACNNenb97Isi/PPPz9KS0vr195///24+OKLo3PnzvVr06ZNa7kJAQDaOBkKAKCxJpVS5513XqO1c845p8WGAQAoRjIUAEBjTSqlJk2a1FpzAAAULRkKAKCxJl1TCgAAAABaglIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJNemSqkxY8ZELpeL4cOH169lWRY1NTVRVVUVZWVlMWDAgFi4cGH+hgQAKDAyFABQiNpMKTV37ty47bbb4tBDD22wPnbs2Bg3blxMmDAh5s6dG5WVlTFw4MBYvXp1niYFACgcMhQAUKjaRCm1Zs2aGDJkSNx+++2x66671q9nWRbjx4+Pa6+9Ns4888w4+OCD46677oq1a9fGlClT8jgxAED+yVAAQCFrE6XUd7/73TjllFPixBNPbLC+ePHiqK2tjUGDBtWvlZaWRv/+/WPOnDnbfb26urpYtWpVgxsAQLFpyQwlPwEALa0k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vjjfo7V5paWlcf311zc6XZ/WZ+/zx97nj73PD/u+45KhWo8/V/lh3/PH3uePvc8fe//p5bKsOH6+8S233BJjx46NZcuWxcEHHxw33XRTHHfccfkeCwCgoMlQAEC+FE0pBQAAAEDb0eavKQUAAABA26OUAgAAACA5pRQAAAAAySmlAAAAAEhOKUXccsst0atXr+jYsWP06dMnnnrqqY88vq6uLq699trYZ599orS0NP7lX/4l7rzzzkTTFpem7v3dd98dhx12WHTq1Cl69OgRF1xwQbz99tuJpi0OTz75ZJx22mlRVVUVuVwuHnjggY99zqxZs6JPnz7RsWPH6N27d0ycOLH1By1CTd37adOmxcCBA2P33XePLl26xNFHHx2PPvpommGLTHN+32/x9NNPR0lJSRx++OGtNh+0RfJT/shP+SFD5Y8MlR/yUxpKqR3cvffeG8OHD49rr7025s+fH8cee2x85StfiSVLlmz3OWeddVY89thjcccdd8SiRYti6tSpsf/++yecujg0de9nz54d3/72t+PCCy+MhQsXxn333Rdz586Niy66KPHkbdt7770Xhx12WEyYMOETHb948eI4+eST49hjj4358+fHv/3bv8Wll14av/vd71p50uLT1L1/8sknY+DAgfHQQw/FvHnz4vjjj4/TTjst5s+f38qTFp+m7v0WK1eujG9/+9txwgkntNJk0DbJT/kjP+WPDJU/MlR+yE+JZOzQjjzyyOziiy9usLb//vtn11xzzTaPf/jhh7OuXbtmb7/9dorxilpT9/4nP/lJ1rt37wZrP//5z7O99tqr1WYsdhGR3X///R95zIgRI7L999+/wdrQoUOzL3zhC604WfH7JHu/LQceeGA2atSolh9oB9KUvT/77LOz6667Lrv++uuzww47rFXngrZEfsof+akwyFD5I0Plh/zUepwptQNbv359zJs3LwYNGtRgfdCgQTFnzpxtPufBBx+Mvn37xtixY2PPPfeM/fbbL6688spYt25dipGLRnP2vl+/fvH666/HQw89FFmWxf/+7//Gb3/72zjllFNSjLzDeuaZZxr9Op100knx3HPPxYYNG/I01Y5p8+bNsXr16thtt93yPcoOYdKkSfH3v/89rr/++nyPAgVFfsof+altkaEKhwyVjvzUdCX5HoD8eeutt2LTpk1RUVHRYL2ioiJqa2u3+ZxXXnklZs+eHR07doz7778/3nrrrRg2bFi88847rovQBM3Z+379+sXdd98dZ599drz//vuxcePGOP300+Pmm29OMfIOq7a2dpu/Ths3boy33norevTokafJdjw//elP47333ouzzjor36MUvb/+9a9xzTXXxFNPPRUlJaICfJj8lD/yU9siQxUOGSoN+al5nClF5HK5BvezLGu0tsXmzZsjl8vF3XffHUceeWScfPLJMW7cuJg8ebJP+5qhKXv/4osvxqWXXho//OEPY968efHII4/E4sWL4+KLL04x6g5tW79O21qn9UydOjVqamri3nvvjT322CPf4xS1TZs2xeDBg2PUqFGx33775XscKFjyU/7IT22HDJV/MlQa8lPzqe92YN27d4927do1+mRp+fLljT7V2KJHjx6x5557RteuXevXDjjggMiyLF5//fWorq5u1ZmLRXP2fsyYMXHMMcfEVVddFRERhx56aHTu3DmOPfbY+PGPf+zTplZSWVm5zV+nkpKS6NatW56m2rHce++9ceGFF8Z9990XJ554Yr7HKXqrV6+O5557LubPnx+XXHJJRHzwD+osy6KkpCSmT58eX/rSl/I8JeSP/JQ/8lPbIkPlnwyVjvzUfM6U2oF16NAh+vTpEzNmzGiwPmPGjOjXr982n3PMMcfEm2++GWvWrKlfe/nll2OnnXaKvfbaq1XnLSbN2fu1a9fGTjs1/CPbrl27iNj6qRMt7+ijj2706zR9+vTo27dvtG/fPk9T7TimTp0a559/fkyZMsX1PxLp0qVLvPDCC7FgwYL628UXXxyf/exnY8GCBXHUUUfle0TIK/kpf+SntkWGyi8ZKi356VPIx9XVKRz33HNP1r59++yOO+7IXnzxxWz48OFZ586ds1dffTXLsiy75pprsnPPPbf++NWrV2d77bVX9vWvfz1buHBhNmvWrKy6ujq76KKL8vUW2qym7v2kSZOykpKS7JZbbsn+/ve/Z7Nnz8769u2bHXnkkfl6C23S6tWrs/nz52fz58/PIiIbN25cNn/+/Oy1117Lsqzxvr/yyitZp06dsu9///vZiy++mN1xxx1Z+/bts9/+9rf5egttVlP3fsqUKVlJSUn2i1/8Ilu2bFn97d13383XW2izmrr3/8xPj4GG5Kf8kZ/yR4bKHxkqP+SnNJRSZL/4xS+yffbZJ+vQoUP2+c9/Pps1a1b9Y+edd17Wv3//Bse/9NJL2YknnpiVlZVle+21V3b55Zdna9euTTx1cWjq3v/85z/PDjzwwKysrCzr0aNHNmTIkOz1119PPHXbNnPmzCwiGt3OO++8LMu2ve9PPPFE9rnPfS7r0KFDtu+++2a33npr+sGLQFP3vn///h95PJ9cc37ff5hQBY3JT/kjP+WHDJU/MlR+yE9p5LLMeasAAAAApOWaUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgooGAMGDIjhw4fne4xPZPLkybHLLrvkewwAgDbviSeeiFwuF++++26+RwESK8n3AABbTJs2Ldq3b99qr3/++efHu+++Gw888ECrfY1P44knnojjjz8+VqxYofACAHYY/fr1i2XLlkXXrl3zPQqQmFIKKBi77bZbvkcAACCxDh06RGVlZbOfv379+ujQoUMLTgSk4tv3gILx4W/fu+WWW6K6ujo6duwYFRUV8fWvf/0TvcZvf/vbOOSQQ6KsrCy6desWJ554Yrz33ntRU1MTd911V/z+97+PXC4XuVwunnjiiW2eLr5gwYLI5XLx6quv1q9Nnjw59t577+jUqVOcccYZ8fbbbzf62v/5n/8Zffr0iY4dO0bv3r1j1KhRsXHjxvrHc7lc/OpXv4ozzjgjOnXqFNXV1fHggw9GRMSrr74axx9/fERE7LrrrpHL5eL8889v2gYCADuURx55JL74xS/GLrvsEt26dYtTTz01/v73v0dExNFHHx3XXHNNg+P/8Y9/RPv27WPmzJkf+9rNzWIDBgyI733vezF8+PDYddddo6KiIm677bZ477334oILLojy8vL4l3/5l3j44Yfrn7OtPPb0009H//79o1OnTrHrrrvGSSedFCtWrKj/Gpdccklcfvnl0b179xg4cGBERMyaNSuOPPLIKC0tjR49esQ111zTIIsBhUcpBRSc5557Li699NL40Y9+FIsWLYpHHnkkjjvuuI993rJly+Jb3/pWfOc734mXXnopnnjiiTjzzDMjy7K48sor46yzzoovf/nLsWzZsli2bFn069fvE83z7LPPxne+850YNmxYLFiwII4//vj48Y9/3OCYRx99NM4555y49NJL48UXX4xf/vKXMXny5LjhhhsaHDdq1Kg466yz4i9/+UucfPLJMWTIkHjnnXeiZ8+e8bvf/S4iIhYtWhTLli2Ln/3sZ59wxwCAHdF7770Xl19+ecydOzcee+yx2GmnneKMM86IzZs3x5AhQ2Lq1KmRZVn98ffee29UVFRE//79P/J1m5vFtrjrrruie/fu8ac//Sm+973vxf/9v/83vvGNb0S/fv3i+eefj5NOOinOPffcWLt27Tafv2DBgjjhhBPioIMOimeeeSZmz54dp512WmzatKnB1ygpKYmnn346fvnLX8Ybb7wRJ598chxxxBHx5z//OW699da44447GmU2oMBkAAWif//+2WWXXZb97ne/y7p06ZKtWrWqSc+fN29eFhHZq6++us3HzzvvvOyrX/1qg7WZM2dmEZGtWLGifm3+/PlZRGSLFy/OsizLvvWtb2Vf/vKXGzzv7LPPzrp27Vp//9hjj81Gjx7d4Jhf//rXWY8ePervR0R23XXX1d9fs2ZNlsvlsocffni7swAAfFLLly/PIiJ74YUXsuXLl2clJSXZk08+Wf/40UcfnV111VUf+zrNzWJZ9kGe++IXv1h/f+PGjVnnzp2zc889t35t2bJlWURkzzzzTJZljTPQt771reyYY475yK9x+OGHN1j7t3/7t+yzn/1stnnz5vq1X/ziF9nOO++cbdq0qcnvA0jDmVJAwRk4cGDss88+0bt37zj33HPj7rvv3u4naR922GGHxQknnBCHHHJIfOMb34jbb7+9/jTvT+Oll16Ko48+usHaP9+fN29e/OhHP4qdd965/vav//qvsWzZsgazH3roofX/3blz5ygvL4/ly5d/6hkBgB3P3//+9xg8eHD07t07unTpEr169YqIiCVLlsTuu+8eAwcOjLvvvjsiIhYvXhzPPPNMDBky5GNft7lZbIsP55127dpFt27d4pBDDqlfq6ioiIjYbgbacqbUR+nbt2+D+1vyWi6Xq1875phjYs2aNfH6669/4tmBtJRSQMEpLy+P559/PqZOnRo9evSIH/7wh3HYYYd97I8JbteuXcyYMSMefvjhOPDAA+Pmm2+Oz372s7F48eLtPmennT7432D2oVPbN2zY0OCYDz+2PZs3b45Ro0bFggUL6m8vvPBC/PWvf42OHTvWH/fPP10wl8vF5s2bP/b1AQD+2WmnnRZvv/123H777fHss8/Gs88+GxEfXPg7ImLIkCHx29/+NjZs2BBTpkyJgw46KA477LCPfd3mZrEttpV3Pry2pTjaXgYqKyv72K/RuXPnBvezLGtQSG1Z+/DXAwqPUgooSCUlJXHiiSfG2LFj4y9/+Uu8+uqr8fjjj3/s83K5XBxzzDExatSomD9/fnTo0CHuv//+iPjgJ7t8+FoEERG77757RHxwPaotFixY0OCYAw88MP74xz82WPvn+5///Odj0aJF8ZnPfKbRbUvx9XG2/NSYf54RAOCfvf322/HSSy/FddddFyeccEIccMABjc4Q/9rXvhbvv/9+PPLIIzFlypQ455xzPvHrNzeLtYRDDz00HnvssSY958ADD4w5c+Y0+DBxzpw5UV5eHnvuuWdLjwi0kJJ8DwDwz/7whz/EK6+8Escdd1zsuuuu8dBDD8XmzZvjs5/97Ec+79lnn43HHnssBg0aFHvssUc8++yz8Y9//CMOOOCAiIjYd99949FHH41FixZFt27domvXrvGZz3wmevbsGTU1NfHjH/84/vrXv8ZPf/rTBq976aWXRr9+/WLs2LHxta99LaZPnx6PPPJIg2N++MMfxqmnnho9e/aMb3zjG7HTTjvFX/7yl3jhhRc+8QU299lnn8jlcvGHP/whTj755CgrK4udd965CTsHAOwodt111+jWrVvcdttt0aNHj1iyZEmjn7bXuXPn+OpXvxo/+MEP4qWXXorBgwd/otdubhZrKSNHjoxDDjkkhg0bFhdffHF06NAhZs6cGd/4xjeie/fu23zOsGHDYvz48fG9730vLrnkkli0aFFcf/31cfnll3/iDwiB9PzpBArOLrvsEtOmTYsvfelLccABB8TEiRNj6tSpcdBBB33k87p06RJPPvlknHzyybHffvvFddddFz/96U/jK1/5SkRE/Ou//mt89rOfjb59+8buu+8eTz/9dLRv3z6mTp0a//M//xOHHXZY3HjjjY1KpC984Qvxq1/9Km6++eY4/PDDY/r06XHdddc1OOakk06KP/zhDzFjxow44ogj4gtf+EKMGzcu9tlnn0/8vvfcc88YNWpUXHPNNVFRURGXXHLJJ34uALBj2WmnneKee+6JefPmxcEHHxzf//734yc/+Umj44YMGRJ//vOf49hjj4299977E712c7NYS9lvv/1i+vTp8ec//zmOPPLIOProo+P3v/99lJRs/5yKPffcMx566KH405/+FIcddlhcfPHFceGFFzbKbEBhyWWf5GIpAAAAANCCnCkFAAAAQHJKKaDNWLJkSey8887bvS1ZsiTfIwIAFLynnnrqIzPV9shiQEvz7XtAm7Fx48Z49dVXt/v4vvvu+5HXGgAAIGLdunXxxhtvbPfxz3zmM9tcl8WAlqaUAgAAACA5374HAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQXEm+BygEmzdvjjfffDPKy8sjl8vlexwAoIBkWRarV6+Oqqqq2Gknn+dtIT8BANvzSfOTUioi3nzzzejZs2e+xwAACtjSpUtjr732yvcYBUN+AgA+zsflJ6VURJSXl0fEB5vVpUuXPE8DABSSVatWRc+ePevzAh+QnwCA7fmk+UkpFVF/ynmXLl2EKgBgm3yLWkPyEwDwcT4uP7kwAgAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJJfXUurJJ5+M0047LaqqqiKXy8UDDzzQ4PEsy6KmpiaqqqqirKwsBgwYEAsXLmxwTF1dXXzve9+L7t27R+fOneP000+P119/PeG7AABIS4YCAIpBXkup9957Lw477LCYMGHCNh8fO3ZsjBs3LiZMmBBz586NysrKGDhwYKxevbr+mOHDh8f9998f99xzT8yePTvWrFkTp556amzatCnV2wAASEqGAgCKQS7LsizfQ0RE5HK5uP/+++NrX/taRHzwCV9VVVUMHz48rr766oj44BO9ioqKuPHGG2Po0KGxcuXK2H333ePXv/51nH322RER8eabb0bPnj3joYceipNOOmmbX6uuri7q6urq769atSp69uwZK1eujC5durTK+1uyZEm89dZbrfLaALCj6969e+y9996t8tqrVq2Krl27tmpO+DRSZSj5CQCKSyHkp5JW+eotYPHixVFbWxuDBg2qXystLY3+/fvHnDlzYujQoTFv3rzYsGFDg2Oqqqri4IMPjjlz5my3lBozZkyMGjWq1d/DFkuWLIn99z8g1q1bm+xrAsCOpKysU/zP/7zUasGqLWmtDCU/AUBxKYT8VLClVG1tbUREVFRUNFivqKiI1157rf6YDh06xK677tromC3P35aRI0fG5ZdfXn9/yyd9reWtt96KdevWxlHfuT669Ni31b4OAOyIVi17NZ69c1S89dZbSqlovQwlPwFA8SiU/FSwpdQWuVyuwf0syxqt/bOPO6a0tDRKS0tbZL6m6NJj39ht788m/7oAwI6npTOU/AQAtLS8Xuj8o1RWVkZENPq0bvny5fWf/FVWVsb69etjxYoV2z0GAGBHIkMBAG1FwZZSvXr1isrKypgxY0b92vr162PWrFnRr1+/iIjo06dPtG/fvsExy5Yti//+7/+uPwYAYEciQwEAbUVev31vzZo18be//a3+/uLFi2PBggWx2267xd577x3Dhw+P0aNHR3V1dVRXV8fo0aOjU6dOMXjw4IiI6Nq1a1x44YVxxRVXRLdu3WK33XaLK6+8Mg455JA48cQT8/W2AABalQwFABSDvJZSzz33XBx//PH197dcPPO8886LyZMnx4gRI2LdunUxbNiwWLFiRRx11FExffr0KC8vr3/OTTfdFCUlJXHWWWfFunXr4oQTTojJkydHu3btkr8fAIAUZCgAoBjktZQaMGBAZFm23cdzuVzU1NRETU3Ndo/p2LFj3HzzzXHzzTe3woQAAIVHhgIAikHBXlMKAAAAgOKllAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJBcQZdSGzdujOuuuy569eoVZWVl0bt37/jRj34Umzdvrj8my7KoqamJqqqqKCsriwEDBsTChQvzODUAQH7JUABAW1DQpdSNN94YEydOjAkTJsRLL70UY8eOjZ/85Cdx88031x8zduzYGDduXEyYMCHmzp0blZWVMXDgwFi9enUeJwcAyB8ZCgBoCwq6lHrmmWfiq1/9apxyyimx7777xte//vUYNGhQPPfccxHxwSd848ePj2uvvTbOPPPMOPjgg+Ouu+6KtWvXxpQpU/I8PQBAfshQAEBbUNCl1Be/+MV47LHH4uWXX46IiD//+c8xe/bsOPnkkyMiYvHixVFbWxuDBg2qf05paWn0798/5syZs93Xrauri1WrVjW4AQAUi9bIUPITANDSSvI9wEe5+uqrY+XKlbH//vtHu3btYtOmTXHDDTfEt771rYiIqK2tjYiIioqKBs+rqKiI1157bbuvO2bMmBg1alTrDQ4AkEetkaHkJwCgpRX0mVL33ntv/OY3v4kpU6bE888/H3fddVf8v//3/+Kuu+5qcFwul2twP8uyRmsfNnLkyFi5cmX9benSpa0yPwBAPrRGhpKfAICWVtBnSl111VVxzTXXxDe/+c2IiDjkkEPitddeizFjxsR5550XlZWVEfHBp309evSof97y5csbffL3YaWlpVFaWtq6wwMA5ElrZCj5CQBoaQV9ptTatWtjp50ajtiuXbv6H2fcq1evqKysjBkzZtQ/vn79+pg1a1b069cv6awAAIVChgIA2oKCPlPqtNNOixtuuCH23nvvOOigg2L+/Pkxbty4+M53vhMRH5xyPnz48Bg9enRUV1dHdXV1jB49Ojp16hSDBw/O8/QAAPkhQwEAbUFBl1I333xz/OAHP4hhw4bF8uXLo6qqKoYOHRo//OEP648ZMWJErFu3LoYNGxYrVqyIo446KqZPnx7l5eV5nBwAIH9kKACgLSjoUqq8vDzGjx8f48eP3+4xuVwuampqoqam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KQUAAABAckop4pZbbolevXpFx44do0+fPvHUU0995PF1dXVx7bXXxj777BOlpaXxL//yL3HnnXcmmra4NHXv77777jjssMOiU6dO0aNHj7jgggvi7bffTjRtcXjyySfjtNNOi6qqqsjlcvHAAw987HNmzZoVffr0iY4dO0bv3r1j4sSJrT9oEWrq3k+bNi0GDhwYu+++e3Tp0iWOPvroePTRR9MMW2Sa8/t+i6effjpKSkri8MMPb7X5oBisWLEizj333OjatWt07do1zj333Hj33Xc/8fOHDh0auVwuxo8f32ozFqum7v2GDRvi6quvjkMOOSQ6d+4cVVVV8e1vfzvefPPNdEO3UU3NrjJUy2nK3stQLaupv++3kKE+GaXUDu7ee++N4cOHx7XXXhvz58+PY489Nr7yla/EkiVLtvucs846Kx577LG44447YtGiRTF16tTYf//9E05dHJq697Nnz45vf/vbceGFF8bChQvjvvvui7lz58ZFF12UePK27b333ovDDjssJkyY8ImOX7x4cZx88slx7LHHxvz58+Pf/u3f4tJLL43f/e53rTxp8Wnq3j/55JMxcODAeOihh2LevHlx/PHHx2mnnRbz589v5UmLT1P3fouVK1fGt7/97TjhhBNaaTIoHoMHD44FCxbEI488Eo888kgsWLAgzj333E/03AceeCCeffbZqKqqauUpi1NT937t2rXx/PPPxw9+8IN4/vnnY9q0afHyyy/H6aefnnDqtqep2VWGajlN3XsZquU059/LETJUk2Ts0I488sjs4osvbrC2//77Z9dcc802j3/44Yezrl27Zm+//XaK8YpaU/f+Jz/5Sda7d+8Gaz//+c+zvfbaq9VmLHYRkd1///0fecyIESOy/fffv8Ha0KFDsy984QutOFnx+yR7vy0HHnhgNmrUqJYfaAfSlL0/++yzs+uuuy67/vrrs8MOO6xV54K27MUXX8wiIvvjH/9Yv/bMM89kEZH9z//8z0c+9/XXX8/23HPP7L//+7+zffbZJ7vppptaedri8mn2/sP+9Kc/ZRGRvfbaa60xZlFoanaVoVpOU/d+W2So5mnu3stQn5wzpXZg69evj3nz5sWgQYMarA8aNCjmzJmzzec8+OCD0bdv3xg7dmzsueeesd9++8WVV14Z69atSzFy0WjO3vfr1y9ef/31eOihhyLLsvjf//3f+O1vfxunnHJKipF3WM8880yjX6eTTjopnnvuudiwYUOeptoxbd68OVavXh277bZbvkfZIUyaNCn+/ve/x/XXX5/vUaDgPfPMM9G1a9c46qij6te+8IUvRNeuXbf793rEB/9fO/fcc+Oqq66Kgw46KMWoRae5e//PVq5cGblcLnbZZZdWmLLta052laFaRnP2/p/JUM3T3L2XoZqmJN8DkD9vvfVWbNq0KSoqKhqsV1RURG1t7Taf88orr8Ts2bOjY8eOcf/998dbb70Vw4YNi3feecd1pZqgOXvfr1+/uPvuu+Pss8+O999/PzZu3Binn3563HzzzSlG3mHV1tZu89dp48aN8dZbb0WPHj3yNNmO56c//Wm89957cdZZZ+V7lKL317/+Na655pp46qmnoqREVICPU1tbG3vssUej9T322GO7f69HRNx4441RUlISl156aWuOV9Sau/cf9v7778c111wTgwcPji5durT0iEWhOdlVhmoZzdn7fyZDNU9z9l6GajpnShG5XK7B/SzLGq1tsXnz5sjlcnH33XfHkUceGSeffHKMGzcuJk+e7GypZmjK3r/44otx6aWXxg9/+MOYN29ePPLII7F48eK4+OKLU4y6Q9vWr9O21mk9U6dOjZqamrj33nu3+Y8PWs6mTZti8ODBMWrUqNhvv/3yPQ7kVU1NTeRyuY+8PffccxGx7b8TPurv9Xnz5sXPfvazmDx5sr9PtqE19/7DNmzYEN/85jdj8+bNccstt7T4+yg2Tcmu2zt+W+t8vKbu/RYy1Kf3Sfdehmoe1d0OrHv37tGuXbtGLe/y5csbtcFb9OjRI/bcc8/o2rVr/doBBxwQWZbF66+/HtXV1a06c7Fozt6PGTMmjjnmmLjqqqsiIuLQQw+Nzp07x7HHHhs//vGPfdrUSiorK7f561RSUhLdunXL01Q7lnvvvTcuvPDCuO++++LEE0/M9zhFb/Xq1fHcc8/F/Pnz45JLLomIDz6QyLIsSkpKYvr06fGlL30pz1NCGpdcckl885vf/Mhj9t133/jLX/4S//u//9vosX/84x/b/Xv9qaeeiuXLl8fee+9dv7Zp06a44oorYvz48fHqq69+qtnbutbc+y02bNgQZ511VixevDgef/xxZ0l9hOZkVxmqZTRn77eQoT6dpu69DNU8SqkdWIcOHaJPnz4xY8aMOOOMM+rXZ8yYEV/96le3+Zxjjjkm7rvvvlizZk3svPPOERHx8ssvx0477RR77bVXkrmLQXP2fu3atY1OAW3Xrl1EbP3UiZZ39NFHx3/+5382WJs+fXr07ds32rdvn6epdhxTp06N73znOzF16lTXT0ukS5cu8cILLzRYu+WWW+Lxxx+P3/72t9GrV688TQbpde/ePbp37/6xxx199NGxcuXK+NOf/hRHHnlkREQ8++yzsXLlyujXr982n3Puuec2+kfiSSedFOeee25ccMEFn374Nq419z5iayH117/+NWbOnKkk+RjNya4yVMtozt5HyFAtoal7L0M1Uz6urk7huOeee7L27dtnd9xxR/biiy9mw4cPzzp37py9+uqrWZZl2TXXXJOde+659cevXr0622uvvbKvf/3r2cKFC7NZs2Zl1dXV2UUXXZSvt9BmNXXvJ02alJWUlGS33HJL9ve//z2bPXt21rdv3+zII4/M11tok1avXp3Nnz8/mz9/fhYR2bhx47L58+fX/7Sdf973V155JevUqVP2/e9/P3vxxRezO+64I2vfvn3229/+Nl9voc1q6t5PmTIlKykpyX7xi19ky5Ytq7+9++67+XoLbVZT9/6f+ckx8PG+/OUvZ4ceemj2zDPPZM8880x2yCGHZKeeemqDYz772c9m06ZN2+5r+Ol7zdPUvd+wYUN2+umnZ3vttVe2YMGCBn/H1NXV5eMttAlNza4yVMtp6t7LUC2nqXv/z2Soj6eUIvvFL36R7bPPPlmHDh2yz3/+89msWbPqHzvvvPOy/v37Nzj+pZdeyk488cSsrKws22uvvbLLL788W7t2beKpi0NT9/7nP/95duCBB2ZlZWVZjx49siFDhmSvv/564qnbtpkzZ2YR0eh23nnnZVm27X1/4oknss997nNZhw4dsn333Te79dZb0w9eBJq69/379//I4/nkmvP7/sMEKvh4b7/9djZkyJCsvLw8Ky8vz4YMGZKtWLGiwTERkU2aNGm7r6GUap6m7v3ixYu3+f/EiMhmzpyZfP62pKnZVYZqOU3ZexmqZTX19/2HyVAfL5dlvu8HAAAAgLT89D0AAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAAre5MmTY5dddsn3GEALymVZluV7CAAAAHY8559/frz77rvxwAMPfOyx69ati9WrV8cee+zR+oMBSZTkewAAPrBhw4Zo3759vscAACg4GzZsiLKysigrK8v3KEAL8u17QJvwyCOPxBe/+MXYZZddolu3bnHqqafG3//+94iIOProo+Oaa65pcPw//vGPaN++fcycOfNjX/uWW26J6urq6NixY1RUVMTXv/71TzTT5s2b48Ybb4zPfOYzUVpaGnvvvXfccMMN9Y9fffXVsd9++0WnTp2id+/e8YMf/CA2bNhQ/3hNTU0cfvjhceedd0bv3r2jtLQ0nLwKADRVa+akfffdN0aPHh3f+c53ory8PPbee++47bbbGhzzwgsvxJe+9KUoKyuLbt26xf/5P/8n1qxZ87GvXVNTE3fddVf8/ve/j1wuF7lcLp544ol49dVXI5fLxX/8x3/EgAEDomPHjvGb3/ym0bfvbclSv/zlL6Nnz57RqVOn+MY3vhHvvvvux28a/P/bu7uQJtswDuD/rWWaXw1ZTgpnMpOlZNA8MMsgsyyIVYSFUzyIDiob2JeEzUlnWVFBVOhBnTittIK0JmQHyTKxchW5BEt7ohYTCyTte/d78L6OfF9103Lmy/8Hgs/9cV3PvaOLi2d76I/AphQRTQsDAwPYu3cv2tra0NTUBLlcjk2bNsHj8cBoNKK6unpYQ+fSpUuIjo7GypUrx4z74MEDmEwmHDlyBJ2dnbDZbMjIyPDrng4dOoSjR4/CbDajo6MDVqsV0dHR3vnw8HBcvHgRHR0dOH36NCorK3Hy5MlhMbq6unD58mXU1dXB4XD4/4EQERER/WOy6qQhJ06cgF6vR3t7O3bt2oWdO3fi+fPnAIDBwUFkZ2dDqVSira0NV65cwe3bt1FYWOgz7v79+5GTk4Ps7Gy4XC64XC4sW7bMO19cXAyTyQSn04m1a9eOGGOolrpx4wZsNhscDgd2797t17mI6A8giIimIbfbLQCIp0+fCrfbLRQKhbh79653Pi0tTRw4cMBnnLq6OhERESH6+/vHlb+/v1/MmjVLVFZW+r2nvLxcLF261HttsVjEzJkzhdvtHlduIiIiorH8rjpJCCE0Go3Iy8vzXns8HjF37lxx7tw5IYQQFRUVQqlUio8fP3rXNDQ0CLlcLt69e+czfkFBgTAYDMPGuru7BQBx6tSpYeMXLlwQkZGR3muLxSJmzJghXr9+7R27deuWkMvlwuVy+XU+IppafFKKiKaFFy9eIDc3F/Hx8YiIiMCCBQsAAJIkQaVSISsrC1VVVQCA7u5utLS0wGg0+oyblZUFjUaD+Ph45Ofno6qqCoODgz73OZ1OfPnyBZmZmaOuqa2txfLly6FWqxEWFgaz2QxJkoat0Wg0UKlUPvMRERERjWay6qQhixcv9v4vk8mgVqvhdrsB/F0TpaSkIDQ01LsmPT0dHo8HnZ2dv3QuvV7vc01sbCzmz5/vvU5LS/stuYkoMNiUIqJpYcOGDejr60NlZSVaW1vR2toKAPj69SsAwGg0ora2Ft++fYPVakVSUhJSUlJ8xg0PD8ejR49QXV2NmJgYlJaWIiUlxedvEfj6kc379+9j27ZtWLduHerr69He3o6SkhLv/Q75uYAjIiIimojJqpOG/PtFLDKZDB6PBwAghIBMJhtx32jj/ppInTSU81dzE1FgsClFRH+8vr4+OJ1OHD58GJmZmdDpdPjw4cOwNRs3bsTnz59hs9lgtVqRl5fnd3yFQoHVq1ejvLwcT548QU9PD+7cuTPmnoSEBISEhKCpqWnEebvdDo1Gg5KSEuj1eiQkJODVq1d+3xMRERGRPya7TvJl0aJFcDgcGBgY8I7Z7XbI5XIsXLjQ5/6goCD8+PFjwvklScLbt2+91y0tLX7nJqKpp5jqGyAi8kWpVCIqKgoVFRWIiYmBJEn/eYtMaGgoDAYDzGYznE4ncnNz/YpdX1+Ply9fIiMjA0qlEjdv3oTH40FiYuKY+4KDg1FcXIyDBw8iKCgI6enp6O3txbNnz7B9+3ZotVpIkoSamhqkpqaioaEB165dm/BnQERERDSSyayT/GE0GmGxWFBQUICysjL09vZiz549yM/PH/YCmNHExcWhsbERnZ2diIqKQmRk5LjyBwcHo6CgAMePH0d/fz9MJhNycnKgVqsneiQiCiA+KUVEfzy5XI6amho8fPgQycnJKCoqwrFjx/6zzmg04vHjx1ixYgViY2P9ij1nzhxcvXoVq1atgk6nw/nz51FdXY2kpCSfe81mM/bt24fS0lLodDps3brV+/sKBoMBRUVFKCwsxJIlS3Dv3j2YzebxHZyIiIjIh8msk/wxe/ZsNDY24v3790hNTcWWLVuQmZmJM2fO+LV/x44dSExMhF6vh0qlgt1uH1d+rVaLzZs3Y/369VizZg2Sk5Nx9uzZiRyFiKaATIif3g1KRERERERENA2UlZXh+vXrcDgcU30rRDRBfFKKiIiIiIiIiIgCjk0pIvpfa25uRlhY2Kh/o5Ekacx9kiQF8BREREREv99E66TxGCt+c3Pzb8lBRNMXv75HRP9rnz59wps3b0ad12q1I45///4dPT09o+6Li4uDQsF3RRAREdH0NdE6aTy6urpGnZs3bx5CQkJ+OQcRTV9sShERERERERERUcDx63tERERERERERBRwbEoREREREREREVHAsSlFREREREREREQBx6YUEREREREREREFHJtSREREREREREQUcGxKERERERERERFRwLEpRUREREREREREAfcXzmcQWlVOk54AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "For cluster 0:\n" + ] + }, + { + "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", + "
featurech
0is_student-0.0
23av_s_car-0.0
22av_no_trip-0.0
21av_ridehail-0.0
\n", + "
" + ], + "text/plain": [ + " feature ch\n", + "0 is_student -0.0\n", + "23 av_s_car -0.0\n", + "22 av_no_trip -0.0\n", + "21 av_ridehail -0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "image/png": "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uzjppJOirKwsnnnmmairq4uIiLVr18bYsWNbdEAAgGIhQwEAbNWsUuqHP/xhTJ48OW677bZo3759/Xr//v3jmWeeabHhAACKiQwFALBVs0qpF154IY477rhG6507d4633nrrk84EAFCUZCgAgK2aVUp169Yt/v73vzdanzt3bvTu3fsTDwUAUIxkKACArZpVSg0bNiwuv/zyeOqppyKXy8Xy5cvjrrvuiquuuiqGDx/e0jMCABQFGQoAYKuS5jxp5MiRsWbNmjj++OPjnXfeieOOOy5KS0vjqquuiksvvbSlZwQAKAoyFADAVk0qpdavXx/f+9734v77749NmzbFaaedFldeeWVERBx00EGx2267tcqQAABtmQwFANBYk0qp66+/PqZOnRpDhw6NsrKymDZtWmzZsiV++9vfttZ8AABtngwFANBYk0qpGTNmxO233x7nnHNOREQMHTo0jj766Ni8eXO0a9euVQYEAGjrZCgAgMaadKHzZcuWxbHHHlt//4gjjoiSkpJYvnx5iw8GAFAsZCgAgMaaVEpt3rw5OnTo0GCtpKQk3n333RYdCgCgmMhQAACNNenH97IsiwsuuCBKS0vr195555245JJLYtddd61fmzFjRstNCADQxslQAACNNamUOv/88xutnXvuuS02DABAMZKhAAAaa1IpNWXKlNaaAwCgaMlQAACNNemaUgAAAADQEpRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAILk2VUqNGzcucrlcjBgxon4ty7KoqamJqqqqKCsri4EDB8bixYvzNyQAQIGRoQCAQtRmSqn58+fHrbfeGp/97GcbrI8fPz4mTJgQkyZNivnz50dlZWUMGjQo1q5dm6dJAQAKhwwFABSqNlFKrVu3LoYOHRq33XZb7LHHHvXrWZbFxIkTY/To0XHmmWdGnz594s4774z169fHtGnT8jgxAED+yVAAQCFrE6XUt7/97TjllFPixBNPbLC+ZMmSqK2tjcGDB9evlZaWxoABA2LevHnbfb26urpYs2ZNgxsAQLFpyQwlPwEALa0k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trZ2m8956aWXYu7cudGxY8e477774vXXX4/hw4fHm2++6boITdCcve/fv3/cddddcfbZZ8c777wT7777bpx++ulx0003pRh5p1VbW7vNf0/vvvtuvP7669GtW7c8Tbbz+clPfhJvv/12nHXWWfkepej97W9/i2uuuSYef/zxKCkRFeCD5Kf8kZ/aFhmqcMhQachPzeNMKSKXyzW4n2VZo7X3bdmyJXK5XNx1111xxBFHxMknnxwTJkyIqVOn+rSvGZqy988991xcdtll8f3vfz8WLFgQDz30UCxZsiQuueSSFKPu1Lb172lb67Se6dOnR01NTdxzzz2xzz775HucorZ58+YYMmRIjBkzJvbff/98jwMFS37KH/mp7ZCh8k+GSkN+aj713U5sr732inbt2jX6ZGnlypWNPtV4X7du3eJTn/pUdOnSpX7twAMPjCzL4tVXX43q6upWnblYNGfvx40bF0cffXR873vfi4iIz372s7HrrrvGscceGz/84Q992tRKKisrt/nvqaSkJLp27ZqnqXYu99xzT1x00UXx29/+Nk488cR8j1P01q5dG08//XQsXLgwLr300oh473+osyyLkpKSmDlzZnzxi1/M85SQP/JT/shPbYsMlX8yVDryU/M5U2on1qFDh+jbt2/MmjWrwfqsWbOif//+23zO0UcfHcuXL49169bVr7344ouxyy67xL777tuq8xaT5uz9+vXrY5ddGn7LtmvXLiK2fupEyzvqqKMa/XuaOXNm9OvXL9q3b5+nqXYe06dPjwsuuCCmTZvm+h+JdO7cOZ599tlYtGhR/e2SSy6Jz3zmM7Fo0aI48sgj8z0i5JX8lD/yU9siQ+WXDJWW/PQJ5OPq6hSOu+++O2vfvn12++23Z88991w2YsSIbNddd81efvnlLMuy7JprrsnOO++8+uPXrl2b7bvvvtnXvva1bPHixdmcOXOy6urq7OKLL87XW2izmrr3U6ZMyUpKSrKbb745+8c//pHNnTs369evX3bEEUfk6y20SWvXrs0WLlyYLVy4MIuIbMKECdnChQuzV155Jcuyxvv+0ksvZZ06dcq++93vZs8991x2++23Z+3bt8/uvffefL2FNqupez9t2rSspKQk+/nPf56tWLGi/vbWW2/l6y20WU3d+w/z22OgIfkpf+Sn/JGh8keGyg/5KQ2lFNnPf/7zrEePHlmHDh2yz3/+89mcOXPqHzv//POzAQMGNDj++eefz0488cSsrKws23fffbMrrrgiW79+feKpi0NT9/5nP/tZdtBBB2VlZWVZt27dsqFDh2avvvpq4qnbtkceeSSLiEa3888/P8uybe/7o48+mn3uc5/LOnTokPXs2TO75ZZb0g9eBJq69wMGDPjI49lxzflz/0FCFTQmP+WP/JQfMlT+yFD5IT+lkcsy560CAAAAkJZrSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySimgYAwcODBGjBiR7zF2yNSpU2P33XfP9xgAAABtVkm+BwB434wZM6J9+/at9voXXHBBvPXWW3H//fe32tf4JB599NE4/vjjY9WqVQovAACg6CmlgIKx55575nsEAADakE2bNrXqh5pA6/Lje0DB+OCP7918881RXV0dHTt2jIqKivja1762Q69x7733xiGHHBJlZWXRtWvXOPHEE+Ptt9+OmpqauPPOO+P3v/995HK5yOVy8eijj8ajjz4auVwu3nrrrfrXWLRoUeRyuXj55Zfr16ZOnRr77bdfdOrUKc4444x44403Gn3tf//3f4++fftGx44do3fv3jFmzJh499136x/P5XLxy1/+Ms4444zo1KlTVFdXxx/+8IeIiHj55Zfj+OOPj4iIPfbYI3K5XFxwwQVN20AAgA946KGH4phjjondd989unbtGqeeemr84x//iIiIo446Kq655poGx//zn/+M9u3bxyOPPPKxr93crLZly5a44YYb4tOf/nSUlpbGfvvtFz/60Y/qH7/66qtj//33j06dOkXv3r3juuuui02bNtU/XlNTE4cddljccccd0bt37ygtLY0sy3boawOFRykFFJynn346LrvssvjBD34QL7zwQjz00ENx3HHHfezzVqxYEf/6r/8a3/zmN+P555+PRx99NM4888zIsiyuuuqqOOuss+JLX/pSrFixIlasWBH9+/ffoXmeeuqp+OY3vxnDhw+PRYsWxfHHHx8//OEPGxzzpz/9Kc4999y47LLL4rnnnotf/OIXMXXq1AYhKyJizJgxcdZZZ8Vf//rXOPnkk2Po0KHx5ptvRvfu3eN3v/tdRES88MILsWLFivjpT3+6gzsGANDY22+/HVdccUXMnz8/Zs+eHbvsskucccYZsWXLlhg6dGhMnz69QaFzzz33REVFRQwYMOAjX7e5WS0iYtSoUXHDDTfEddddF88991xMmzYtKioq6h8vLy+PqVOnxnPPPRc//elP47bbbosbb7yxwWv8/e9/j9/85jfxu9/9LhYtWrTjGwIUnFymVgYKxMCBA+Owww6L4447Li688MJ49dVXo7y8fIef/8wzz0Tfvn3j5Zdfjh49ejR6fFvXlNrWdZwWLVoUn/vc52LJkiXRs2fPGDJkSKxatSoefPDB+uedc8458dBDD9WfYXXcccfFl7/85Rg1alT9Mb/+9a9j5MiRsXz58oh470ypa6+9Nv7P//k/EfFeUCwvL48HHnggvvSlL7mmFADQqv75z3/GPvvsE88++2xUVFREVVVVPPzww3HsscdGRET//v3jmGOOifHjx3/k68yYMaNZWW3t2rWx9957x6RJk+Liiy/eoef8+Mc/jnvuuSeefvrpiHjvTKmxY8fGa6+9FnvvvfcOf22gMDlTCig4gwYNih49ekTv3r3jvPPOi7vuuivWr1//sc879NBD44QTTohDDjkkvv71r8dtt90Wq1at+sTzPP/883HUUUc1WPvw/QULFsQPfvCD2G233epv3/rWt2LFihUNZv/sZz9b/8+77rprlJeXx8qVKz/xjAAAH/aPf/wjhgwZEr17947OnTtHr169IiJi6dKlsffee8egQYPirrvuioiIJUuWxJNPPhlDhw792NdtblZ7/vnno66uLk444YTtHnPvvffGMcccE5WVlbHbbrvFddddF0uXLm1wTI8ePRRSUCSUUkDBKS8vj2eeeSamT58e3bp1i+9///tx6KGHNrju07a0a9cuZs2aFQ8++GAcdNBBcdNNN8VnPvOZWLJkyXafs8su7/01+MGTRj943YIPP7Y9W7ZsiTFjxsSiRYvqb88++2z87W9/i44dO9Yf9+ELceZyudiyZcvHvj4AQFOddtpp8cYbb8Rtt90WTz31VDz11FMREbFx48aIiBg6dGjce++9sWnTppg2bVocfPDBceihh37s6zY3q5WVlX3k43/+85/jnHPOiS9/+cvxxz/+MRYuXBijR4+un/d9u+6668fOCLQNSimgIJWUlMSJJ54Y48ePj7/+9a/x8ssvx8MPP/yxz8vlcnH00UfHmDFjYuHChdGhQ4e47777IiKiQ4cOsXnz5gbHv/8p24oVK+rXPnxtgoMOOij+/Oc/N1j78P3Pf/7z8cILL8SnP/3pRrf3i6+P06FDh4iIRjMCADTVG2+8Ec8//3xce+21ccIJJ8SBBx7Y6Azyr371q/HOO+/EQw89FNOmTYtzzz13h1+/OVmturo6ysrKYvbs2dt8/IknnogePXrE6NGjo1+/flFdXR2vvPLKDs8EtD0l+R4A4MP++Mc/xksvvRTHHXdc7LHHHvHAAw/Eli1b4jOf+cxHPu+pp56K2bNnx+DBg2OfffaJp556Kv75z3/GgQceGBERPXv2jD/96U/xwgsvRNeuXaNLly7x6U9/Orp37x41NTXxwx/+MP72t7/FT37ykwave9lll0X//v1j/Pjx8dWvfjVmzpwZDz30UINjvv/978epp54a3bt3j69//euxyy67xF//+td49tlnG10UfXt69OgRuVwu/vjHP8bJJ58cZWVlsdtuuzVh5wAA3rPHHntE165d49Zbb41u3brF0qVLG/22vV133TW+8pWvxHXXXRfPP/98DBkyZIdeu7lZrWPHjnH11VfHyJEjo0OHDnH00UfHP//5z1i8eHFcdNFF8elPfzqWLl0ad999dxx++OHx//7f/6v/cBEoTs6UAgrO7rvvHjNmzIgvfvGLceCBB8bkyZNj+vTpcfDBB3/k8zp37hyPPfZYnHzyybH//vvHtddeGz/5yU/iy1/+ckREfOtb34rPfOYz0a9fv9h7773jiSeeiPbt28f06dPjv//7v+PQQw+NG264oVGJ9IUvfCF++ctfxk033RSHHXZYzJw5M6699toGx5x00knxxz/+MWbNmhWHH354fOELX4gJEyZs84Lr2/OpT30qxowZE9dcc01UVFTEpZdeusPPBQD4oF122SXuvvvuWLBgQfTp0ye++93vxo9//ONGxw0dOjT+8z//M4499tjYb7/9dui1m5vVIiKuu+66uPLKK+P73/9+HHjggXH22WfXX1/zK1/5Snz3u9+NSy+9NA477LCYN29eXHfddU1740Cb4rfvAQAAAJCcM6UAAAAASE4pBbQZS5cujd122227tw//umAAAJru8ccf/8jMtT2yGtBUfnwPaDPefffdePnll7f7eM+ePaOkxO9vAAD4JDZs2BCvvfbadh//9Kc/vc11WQ1oKqUUAAAAAMn58T0AAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDkSvI9QCHYsmVLLF++PMrLyyOXy+V7HACggGRZFmvXro2qqqrYZRef571PfgIAtmdH85NSKiKWL18e3bt3z/cYAEABW7ZsWey77775HqNgyE8AwMf5uPyklIqI8vLyiHhvszp37pznaQCAQrJmzZro3r17fV7gPfITALA9O5qflFIR9aecd+7cWagCALbJj6g1JD8BAB/n4/KTCyMAAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEByeS2lHnvssTjttNOiqqoqcrlc3H///Q0ez7IsampqoqqqKsrKymLgwIGxePHiBsfU1dXFd77zndhrr71i1113jdNPPz1effXVhO8CACAtGQoAKAZ5LaXefvvtOPTQQ2PSpEnbfHz8+PExYcKEmDRpUsyfPz8qKytj0KBBsXbt2vpjRowYEffdd1/cfffdMXfu3Fi3bl2ceuqpsXnz5lRvAwAgKRkKACgGuSzLsnwPERGRy+Xivvvui69+9asR8d4nfFVVVTFixIi4+uqrI+K9T/QqKirihhtuiGHDhsXq1atj7733jl/96ldx9tlnR0TE8uXLo3v37vHAAw/ESSedtM2vVVdXF3V1dfX316xZE927d4/Vq1dH586dW+X9LV26NF5//fVWeW0A2Nnttddesd9++7XKa69Zsya6dOnSqjnhk0iVoeQnACguhZCfSlrlq7eAJUuWRG1tbQwePLh+rbS0NAYMGBDz5s2LYcOGxYIFC2LTpk0Njqmqqoo+ffrEvHnztltKjRs3LsaMGdPq7+F9S5cujQMOODA2bFif7GsCwM6krKxT/Pd/P99qwaotaa0MJT8BQHEphPxUsKVUbW1tRERUVFQ0WK+oqIhXXnml/pgOHTrEHnvs0eiY95+/LaNGjYorrrii/v77n/S1ltdffz02bFgfR37z+ujcrWerfR0A2BmtWfFyPHXHmHj99deVUtF6GUp+AoDiUSj5qWBLqfflcrkG97Msa7T2YR93TGlpaZSWlrbI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lsUVV1wRxxxzTPTp0yciImprayMioqKiosGxFRUV9Y9ty7hx46JLly71t+7du7fe4AAAedRSGUp+AgBaWpsppS699NL461//GtOnT2/0WC6Xa3A/y7JGax80atSoWL16df1t2bJlLT4vAEAhaKkMJT8BAC2toK8p9b7vfOc78Yc//CEee+yx2HfffevXKysrI+K9T/u6detWv75y5cpGn/x9UGlpaZSWlrbewAAABaAlM5T8BAC0tII+UyrLsrj00ktjxowZ8fDDD0evXr0aPN6rV6+orKyMWbNm1a9t3Lgx5syZE/379089LgBAQZChAIC2oKDPlPr2t78d06ZNi9///vdRXl5ef42DLl26RFlZWeRyuRgxYkSMHTs2qquro7q6OsaOHRudOnWKIUOG5Hl6AID8kKEAgLagoEupW265JSIiBg4c2GB9ypQpccEFF0RExMiRI2PDhg0xfPjwWLVqVRx55JExc+bMKC8vTzwtAEBhkKEAgLagoEupLMs+9phcLhc1NTVRU1PT+gMBALQBMhQA0BYU9DWlAAAAAChOSikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASK5oSqmbb745evXqFR07doy+ffvG448/nu+RAAAKngwFAORLUZRS99xzT4wYMSJGjx4dCxcujGOPPTa+/OUvx9KlS/M9GgBAwZKhAIB8KopSasKECXHRRRfFxRdfHAceeGBMnDgxunfvHrfccku+RwMAKFgyFACQTyX5HuCT2rhxYyxYsCCuueaaBuuDBw+OefPmbfM5dXV1UVdXV39/9erVERGxZs2aVplx3bp1ERHx5isvxLt1G1rlawDAzmpN7Xtn9axbt65V/lv+/mtmWdbir51PTc1Q8hMAFI9CyU9tvpR6/fXXY/PmzVFRUdFgvaKiImpra7f5nHHjxsWYMWMarXfv3r1VZnzfgl///1r19QFgZzZgwIBWff21a9dGly5dWvVrpNTUDCU/AUDxyXd+avOl1PtyuVyD+1mWNVp736hRo+KKK66ov79ly5Z48803o2vXrtt9zs5qzZo10b1791i2bFl07tw53+PsVOx9/tj7/LH3+WHfP1qWZbF27dqoqqrK9yitYkczlPzUNL6v8sO+54+9zx97nz/2fvt2ND+1+VJqr732inbt2jX6RG/lypWNPvl7X2lpaZSWljZY23333VtrxKLQuXNn32R5Yu/zx97nj73PD/u+fcV0htT7mpqh5Kfm8X2VH/Y9f+x9/tj7/LH327Yj+anNX+i8Q4cO0bdv35g1a1aD9VmzZkX//v3zNBUAQGGToQCAfGvzZ0pFRFxxxRVx3nnnRb9+/eKoo46KW2+9NZYuXRqXXHJJvkcDAChYMhQAkE9FUUqdffbZ8cYbb8QPfvCDWLFiRfTp0yceeOCB6NGjR75Ha/NKS0vj+uuvb3S6Pq3P3uePvc8fe58f9n3nJUO1Ht9X+WHf88fe54+9zx97/8nlsmL7/cYAAAAAFLw2f00pAAAAANoepRQAAAAAySmlAAAAAEhOKQUAAABAckopGlm1alWcd9550aVLl+jSpUucd9558dZbb+3w84cNGxa5XC4mTpzYajMWo6bu+6ZNm+Lqq6+OQw45JHbdddeoqqqKb3zjG7F8+fJ0Q7dhN998c/Tq1Ss6duwYffv2jccff/wjj58zZ0707ds3OnbsGL17947JkycnmrS4NGXfZ8yYEYMGDYq99947OnfuHEcddVT86U9/SjhtcWnqn/n3PfHEE1FSUhKHHXZY6w4IbUxTv6fq6upi9OjR0aNHjygtLY1/+Zd/iTvuuCPRtMWlqXt/1113xaGHHhqdOnWKbt26xYUXXhhvvPFGommLx2OPPRannXZaVFVVRS6Xi/vvv/9jnyM/tYym7r0M1TKa82f+ffLTjlNK0ciQIUNi0aJF8dBDD8VDDz0UixYtivPOO2+Hnnv//ffHU089FVVVVa08ZfFp6r6vX78+nnnmmbjuuuvimWeeiRkzZsSLL74Yp59+esKp26Z77rknRowYEaNHj46FCxfGscceG1/+8pdj6dKl2zx+yZIlcfLJJ8exxx4bCxcujP/9v/93XHbZZfG73/0u8eRtW1P3/bHHHotBgwbFAw88EAsWLIjjjz8+TjvttFi4cGHiydu+pu79+1avXh3f+MY34oQTTkg0KbQNzfmeOuuss2L27Nlx++23xwsvvBDTp0+PAw44IOHUxaGpez937tz4xje+ERdddFEsXrw4fvvb38b8+fPj4osvTjx52/f222/HoYceGpMmTdqh4+WnltPUvZehWkZT9/198lMTZfABzz33XBYR2Z///Of6tSeffDKLiOy///u/P/K5r776avapT30q+6//+q+sR48e2Y033tjK0xaPT7LvH/SXv/wli4jslVdeaY0xi8YRRxyRXXLJJQ3WDjjggOyaa67Z5vEjR47MDjjggAZrw4YNy77whS+02ozFqKn7vi0HHXRQNmbMmJYereg1d+/PPvvs7Nprr82uv/767NBDD23FCaFtaer31IMPPph16dIle+ONN1KMV9Sauvc//vGPs969ezdY+9nPfpbtu+++rTbjziAisvvuu+8jj5GfWseO7P22yFCfTFP2XX5qGmdK0cCTTz4ZXbp0iSOPPLJ+7Qtf+EJ06dIl5s2bt93nbdmyJc4777z43ve+FwcffHCKUYtKc/f9w1avXh25XC523333VpiyOGzcuDEWLFgQgwcPbrA+ePDg7e71k08+2ej4k046KZ5++unYtGlTq81aTJqz7x+2ZcuWWLt2bey5556tMWLRau7eT5kyJf7xj3/E9ddf39ojQpvSnO+pP/zhD9GvX78YP358fOpTn4r9998/rrrqqtiwYUOKkYtGc/a+f//+8eqrr8YDDzwQWZbF//zP/8S9994bp5xySoqRd2ryU+GQodKRn5quJN8DUFhqa2tjn332abS+zz77RG1t7Xafd8MNN0RJSUlcdtllrTle0Wruvn/QO++8E9dcc00MGTIkOnfu3NIjFo3XX389Nm/eHBUVFQ3WKyoqtrvXtbW12zz+3Xffjddffz26devWavMWi+bs+4f95Cc/ibfffjvOOuus1hixaDVn7//2t7/FNddcE48//niUlIgK8EHN+Z566aWXYu7cudGxY8e477774vXXX4/hw4fHm2++6bpSTdCcve/fv3/cddddcfbZZ8c777wT7777bpx++ulx0003pRh5pyY/FQ4ZKg35qXmcKbWTqKmpiVwu95G3p59+OiIicrlco+dnWbbN9YiIBQsWxE9/+tOYOnXqdo/ZWbXmvn/Qpk2b4pxzzoktW7bEzTff3OLvoxh9eF8/bq+3dfy21vloTd33902fPj1qamrinnvu2WaBy8fb0b3fvHlzDBkyJMaMGRP7779/qvGgzWnK32dbtmyJXC4Xd911VxxxxBFx8sknx4QJE2Lq1KnOlmqGpuz9c889F5dddll8//vfjwULFsRDDz0US5YsiUsuuSTFqDs9+Sn/ZKg05KfmU9/tJC699NI455xzPvKYnj17xl//+tf4n//5n0aP/fOf/2z0Scf7Hn/88Vi5cmXst99+9WubN2+OK6+8MiZOnBgvv/zyJ5q9LWvNfX/fpk2b4qyzzoolS5bEww8/7Cypj7HXXntFu3btGn2iunLlyu3udWVl5TaPLykpia5du7barMWkOfv+vnvuuScuuuii+O1vfxsnnnhia45ZlJq692vXro2nn346Fi5cGJdeemlEvPc/1FmWRUlJScycOTO++MUvJpkdClFz/j7r1q1bfOpTn4ouXbrUrx144IGRZVm8+uqrUV1d3aozF4vm7P24cePi6KOPju9973sREfHZz342dt111zj22GPjhz/8obN1WpH8lH8yVDryU/MppXYSe+21V+y1114fe9xRRx0Vq1evjr/85S9xxBFHRETEU089FatXr47+/ftv8znnnXdeo7/kTjrppDjvvPPiwgsv/OTDt2Gtue8RWwupv/3tb/HII4/4D/wO6NChQ/Tt2zdmzZoVZ5xxRv36rFmz4itf+co2n3PUUUfFv//7vzdYmzlzZvTr1y/at2/fqvMWi+bse8R7n+5985vfjOnTp7v+RzM1de87d+4czz77bIO1m2++OR5++OG49957o1evXq0+MxSy5vx9dvTRR8dvf/vbWLduXey2224REfHiiy/GLrvsEvvuu2+SuYtBc/Z+/fr1jX6Mpl27dhGx9awdWof8lF8yVFry0yeQj6urU9i+9KUvZZ/97GezJ598MnvyySezQw45JDv11FMbHPOZz3wmmzFjxnZfw2/fa7qm7vumTZuy008/Pdt3332zRYsWZStWrKi/1dXV5eMttBl333131r59++z222/PnnvuuWzEiBHZrrvumr388stZlmXZNddck5133nn1x7/00ktZp06dsu9+97vZc889l91+++1Z+/bts3vvvTdfb6FNauq+T5s2LSspKcl+/vOfN/jz/dZbb+XrLbRZTd37D/PbY6Chpn5PrV27Ntt3332zr33ta9nixYuzOXPmZNXV1dnFF1+cr7fQZjV176dMmZKVlJRkN998c/aPf/wjmzt3btavX7/siCOOyNdbaLPWrl2bLVy4MFu4cGEWEdmECROyhQsX1v/WZ/mp9TR172WoltHUff8w+WnHKKVo5I033siGDh2alZeXZ+Xl5dnQoUOzVatWNTgmIrIpU6Zs9zWUUk3X1H1fsmRJFhHbvD3yyCPJ529rfv7zn2c9evTIOnTokH3+85/P5syZU//Y+eefnw0YMKDB8Y8++mj2uc99LuvQoUPWs2fP7JZbbkk8cXFoyr4PGDBgm3++zz///PSDF4Gm/pn/IKEKGmvq99Tzzz+fnXjiiVlZWVm27777ZldccUW2fv36xFMXh6bu/c9+9rPsoIMOysrKyrJu3bplQ4cOzV599dXEU7d9jzzyyEf+d1l+aj1N3XsZqmU058/8B8lPOyaXZc5bBQAAACAtv30PAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgogD6ZOnRq77757vscAANhhL7/8cuRyuVi0aNF2j3n00Ucjl8vFW2+9tcOv27Nnz5g4ceInmq2mpiYOO+yw+vsXXHBBfPWrX/1Erwm0PqUUQAtpSvg5++yz48UXX2zdgQAAWlD37t1jxYoV0adPn3yP0shVV10Vs2fPzvcYQBOV5HsAgJ3Npk2boqysLMrKyvI9CgDADtm4cWN06NAhKisr8z3KNu22226x22675XsMoImcKQUU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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], "source": [ "### DEMOGRAPHICS\n", "\n", @@ -620,7 +1354,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "id": "580bbd86", "metadata": {}, "outputs": [], @@ -629,10 +1363,10 @@ "\n", "def get_trip_summary_df(users, df):\n", " '''\n", - " 1. df = a huge dataframe of user-trips. Each row is a trip.\n", - " 2. every trip is divided into sections: [walk, transit, walk]\n", - " 3. Each section has a corresponding distance and duration: [m1, m2, m3], [t1, t2, t3], [d1, d2, d3]\n", - " 4. What we are doing is only considering the mode, distance, and duration of the section with the largest distance\n", + " Group the trips by user ID and argmax_mode and compute trip summaries. Additional\n", + " statistics that could be incorporated: IQR.\n", + " \n", + " mode_coverage computes trips summaries for the sections with the most-traveled distance.\n", " '''\n", " \n", " costs = [c for c in df.columns if 'av_' in c]\n", @@ -654,12 +1388,208 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "id": "92ad2485", "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For cluster -1:\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/4x/l9lw50rn7qvf79m01f21x70mlpd6gh/T/ipykernel_35596/1105737326.py:49: RuntimeWarning: Mean of empty slice\n", + " out_cluster_homogeneity[cix][feature] = np.nanmean([in_cluster_homogeneity[x].get(feature, np.nan) for x in oix])\n" + ] + }, + { + "data": { + "text/plain": [ + "unknown 0.986577\n", + "car 0.013423\n", + "Name: target, dtype: float64" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "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", + "
featurech
0section_duration_argmax_mean_bicycling0.0
25duration_median0.0
24duration_mean0.0
23mph_median_walking0.0
\n", + "
" + ], + "text/plain": [ + " feature ch\n", + "0 section_duration_argmax_mean_bicycling 0.0\n", + "25 duration_median 0.0\n", + "24 duration_mean 0.0\n", + "23 mph_median_walking 0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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97+PXr16xamnnhq77bZbHHjggXHHHXfkty9YsCAqKytjwIAB+bWioqLo27dvzJw5c4vPO2rUqGjXrl3+1qlTp3p9HwAAKdVHhpKfAIC61qBLqVdeeSVuu+226NatWzz00ENx/vnnx8UXXxy/+MUvIiKisrIyIiJKS0urPa60tDS/bXOuvvrqWLFiRf62aNGi+nsTAACJ1UeGkp8AgLrWoL++t2HDhujVq1eMHDkyIiIOPPDAeP755+O2226Lb3zjG/n9crlctcdlWVZj7cOKioqiqKiofoYGACiw+shQ8hMAUNca9JlSHTt2jH322afa2t577x0LFy6MiIiysrKIiBqf6C1durTGJ38AAJ8WMhQA0Bg06FLq0EMPjRdffLHa2vz586Nz584REdG1a9coKyuLqVOn5revXbs2pk2bFn369Ek6KwBAQyFDAQCNQYP++t63v/3t6NOnT4wcOTJOO+20eOqpp+L222+P22+/PSI+OOV82LBhMXLkyOjWrVt069YtRo4cGa1bt46BAwcWeHoAgMKQoQCAxqBBl1IHH3xw/O53v4urr746rr/++ujatWuMHTs2Bg0alN9n+PDhsWbNmhg6dGgsX748evfuHVOmTImSkpICTg4AUDgyFADQGDToUioi4vjjj4/jjz9+i9tzuVxUVFRERUVFuqEAABo4GQoAaOga9DWlAAAAAGiaalVKNWvWLJYuXVpj/c0334xmzZp94qEAAJoiGQoAYJNalVJZlm12vaqqKlq2bPmJBgIAaKpkKACATbbrmlI/+tGPIuKDaxD87Gc/izZt2uS3rV+/Ph577LHo3r173U4IANDIyVAAADVtVyl18803R8QHn/KNHz++2mnmLVu2jC5dusT48ePrdkIAgEZOhgIAqGm7SqkFCxZERMQRRxwRkydPjp133rlehgIAaEpkKACAmrarlNro0Ucfres5AACaPBkKAGCTWpVS69evj4kTJ8bDDz8cS5cujQ0bNlTb/sgjj9TJcAAATYkMBQCwSa1KqUsuuSQmTpwYX/nKV6JHjx6Ry+Xqei4AgCZHhgIA2KRWpdQ999wT9913Xxx33HF1PQ8AQJMlQwEAbLJDbR7UsmXL2Guvvep6FgCAJk2GAgDYpFal1GWXXRa33HJLZFlW1/MAADRZMhQAwCa1+vrejBkz4tFHH40HH3ww9t1332jRokW1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CxcujPPPP7/QozV6RUVFce2119Y4XZ/659gXjmNfOI59YTjun14yVP3x96owHPfCcewLx7EvHMf+k8tlWdP4/cY/+clPYvTo0bFkyZLo0aNH3HzzzXH44YcXeiwAgAZNhgIACqXJlFIAAAAANB6N/ppSAAAAADQ+SikAAAAAklNKAQAAAJCcUgoAAACA5JRS1LB8+fI466yzol27dtGuXbs466yz4u23397mxw8ZMiRyuVyMHTu23mZsirb3uK9bty6uvPLK6NmzZ+y4445RXl4e3/jGN2Lx4sXphm7EfvKTn0TXrl2jVatWcdBBB8X06dM/dv9p06bFQQcdFK1atYo999wzxo8fn2jSpmV7jvvkyZOjf//+seuuu0bbtm3jkEMOiYceeijhtE3L9v7Mb/T4449H8+bN44ADDqjfAaGRk58KR4ZKR34qHBmqcGSo+qWUooaBAwfG3Llz409/+lP86U9/irlz58ZZZ521TY994IEH4sknn4zy8vJ6nrLp2d7j/u6778YzzzwT11xzTTzzzDMxefLkmD9/fnz1q19NOHXjdO+998awYcNixIgRMWfOnDjssMPi2GOPjYULF252/wULFsRxxx0Xhx12WMyZMyf+67/+Ky6++OK4//77E0/euG3vcX/ssceif//+8cc//jFmz54dRxxxRJxwwgkxZ86cxJM3ftt77DdasWJFfOMb34gjjzwy0aTQeMlPhSNDpSE/FY4MVTgyVAIZfMgLL7yQRUT217/+Nb/2xBNPZBGR/eMf//jYx77++uvZZz7zmezvf/971rlz5+zmm2+u52mbjk9y3D/sqaeeyiIie+211+pjzCbjC1/4Qnb++edXW+vevXt21VVXbXb/4cOHZ927d6+2NmTIkOyLX/xivc3YFG3vcd+cffbZJ7vuuuvqerQmr7bH/vTTT8++853vZNdee222//771+OE0LjJT4UjQ6UjPxWODFU4MlT9c6YU1TzxxBPRrl276N27d37ti1/8YrRr1y5mzpy5xcdt2LAhzjrrrLjiiiti3333TTFqk1Lb4/5RK1asiFwuFzvttFM9TNk0rF27NmbPnh0DBgyotj5gwIAtHusnnniixv5HH310PP3007Fu3bp6m7Upqc1x/6gNGzbEqlWron379vUxYpNV22M/YcKEePnll+Paa6+t7xGh0ZOfCkeGSkN+KhwZqnBkqDSaF3oAGpbKysrYbbfdaqzvtttuUVlZucXH3XjjjdG8efO4+OKL63O8Jqu2x/3D3nvvvbjqqqti4MCB0bZt27oesclYtmxZrF+/PkpLS6utl5aWbvFYV1ZWbnb/999/P5YtWxYdO3ast3mbitoc94+66aab4p133onTTjutPkZssmpz7F966aW46qqrYvr06dG8uagAWyM/FY4MlYb8VDgyVOHIUGk4U+pToqKiInK53Mfenn766YiIyOVyNR6fZdlm1yMiZs+eHbfccktMnDhxi/t8WtXncf+wdevWxRlnnBEbNmyIn/zkJ3X+Ppqijx7XrR3rze2/uXU+3vYe943uvvvuqKioiHvvvXez//HB1m3rsV+/fn0MHDgwrrvuuvjsZz+bajxokOSnwpGhGib5qXBkqMKRoeqX6u5T4sILL4wzzjjjY/fp0qVLPPvss/H//X//X41t//rXv2o0xBtNnz49li5dGnvssUd+bf369XHZZZfF2LFj49VXX/1Eszdm9XncN1q3bl2cdtppsWDBgnjkkUd8wrcVu+yySzRr1qzGpxtLly7d4rEuKyvb7P7NmzePDh061NusTUltjvtG9957b5x77rnxm9/8Jo466qj6HLNJ2t5jv2rVqnj66adjzpw5ceGFF0bEB6f9Z1kWzZs3jylTpsSXv/zlJLNDoclPhSNDNSzyU+HIUIUjQ6WhlPqU2GWXXWKXXXbZ6n6HHHJIrFixIp566qn4whe+EBERTz75ZKxYsSL69Omz2cecddZZNf5P7uijj46zzjorvvnNb37y4Rux+jzuEZvC1EsvvRSPPvqof+C3QcuWLeOggw6KqVOnxsknn5xfnzp1apx44ombfcwhhxwSf/jDH6qtTZkyJXr16hUtWrSo13mbitoc94gPPt0755xz4u67746vfOUrKUZtcrb32Ldt2zaee+65ams/+clP4pFHHonf/va30bVr13qfGRoK+alwZKiGRX4qHBmqcGSoRApxdXUatmOOOSbbb7/9sieeeCJ74oknsp49e2bHH398tX0+97nPZZMnT97ic/jtMdtve4/7unXrsq9+9avZ7rvvns2dOzdbsmRJ/lZVVVWIt9Bo3HPPPVmLFi2yn//859kLL7yQDRs2LNtxxx2zV199NcuyLLvqqquys846K7//K6+8krVu3Tr79re/nb3wwgvZz3/+86xFixbZb3/720K9hUZpe4/7pEmTsubNm2c//vGPq/18v/3224V6C43W9h77j/KbY2Dr5KfCkaHSkJ8KR4YqHBmq/imlqOHNN9/MBg0alJWUlGQlJSXZoEGDsuXLl1fbJyKyCRMmbPE5hKrtt73HfcGCBVlEbPb26KOPJp+/sfnxj3+cde7cOWvZsmX2+c9/Pps2bVp+2+DBg7O+fftW2/8vf/lLduCBB2YtW7bMunTpkt12222JJ24atue49+3bd7M/34MHD04/eBOwvT/zHyZQwdbJT4UjQ6UjPxWODFU4MlT9ymXZ/7vaHAAAAAAk4rfvAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKagjuVwuHnjggYLO0KVLlxg7dmzBXn/ixImx0047Fez1abgqKirigAMO+Nh9zj777DjppJOSzPOXv/wlcrlcvP322xHhZxeAwujXr18MGzasIK/90X8Lm5JXX301crlczJ07NyKa9nuFxk4pBdtpS/9xvWTJkjj22GPTD1QgmyvATj/99Jg/f35hBqLRu+WWW2LixIkFeW0/uwA0ZZsrv/r06RNLliyJdu3aFWaohD5N7xUam+aFHgCairKyskKP8IllWRbr16+P5s1r938NxcXFUVxcXMdT1a21a9dGy5YtCz0Gm1HIoNgYfnYB4KPWrVsXLVq0qNVjW7Zs2STy67b4NL1XaGycKUWT9dvf/jZ69uwZxcXF0aFDhzjqqKPinXfeiYiICRMmxN577x2tWrWK7t27x09+8pNqj3399dfjjDPOiPbt28eOO+4YvXr1iieffDImTpwY1113Xfztb3+LXC4XuVwuf2bHR7++99xzz8WXv/zl/Ov/x3/8R6xevTq/feNXlX74wx9Gx44do0OHDnHBBRfEunXrtun9LV26NE444YQoLi6Orl27xq9//etq2z962nJExNtvvx25XC7+8pe/RMSmU5kfeuih6NWrVxQVFcX06dPj5ZdfjhNPPDFKS0ujTZs2cfDBB8ef//zn/PP069cvXnvttfj2t7+dPw4Rm/8K1G233Rb/9m//Fi1btozPfe5z8ctf/rLa9lwuFz/72c/i5JNPjtatW0e3bt3i97///TYdg/Xr18e5554bXbt2jeLi4vjc5z4Xt9xyS7V9Nh7nUaNGRXl5eXz2s5+NiIiZM2fGAQccEK1atYpevXrFAw88sNnTvB966KE48MADo7i4OL785S/H0qVL48EHH4y999472rZtG1//+tfj3Xffzb/en/70p/jSl74UO+20U3To0CGOP/74ePnll/Pbf/GLX0SbNm3ipZdeyq9ddNFF8dnPfjb/8/lxunTpEt/73vfiG9/4RrRp0yY6d+4c//M//xP/+te/4sQTT4w2bdpEz5494+mnn672uJkzZ8bhhx8excXF0alTp7j44ourvd6vfvWr6NWrV5SUlERZWVkMHDgwli5dmt++8Xg8/PDD0atXr2jdunX06dMnXnzxxW34k9rkpz/9aXTq1Clat24dp556arXT6D/69b0NGzbEjTfeGHvttVcUFRXFHnvsETfccENERHz5y1+OCy+8sNpzv/nmm1FUVBSPPPJIRERUVVXF8OHDo1OnTlFUVBTdunWLn//855ud66M/uxvPiPzlL38ZXbp0iXbt2sUZZ5wRq1atyu+zatWqGDRoUOy4447RsWPHuPnmmwv6NQwAGrZ33nkn/+93x44d46abbqq2fXOXgthpp53yWXNjtrvvvvuiX79+0apVq/jVr34Vb775Znz961+P3XffPVq3bh09e/aMu+++O/8cZ599dkybNi1uueWWfG579dVXN/uVtvvvvz/23XffKCoqii5dutSYsUuXLjFy5Mg455xzoqSkJPbYY4+4/fbbt+n9f3j+ww47LIqLi+Pggw+O+fPnx6xZs6JXr17Rpk2bOOaYY+Jf//pXtcduLbs/9dRTceCBB+Zz3Zw5c6pt/+h73doxi/gg71588cUxfPjwaN++fZSVlUVFRcU2vVdgO2TQBC1evDhr3rx5NmbMmGzBggXZs88+m/34xz/OVq1ald1+++1Zx44ds/vvvz975ZVXsvvvvz9r3759NnHixCzLsmzVqlXZnnvumR122GHZ9OnTs5deeim79957s5kzZ2bvvvtudtlll2X77rtvtmTJkmzJkiXZu+++m2VZlkVE9rvf/S7Lsix75513svLy8uyUU07Jnnvuuezhhx/Ounbtmg0ePDg/4+DBg7O2bdtm559/fjZv3rzsD3/4Q9a6devs9ttv36b3eOyxx2Y9evTIZs6cmT399NNZnz59suLi4uzmm2/OsizLFixYkEVENmfOnPxjli9fnkVE9uijj2ZZlmWPPvpoFhHZfvvtl02ZMiX75z//mS1btiybO3duNn78+OzZZ5/N5s+fn40YMSJr1apV9tprr2VZlmVvvvlmtvvuu2fXX399/jhkWZZNmDAha9euXf71Jk+enLVo0SL78Y9/nL344ovZTTfdlDVr1ix75JFH8vtERLb77rtnkyZNyl566aXs4osvztq0aZO9+eabWz0Ga9euzb773e9mTz31VPbKK69kv/rVr7LWrVtn9957b7Xj3KZNm+yss87K/v73v2fPPfdctnLlyqx9+/bZmWeemT3//PPZH//4x+yzn/1steO18dh88YtfzGbMmJE988wz2V577ZX17ds3GzBgQPbMM89kjz32WNahQ4fs+9//fv71fvvb32b3339/Nn/+/GzOnDnZCSeckPXs2TNbv359fp9TTz01O/jgg7N169ZlDz74YNaiRYvsqaee2qY/986dO2ft27fPxo8fn82fPz/7z//8z6ykpCQ75phjsvvuuy978cUXs5NOOinbe++9sw0bNmRZlmXPPvts1qZNm+zmm2/O5s+fnz3++OPZgQcemJ199tn55/35z3+e/fGPf8xefvnl7Iknnsi++MUvZscee2x++8bj0bt37+wvf/lL9vzzz2eHHXZY1qdPn22a+9prr8123HHH7Mtf/nI2Z86cbNq0adlee+2VDRw4sNqf1Yknnpi/P3z48GznnXfOJk6cmP3zn//Mpk+fnt1xxx1ZlmXZr3/962znnXfO3nvvvfz+t9xyS9alS5f8+z7ttNOyTp06ZZMnT85efvnl7M9//nN2zz33VHs/y5cvz7Ks5s/utddem7Vp0yb/d/ixxx7LysrKsv/6r//K73PeeedlnTt3zv785z9nzz33XHbyySdnJSUl2SWXXLJNxwSAT5f//M//zHbfffdsypQp2bPPPpsdf/zxWZs2bfL/bnw4S27Url27bMKECVmWbcp2Xbp0yefYN954I3v99dezH/zgB9mcOXOyl19+OfvRj36UNWvWLPvrX/+aZVmWvf3229khhxySfetb38rntvfff7/Gv4VPP/10tsMOO2TXX3999uKLL2YTJkzIiouL86+fZZtyyI9//OPspZdeykaNGpXtsMMO2bx587b6/jfO37179+xPf/pT9sILL2Rf/OIXs89//vNZv379quWt888/P/+4rWX31atXZ7vuumt2+umnZ3//+9+zP/zhD9mee+652Vy38b1u7ZhlWZb17ds3a9u2bVZRUZHNnz8/u+uuu7JcLpdNmTJlG//EgW2hlKJJmj17dhYR2auvvlpjW6dOnbJJkyZVW/vv//7v7JBDDsmyLMt++tOfZiUlJVssRa699tps//33r7H+4SBx++23ZzvvvHO2evXq/Pb/+7//y3bYYYessrIyy7IP/gO8c+fO2fvvv5/f59RTT81OP/30rb6/F198MYuIav9wzps3L4uIWpVSDzzwwFZfc5999sluvfXW/P3OnTvnX2ujj/6HfZ8+fbJvfetb1fY59dRTs+OOOy5/PyKy73znO/n7q1evznK5XPbggw9udabNGTp0aPbv//7v+fuDBw/OSktLs6qqqvzabbfdlnXo0CFbs2ZNfu2OO+7YbHj585//nN9n1KhRWURkL7/8cn5tyJAh2dFHH73FeZYuXZpFRPbcc8/l1956661s9913z/7zP/8zKy0tzb73ve9t8/vr3LlzduaZZ+bvL1myJIuI7JprrsmvPfHEE1lE5MvCs846K/uP//iPas8zffr0bIcddqh2DD7sqaeeyiIiW7VqVZZlmz8e//d//5dFxBaf48OuvfbarFmzZtmiRYvyaw8++GC2ww475Of8cCm1cuXKrKioKF9CfdR7772XtW/fvloBecABB2QVFRVZlm36OzJ16tTNPn5bSqnWrVtnK1euzK9dccUVWe/evfPztWjRIvvNb36T3/72229nrVu3VkoBUMOqVauyli1b5j8cybIPPuQrLi7e7lJq7NixW3294447Lrvsssvy9/v27Vvj36eP/ls4cODArH///tX2ueKKK7J99tknf/+jOWTDhg3Zbrvtlt12221bnWnj/D/72c/ya3fffXcWEdnDDz+cXxs1alT2uc99Ln9/W7J7+/bts3feeSe//bbbbvvYUmpzNnfMvvSlL1Xb5+CDD86uvPLKrb5XYNv5+h5N0v777x9HHnlk9OzZM0499dS44447Yvny5fGvf/0rFi1aFOeee260adMmf/ve976X/4rV3Llz48ADD4z27dvX+vXnzZsX+++/f+y44475tUMPPTQ2bNhQ7etO++67bzRr1ix/v2PHjtW+MvVxz9+8efPo1atXfq179+61/u1hH36eiA9OLx8+fHjss88+sdNOO0WbNm3iH//4RyxcuHC7nnfevHlx6KGHVls79NBDY968edXW9ttvv/z/3nHHHaOkpGSbjkNExPjx46NXr16x6667Rps2beKOO+6oMWfPnj2rXUfqxRdfjP322y9atWqVX/vCF76w2ef/8GylpaXRunXr2HPPPautfXjWl19+OQYOHBh77rlntG3bNrp27RoRUW2mnXfeOX7+85/nv9p41VVXbdN73dJMG9/jR9c2zjV79uyYOHFitZ/5o48+OjZs2BALFiyIiIg5c+bEiSeeGJ07d46SkpLo169fjbk/+todO3as9jpbs8cee8Tuu++ev3/IIYfU+Dux0bx586KqqiqOPPLIzT5XUVFRnHnmmXHnnXdGxAd/b//2t7/F2Wefnb/frFmz6Nu37zbNtjldunSJkpKS/P0P//185ZVXYt26ddV+btq1axef+9znav16ADRdL7/8cqxduzYOOeSQ/Fr79u1r9e/GR3Pb+vXr44Ybboj99tsvOnToEG3atIkpU6bUWW576aWXYv369fm1D2eBXC4XZWVl25wFPvr4LeWYjc+3Ldl9Y+5u3bp1/jk+fJw3Z1uP2Ydnjdj2rA5sOxc6p0lq1qxZTJ06NWbOnBlTpkyJW2+9NUaMGBF/+MMfIiLijjvuiN69e9d4TETUycWOsyzLX2fpoz68/tELU+ZyudiwYcM2Pf9Hn+ujdthhh2r7RsQWr1f14fIsIuKKK66Ihx56KH74wx/GXnvtFcXFxfG1r30t1q5du9XZPuqjM27u2NT2ONx3333x7W9/O2666aY45JBDoqSkJH7wgx/Ek08+WW2/j76/zc3w4eO0pdlyudxWZz3hhBOiU6dOcccdd0R5eXls2LAhevToUePYPfbYY9GsWbNYvHhxvPPOO9G2bdutvt8tzbSltY1zbdiwIYYMGRIXX3xxjefaY4894p133okBAwbEgAED4le/+lXsuuuusXDhwjj66KNrzP1xr7O9Nj5+cz/H2/L38LzzzosDDjggXn/99bjzzjvjyCOPjM6dO2/z47fm4/6st/R3cEs/RwB8um3Lvw+5XK7GfpvLbh/NNTfddFPcfPPNMXbs2OjZs2fsuOOOMWzYsO3Obduaj2qb2zb3+C3lmA9nmIiPz+61+bd3W4/ZJ32vwNY5U4omK5fLxaGHHhrXXXddzJkzJ1q2bBmPP/54fOYzn4lXXnkl9tprr2q3jWe07LfffjF37tx46623Nvu8LVu2rPZp0ebss88+MXfu3GoXkn788cdjhx12yF9o+5PYe++94/333692MesXX3yx2oUqd91114iIWLJkSX7twxc9/zjTp0+Ps88+O04++eTo2bNnlJWVxauvvlptn205DnvvvXfMmDGj2trMmTNj77333qY5tmXOPn36xNChQ+PAAw+Mvfbaq9pFxbeke/fu8eyzz0ZVVVV+7aMXBq+NN998M+bNmxff+c534sgjj4y99947li9fXmO/mTNnxujRo+MPf/hDtG3bNi666KJP/Nof5/Of/3w8//zzNX7m99prr2jZsmX84x//iGXLlsX3v//9OOyww6J79+718ingwoULY/Hixfn7TzzxxBb/TnTr1i2Ki4vj4Ycf3uLz9ezZM3r16hV33HFHTJo0Kc4555xq2zZs2BDTpk2r2zfx//zbv/1btGjRIp566qn82sqVK6tdwB4ANtprr72iRYsW8de//jW/tnz58pg/f37+/q677lott7300kvVfpnKlkyfPj1OPPHEOPPMM2P//fePPffcs8a/R9uaXzeX2z772c9WO7M/pdLS0q1m93322Sf+9re/xZo1a/KP+/Bx3pxtOWZAGkopmqQnn3wyRo4cGU8//XQsXLgwJk+eHP/6179i7733joqKihg1alTccsstMX/+/HjuuediwoQJMWbMmIiI+PrXvx5lZWVx0kknxeOPPx6vvPJK3H///fHEE09ExAdf6VmwYEHMnTs3li1bVq3Y2GjQoEHRqlWrGDx4cPz973+PRx99NC666KI466yz8qcpfxKf+9zn4phjjolvfetb8eSTT8bs2bPjvPPOq3Z2SHFxcXzxi1+M73//+/HCCy/EY489Ft/5zne26fn32muvmDx5cv4rUQMHDqzxqVCXLl3iscceizfeeCOWLVu22ee54oorYuLEiTF+/Ph46aWXYsyYMTF58uS4/PLLa//mPzLn008/HQ899FDMnz8/rrnmmpg1a9ZWH7fx/fzHf/xHzJs3L39WWMTHn322NTvvvHN06NAhbr/99vjnP/8ZjzzySFx66aXV9lm1alWcddZZcdFFF8Wxxx4bkyZNivvuuy9+85vf1Pp1t+bKK6+MJ554Ii644IKYO3duvPTSS/H73/8+X4btscce0bJly7j11lvjlVdeid///vfx3//933U+x8a/E3/7299i+vTpcfHFF8dpp5222V/R3KpVq7jyyitj+PDh8Ytf/CJefvnl+Otf/1rjt+edd9558f3vfz/Wr18fJ598cn69S5cuMXjw4DjnnHPigQceiAULFsRf/vKXuO++++rkvZSUlMTgwYPjiiuuiEcffTSef/75OOecc2KHHXb4RD9DADRNbdq0iXPPPTeuuOKKePjhh+Pvf/97nH322fkz2yM++M2y48aNi2eeeSaefvrpOP/882ucqbM5e+21V/4bAvPmzYshQ4ZEZWVltX26dOkSTz75ZLz66quxbNmyzZ7tc9lll8XDDz8c//3f/x3z58+Pu+66K8aNG1dnua22tpbdBw4cGDvssEOce+658cILL8Qf//jHfK7bkm05ZkAaSimapLZt28Zjjz0Wxx13XHz2s5+N73znO3HTTTfFscceG+edd1787Gc/i4kTJ0bPnj2jb9++MXHixPynLS1btowpU6bEbrvtFscdd1z07Nkzvv/97+c/Ifr3f//3OOaYY+KII46IXXfdtcavj42IaN26dTz00EPx1ltvxcEHHxxf+9rX4sgjj4xx48bV2XucMGFCdOrUKfr27RunnHJK/Md//Efstttu1fa58847Y926ddGrV6+45JJL4nvf+942PffNN98cO++8c/Tp0ydOOOGEOProo+Pzn/98tX2uv/76ePXVV+Pf/u3f8mdlfdRJJ50Ut9xyS/zgBz+IfffdN37605/GhAkT8tcr+qTOP//8OOWUU+L000+P3r17x5tvvhlDhw7d6uPatm0bf/jDH2Lu3LlxwAEHxIgRI+K73/1uRES160xtrx122CHuueeemD17dvTo0SO+/e1vxw9+8INq+1xyySWx4447xsiRIyPig+uK3XjjjXH++efHG2+8UevX/jj77bdfTJs2LV566aU47LDD4sADD4xrrrkmf02oXXfdNSZOnBi/+c1vYp999onvf//7Ww1ztbHXXnvFKaecEscdd1wMGDAgevToUeNXOn/YNddcE5dddll897vfjb333jtOP/30Gmdwff3rX4/mzZvHwIEDa/zZ3XbbbfG1r30thg4dGt27d49vfetb1c5e/KTGjBkThxxySBx//PFx1FFHxaGHHpr/ddUA8FE/+MEP4vDDD4+vfvWrcdRRR8WXvvSlOOigg/Lbb7rppujUqVMcfvjhMXDgwLj88surXSdpS665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M888Mzp06BCtW7eOAw44IGbPnp3fnmVZVFRURHl5eRQXF0e/fv3i+eefL+DEAACFJ0MBAA1dgy6lli9fHoceemi0aNEiHnzwwXjhhRfipptuip122im/z+jRo2PMmDExbty4mDVrVpSVlUX//v1j1apVhRscAKCAZCgAoDFoXugBPs6NN94YnTp1igkTJuTXunTpkv/fWZbF2LFjY8SIEXHKKadERMRdd90VpaWlMWnSpBgyZEjqkQEACk6GAgAagwZ9ptTvf//76NWrV5x66qmx2267xYEHHhh33HFHfvuCBQuisrIyBgwYkF8rKiqKvn37xsyZM7f4vFVVVbFy5cpqNwCApqI+MpT8BADUtQZdSr3yyitx2223Rbdu3eKhhx6K888/Py6++OL4xS9+ERERlZWVERFRWlpa7XGlpaX5bZszatSoaNeuXf7WqVOn+nsTAACJ1UeGkp8AgLrWoEupDRs2xOc///kYOXJkHHjggTFkyJD41re+Fbfddlu1/XK5XLX7WZbVWPuwq6++OlasWJG/LVq0qF7mBwAohPrIUPITAFDXGnQp1bFjx9hnn32qre29996xcOHCiIgoKyuLiKjxid7SpUtrfPL3YUVFRdG2bdtqNwCApqI+MpT8BADUtQZdSh166KHx4osvVlubP39+dO7cOSIiunbtGmVlZTF16tT89rVr18a0adOiT58+SWcFAGgoZCgAoDFo0L9979vf/nb06dMnRo4cGaeddlo89dRTcfvtt8ftt98eER+ccj5s2LAYOXJkdOvWLbp16xYjR46M1q1bx8CBAws8PQBAYchQAEBj0KBLqYMPPjh+97vfxdVXXx3XX399dO3aNcaOHRuDBg3K7zN8+PBYs2ZNDB06NJYvXx69e/eOKVOmRElJSQEnBwAoHBkKAGgMGnQpFRFx/PHHx/HHH7/F7blcLioqKqKioiLdUAAADZwMBQA0dA36mlIAAAAANE1KKQAAAACSq1Up1axZs1i6dGmN9TfffDOaNWv2iYcCAGiKZCgAgE1qVUplWbbZ9aqqqmjZsuUnGggAoKmSoQAANtmuC53/6Ec/iogPLoz5s5/9LNq0aZPftn79+njssceie/fudTshAEAjJ0MBANS0XaXUzTffHBEffMo3fvz4aqeZt2zZMrp06RLjx4+v2wkBABo5GQoAoKbtKqUWLFgQERFHHHFETJ48OXbeeed6GQoAoCmRoQAAatquUmqjRx99tK7nAABo8mQoAIBNalVKrV+/PiZOnBgPP/xwLF26NDZs2FBt+yOPPFInwwEANCUyFADAJrUqpS655JKYOHFifOUrX4kePXpELper67kAAJocGQoAYJNalVL33HNP3HfffXHcccfV9TwAAE2WDAUAsMkOtXlQy5YtY6+99qrrWQAAmjQZCgBgk1qVUpdddlnccsstkWVZXc8DANBkyVAAAJvU6ut7M2bMiEcffTQefPDB2HfffaNFixbVtk+ePLlOhgMAaEpkKACATWpVSu20005x8skn1/UsAABNmgwFALBJrUqpCRMm1PUcAABNngwFALBJra4pFRHx/vvvx5///Of46U9/GqtWrYqIiMWLF8fq1avrbDgAgKZGhgIA+ECtzpR67bXX4phjjomFCxdGVVVV9O/fP0pKSmL06NHx3nvvxfjx4+t6TgCARk+GAgDYpFZnSl1yySXRq1evWL58eRQXF+fXTz755Hj44YfrbDgAgKZEhgIA2KTWv33v8ccfj5YtW1Zb79y5c7zxxht1MhgAQFMjQwEAbFKrM6U2bNgQ69evr7H++uuvR0lJySceCgCgKZKhAAA2qVUp1b9//xg7dmz+fi6Xi9WrV8e1114bxx13XF3NBgDQpMhQAACb1OrrezfffHMcccQRsc8++8R7770XAwcOjJdeeil22WWXuPvuu+t6RgCAJkGGAgDYpFalVHl5ecydOzfuueeemD17dmzYsCHOPffcGDRoULWLdgIAsIkMBQCwSa1KqYiI4uLi+OY3vxnf/OY363IeAIAmTYYCAPhAra4pNWrUqLjzzjtrrN95551x4403fuKhAACaIhkKAGCTWpVSP/3pT6N79+411vfdd98YP378Jx4KAKApkqEAADapVSlVWVkZHTt2rLG+6667xpIlSz7xUAAATZEMBQCwSa1KqU6dOsXjjz9eY/3xxx+P8vLyTzwUAEBTJEMBAGxSqwudn3feeTFs2LBYt25dfPnLX46IiIcffjiGDx8el112WZ0OCADQVMhQAACb1KqUGj58eLz11lsxdOjQWLt2bUREtGrVKq688sq4+uqr63RAAICmQoYCANhku0up9evXx4wZM+LKK6+Ma665JubNmxfFxcXRrVu3KCoqqo8ZAQAaPRkKAKC67S6lmjVrFkcffXTMmzcvunbtGgcffHB9zAUA0KTIUAAA1dXqQuc9e/aMV155pa5nAQBo0mQoAIBNalVK3XDDDXH55ZfH//7v/8aSJUti5cqV1W4AANQkQwEAbFKrC50fc8wxERHx1a9+NXK5XH49y7LI5XKxfv36upkOAKAJkaEAADapVSn16KOP1vUcAABNngwFALBJrUqpvn371vUcAABNngwFALBJra4pFRExffr0OPPMM6NPnz7xxhtvRETEL3/5y5gxY0adDQcA0NTIUAAAH6hVKXX//ffH0UcfHcXFxfHMM89EVVVVRESsWrUqRo4cWacDAgA0FTIUAMAmtSqlvve978X48ePjjjvuiBYtWuTX+/TpE88880ydDQcA0JTIUAAAm9SqlHrxxRfj8MMPr7Hetm3bePvttz/pTAAATZIMBQCwSa1KqY4dO8Y///nPGuszZsyIPffc8xMPBQDQFMlQAACb1KqUGjJkSFxyySXx5JNPRi6Xi8WLF8evf/3ruPzyy2Po0KF1PSMAQJMgQwEAbNK8Ng8aPnx4rFy5Mo444oh477334vDDD4+ioqK4/PLL48ILL6zrGQEAmgQZCgBgk+0qpd5999244oor4oEHHoh169bFCSecEJdddllEROyzzz7Rpk2behkSAKAxk6EAAGrarlLq2muvjYkTJ8agQYOiuLg4Jk2aFBs2bIjf/OY39TUfAECjJ0MBANS0XaXU5MmT4+c//3mcccYZERExaNCgOPTQQ2P9+vXRrFmzehkQAKCxk6EAAGrargudL1q0KA477LD8/S984QvRvHnzWLx4cZ0PBgDQVMhQAAA1bVcptX79+mjZsmW1tebNm8f7779fp0MBADQlMhQAQE3b9fW9LMvi7LPPjqKiovzae++9F+eff37suOOO+bXJkyfX3YQAAI2cDAUAUNN2lVKDBw+usXbmmWfW2TAAAE2RDAUAUNN2lVITJkyorzkAAJosGQoAoKbtuqYUAAAAANQFpRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABIrlGVUqNGjYpcLhfDhg3Lr2VZFhUVFVFeXh7FxcXRr1+/eP755ws3JABAAyNDAQANUaMppWbNmhW333577LffftXWR48eHWPGjIlx48bFrFmzoqysLPr37x+rVq0q0KQAAA2HDAUANFSNopRavXp1DBo0KO64447Yeeed8+tZlsXYsWNjxIgRccopp0SPHj3irrvuinfffTcmTZq0xeerqqqKlStXVrsBADQ1dZmh5CcAoK41ilLqggsuiK985Stx1FFHVVtfsGBBVFZWxoABA/JrRUVF0bdv35g5c+YWn2/UqFHRrl27/K1Tp071NjsAQKHUZYaSnwCAutbgS6l77rknnnnmmRg1alSNbZWVlRERUVpaWm29tLQ0v21zrr766lixYkX+tmjRorodGgCgwOo6Q8lPAEBda17oAT7OokWL4pJLLokpU6ZEq1attrhfLperdj/LshprH1ZUVBRFRUV1NicAQENSHxlKfgIA6lqDPlNq9uzZsXTp0jjooIOiefPm0bx585g2bVr86Ec/iubNm+c/3fvoJ3pLly6t8ckfAMCnhQwFADQGDbqUOvLII+O5556LuXPn5m+9evWKQYMGxdy5c2PPPfeMsrKymDp1av4xa9eujWnTpkWfPn0KODkAQOHIUABAY9Cgv75XUlISPXr0qLa24447RocOHfLrw4YNi5EjR0a3bt2iW7duMXLkyGjdunUMHDiwECMDABScDAUANAYNupTaFsOHD481a9bE0KFDY/ny5dG7d++YMmVKlJSUFHo0AIAGS4YCAAqt0ZVSf/nLX6rdz+VyUVFRERUVFQWZBwCgMZChAICGpkFfUwoAAACApkkpBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAILkGXUqNGjUqDj744CgpKYnddtstTjrppHjxxRer7ZNlWVRUVER5eXkUFxdHv3794vnnny/QxAAAhSdDAQCNQYMupaZNmxYXXHBB/PWvf42pU6fG+++/HwMGDIh33nknv8/o0aNjzJgxMW7cuJg1a1aUlZVF//79Y9WqVQWcHACgcGQoAKAxaF7oAT7On/70p2r3J0yYELvttlvMnj07Dj/88MiyLMaOHRsjRoyIU045JSIi7rrrrigtLY1JkybFkCFDCjE2AEBByVAAQGPQoM+U+qgVK1ZERET79u0jImLBggVRWVkZAwYMyO9TVFQUffv2jZkzZ27xeaqqqmLlypXVbgAATVVdZCj5CQCoa42mlMqyLC699NL40pe+FD169IiIiMrKyoiIKC0trbZvaWlpftvmjBo1Ktq1a5e/derUqf4GBwAooLrKUPITAFDXGk0pdeGFF8azzz4bd999d41tuVyu2v0sy2qsfdjVV18dK1asyN8WLVpU5/MCADQEdZWh5CcAoK416GtKbXTRRRfF73//+3jsscdi9913z6+XlZVFxAef9nXs2DG/vnTp0hqf/H1YUVFRFBUV1d/AAAANQF1mKPkJAKhrDfpMqSzL4sILL4zJkyfHI488El27dq22vWvXrlFWVhZTp07Nr61duzamTZsWffr0ST0uAECDIEMBAI1Bgz5T6oILLohJkybF//zP/0RJSUn+Ggft2rWL4uLiyOVyMWzYsBg5cmR069YtunXrFiNHjozWrVvHwIEDCzw9AEBhyFAAQGPQoEup2267LSIi+vXrV219woQJcfbZZ0dExPDhw2PNmjUxdOjQWL58efTu3TumTJkSJSUliacFAGgYZCgAoDFo0KVUlmVb3SeXy0VFRUVU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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "==================================================\n", + "For cluster 0:\n" + ] + }, + { + "data": { + "text/plain": [ + "unknown 1.0\n", + "Name: target, dtype: float64" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "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", + "
featurech
31duration_median250175.825182
1section_duration_argmax_mean_car262552.009065
11section_distance_argmax_mean_car263103.437553
24mph_mean_walking264091.869648
\n", + "
" + ], + "text/plain": [ + " feature ch\n", + "31 duration_median 250175.825182\n", + "1 section_duration_argmax_mean_car 262552.009065\n", + "11 section_distance_argmax_mean_car 263103.437553\n", + "24 mph_mean_walking 264091.869648" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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0BzpoQAAdqvTg86/+c1vxmWXXRbvvvtunHbaaRER8dhjj8WECRPi8ssvb9ACAQCaCz0UAMBudQqlJkyYEO+8806MGzcutm/fHhERhx12WFx55ZUxceLEBi0QAKC50EMBAOy236HUzp0746mnnoorr7wyvv/978eyZcuioKAgunfvHtls9kDUCADQ5OmhAABq2u9QqkWLFnH66afHsmXLomvXrnHSSScdiLoAAJoVPRQAQE11un3v+OOPjzfffDO6du3a0PUAwEFn1apVUVlZme8ymqz27dvHUUcdle8y9okeqiY/+3W3bNmyfJcAAPVWp1Dq2muvjSuuuCL+4z/+Iz772c/G4YcfXmN5UVFRgxQHAM3dqlWromfP42Lbtq35LqXJKihoHa++uqxJBFN6qN387DeMd6u357sEAKizOoVSZ5xxRkREfPnLX45MJpMbT5IkMplM7Ny5s2GqA4BmrrKyMrZt2xr9/+XqKCo9Ot/lNDlVa1bGc3deE5WVlU0ilNJD7eZnv37WLH0m/vDQbbFjx458lwIAdVanUOqJJ55o6DoA4KBWVHp0tDvq2HyXwQGmh6rNz37dVK1Zme8SAKDe6hRKDRo0qKHrAABo9vRQAAC7HVLXFz755JNx3nnnxcCBA+PPf/5zRET893//dzz11FMNVhwAQHOjhwIAeE+dQqn7778/Tj/99CgoKIgXXnghqqurIyJi06ZNMXny5AYtEACgudBDAQDsVqdQ6oc//GHceuutcfvtt8ehhx6aGx84cGC88MILDVYcAEBzoocCANitTqHUa6+9Fqeeemqt8aKiotiwYUN9awIAaJb0UAAAu9UplCotLY0//vGPtcafeuqpOOaYY+pdFABAc6SHAgDYrU6h1IUXXhiXXnppPPfcc5HJZOLtt9+Oe++9N6644ooYN25cQ9cIANAs6KEAAHZrWZcXTZgwIaqqqmLIkCHxt7/9LU499dTIZrNxxRVXxMUXX9zQNQIANAt6KACA3fYrlNq6dWt897vfjQcffDDefffdGDFiRFx++eUREdGrV69o06bNASkSAKAp00MBANS2X6HU1VdfHdOnT49zzz03CgoKYsaMGbFr16749a9/faDqAwBo8vRQAAC17VcoNWvWrLjjjjvin/7pnyIi4txzz43Pf/7zsXPnzmjRosUBKRAAoKnTQwEA1LZfDzpfvXp1nHLKKbn5z33uc9GyZct4++23G7wwAIDmQg8FAFDbfoVSO3fujFatWtUYa9myZezYsaNBiwIAaE70UAAAte3X7XtJksSYMWMim83mxv72t7/F2LFj4/DDD8+NzZo1q+EqBABo4vRQAAC17VcoNXr06Fpj5513XoMVAwDQHOmhAABq269Qatq0aQeqDgCAZksPBQBQ2349UwoAAAAAGoJQCgAAAIDUCaUAAAAASJ1QCgAAAIDUCaUAAAAASJ1QCgAAAIDUCaUAAAAASJ1QCgAAAIDUCaUAAAAASJ1QCgAAAIDUCaUAAAAASJ1QCgAAAIDUCaUAAAAASJ1QCgAAAIDU5TWUWrBgQYwYMSI6duwYmUwmHnzwwRrLx4wZE5lMpsZ08skn56dYAIBGQg8FADQHeQ2ltmzZEieccEJMmTJlr+ucccYZsWbNmtz08MMPp1ghAEDjo4cCAJqDlvnc+fDhw2P48OEfuU42m42SkpKUKgIAaPz0UABAc9Donyk1b9686NChQ/To0SMuuOCCWLt27UeuX11dHVVVVTUmAICDjR4KAGjsGnUoNXz48Lj33nvj8ccfjxtuuCEWLVoUp512WlRXV+/1NeXl5dG2bdvc1Llz5xQrBgDIPz0UANAU5PX2vY9zzjnn5P67T58+0a9fv+jSpUv89re/jZEjR+7xNRMnTozx48fn5quqqjRVAMBBRQ8FADQFjTqU+rDS0tLo0qVLLF++fK/rZLPZyGazKVYFANC46aEAgMaoUd++92Hr1q2L1atXR2lpab5LAQBoMvRQAEBjlNcrpTZv3hx//OMfc/MrVqyIJUuWRLt27aJdu3ZRVlYWX/3qV6O0tDRWrlwZV111VbRv3z7OPvvsPFYNAJBfeigAoDnIayi1ePHiGDJkSG7+/ecYjB49OqZOnRpLly6Nu+++OzZs2BClpaUxZMiQuO+++6KwsDBfJQMA5J0eCgBoDvIaSg0ePDiSJNnr8kcffTTFagAAmgY9FADQHDSpZ0oBAAAA0DwIpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABIXV5DqQULFsSIESOiY8eOkclk4sEHH6yxPEmSKCsri44dO0ZBQUEMHjw4Xn755fwUCwDQSOihAIDmIK+h1JYtW+KEE06IKVOm7HH59ddfHzfeeGNMmTIlFi1aFCUlJTF06NDYtGlTypUCADQeeigAoDlomc+dDx8+PIYPH77HZUmSxM033xyTJk2KkSNHRkTEXXfdFcXFxTFjxoy48MIL9/i66urqqK6uzs1XVVU1fOEAAHmkhwIAmoNG+0ypFStWREVFRQwbNiw3ls1mY9CgQbFw4cK9vq68vDzatm2bmzp37pxGuQAAjYIeCgBoKhptKFVRUREREcXFxTXGi4uLc8v2ZOLEibFx48bctHr16gNaJwBAY6KHAgCairzevrcvMplMjfkkSWqNfVA2m41sNnugywIAaNT0UABAY9dor5QqKSmJiKj1jd7atWtrffMHAMB79FAAQFPRaEOprl27RklJScydOzc3tn379pg/f34MHDgwj5UBADReeigAoKnI6+17mzdvjj/+8Y+5+RUrVsSSJUuiXbt2cdRRR8Vll10WkydPju7du0f37t1j8uTJ0bp16xg1alQeqwYAyC89FADQHOQ1lFq8eHEMGTIkNz9+/PiIiBg9enRMnz49JkyYENu2bYtx48bF+vXro3///jFnzpwoLCzMV8kAAHmnhwIAmoO8hlKDBw+OJEn2ujyTyURZWVmUlZWlVxQAQCOnhwIAmoNG+0wpAAAAAJovoRQAAAAAqcvr7XvNxapVq6KysjLfZTRp1dXVkc1m811Gk7Rs2bJ8lwAAAOwnv0fWn98j66d9+/Zx1FFH5bUGoVQ9rVq1Knr2PC62bdua71Katkwm4iOejcHHe7d6e75LAAAA9oHfIxuI3yPrpaCgdbz66rK8BlNCqXqqrKyMbdu2Rv9/uTqKSo/OdzlN0pqlz8QfHrotPj3qyjiya898l9PkvH/8duzYke9SAACAfeD3yPrze2T9VK1ZGc/deU1UVlYKpZqDotKjo91Rx+a7jCapas3KiIho0+Eox7AO3j9+AABA0+L3yLrze2Tz4EHnAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6hp1KFVWVhaZTKbGVFJSku+yAAAaNT0UANAUtMx3AR+nd+/e8bvf/S4336JFizxWAwDQNOihAIDGrtGHUi1bttyvb/aqq6ujuro6N19VVXUgygIAaNT0UABAY9eob9+LiFi+fHl07NgxunbtGv/0T/8Ub7755keuX15eHm3bts1NnTt3TqlSAIDGQw8FADR2jTqU6t+/f9x9993x6KOPxu233x4VFRUxcODAWLdu3V5fM3HixNi4cWNuWr16dYoVAwDknx4KAGgKGvXte8OHD8/99/HHHx8DBgyIv/u7v4u77rorxo8fv8fXZLPZyGazaZUIANDo6KEAgKagUV8p9WGHH354HH/88bF8+fJ8lwIA0GTooQCAxqhJhVLV1dWxbNmyKC0tzXcpAABNhh4KAGiMGnUodcUVV8T8+fNjxYoV8dxzz8U//uM/RlVVVYwePTrfpQEANFp6KACgKWjUz5T605/+FP/8z/8clZWVceSRR8bJJ58czz77bHTp0iXfpQEANFp6KACgKWjUodTMmTPzXQIAQJOjhwIAmoJGffseAAAAAM2TUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA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1y4OP/zw6NevXzz33HMxffr0uOaaa+J///d/cz3B+33Gh/uQpUuXxmmnnZbb/7/+67/G5s2bc8vHjBkTX/nKV+I///M/o7S0NI444oi46KKL4t13392n97d27doYMWJEFBQURNeuXePee++tsfzDt+JHRGzYsCEymUzMmzcvInaf3x999NHo169fZLPZePLJJ+ONN96Is846K4qLi6NNmzZx0kknxe9+97vcdgYPHhxvvfVWfOc738kdh4g93743derU+Lu/+7to1apVHHvssfHf//3fNZZnMpn4xS9+EWeffXa0bt06unfvHg899NA+HYOdO3fGN77xjejatWsUFBTEscceG7fcckuNdd4/zuXl5dGxY8fo0aNHREQsXLgwPv3pT+d6nwcffHCPjy549NFH48QTT4yCgoI47bTTYu3atfHII4/EcccdF0VFRfHP//zPsXXr1tz+Zs+eHV/4whfiE5/4RBxxxBHxD//wD/HGG2/klt99993Rpk2bWL58eW7skksuiR49euR+Pj/K0UcfHT/84Q9zPXGXLl3i//7f/xt//etf46yzzoo2bdrE8ccfH4sXL67xuoULF8app54aBQUF0blz5/j2t79dY3/33HNP9OvXLwoLC6OkpCRGjRoVa9euzS1//3g89thj0a9fv2jdunUMHDgwXnvttX34pN7z0EMPRb9+/eKwww6L9u3bx8iRI/d7/x/+WYUGlQB8hG9961tJp06dkjlz5iQvvfRS8g//8A9JmzZtkksvvTRJkiSJiOSBBx6o8Zq2bdsm06ZNS5IkSVasWJFERHL00Ucn999/f/Lmm28mf/7zn5M//elPyY9//OPkxRdfTN54443kJz/5SdKiRYvk2WefTZIkSTZs2JAMGDAgueCCC5I1a9Yka9asSXbs2JE88cQTSUQk69evT5IkSRYvXpwccsghyb//+78nr732WjJt2rSkoKAgt/8kSZIuXbok7dq1S376058my5cvT8rLy5NDDjkkWbZs2ce+//fr79mzZzJ79uzklVdeSU4++eTkM5/5TDJ48ODkqaeeSl544YWkW7duydixY3Ovu+2225LS0tLce77//vuTdu3aJdOnT0+SJEk2b96cHHnkkck555yT/OEPf0h+85vfJMccc0wSEcmLL76YJElS671+3DFLkiQZNGhQUlRUlJSVlSWvv/56ctdddyWZTCaZM2fOPn7iAFA3b7/9dtKyZcvkxhtvTFasWJG89NJLyU9/+tNk06ZNH3te3LRpU3LMMcckp5xySvLkk08my5cvT+67775k4cKFydatW5PLL7886d27d64n2Lp1a5IkNfuQLVu2JB07dkxGjhyZLF26NHnssceSrl27JqNHj87VOHr06KSoqCgZO3ZssmzZsuQ3v/lN0rp16+S2227bp/c4fPjwpE+fPsnChQuTxYsXJwMHDkwKCgqSm266KUmS3X3D++fyJEmS9evXJxGRPPHEE0mS7D6/9+3bN5kzZ07yxz/+MamsrEyWLFmS3HrrrclLL72UvP7668mkSZOSww47LHnrrbeSJEmSdevWJZ06dUr+/d//PXcckiRJpk2blrRt2za3v1mzZiWHHnpo8tOf/jR57bXXkhtuuCFp0aJF8vjjj+fWiYikU6dOyYwZM5Lly5cn3/72t5M2bdok69at+9hjsH379uQHP/hB8vvf/z558803k3vuuSdp3bp1ct9999U4zm3atEnOP//85A9/+EOydOnSpKqqKmnXrl1y3nnnJS+//HLy8MMPJz169Nhj73PyySfX6LEGDRqUDBs2LHnhhReSBQsWJEcccURy3XXX5fb3P//zP8n999+fvP7668mLL76YjBgxIjn++OOTnTt35tb52te+lpx00knJu+++mzzyyCPJoYcemvz+97/fp8/9/V7y1ltvTV5//fXkW9/6VlJYWJicccYZya9+9avktddeS77yla8kxx13XLJr164kSZLkpZdeStq0aZPcdNNNyeuvv548/fTTyYknnpiMGTMmt9077rgjefjhh5M33ngjeeaZZ5KTTz45GT58eG75+8ejf//+ybx585KXX345OeWUU5KBAwfuU93/7//9v6RFixbJD37wg+SVV15JlixZklx77bX7vf8P/6xCQxJKAXu1adOmpFWrVsnMmTNzY+vWrUsKCgr2O5S6+eabP3Z/Z555ZnL55Zfn5gcNGpTbz/s+HNSMGjUqGTp0aI11vvvd7ya9evXKzXfp0iU577zzcvO7du1KOnTokEydOvVja3q//l/84he5sV/+8pdJRCSPPfZYbqy8vDw59thjc/OdO3dOZsyYUWNb//Ef/5EMGDAgSZIk+fnPf560a9cu2bJlS2751KlTPzKU2pM9HbMvfOELNdY56aSTkiuvvPJj3ysA1Mfzzz+fRESycuXKWsv25bxYWFi411Dk6quvTk444YRa4x/sQ2677bbkk5/8ZLJ58+bc8t/+9rfJIYccklRUVCRJ8l5Y0qVLl2THjh25db72ta8l55xzzse+v9deey2JiBpfBi1btiyJiDqFUg8++ODH7rNXr17Jf/3Xf+Xmu3TpktvX+z4cSg0cODC54IILaqzzta99LTnzzDNz8xGRfO9738vNb968OclkMskjjzzysTXtybhx45KvfvWrufnRo0cnxcXFSXV1dW5s6tSpyRFHHJFs27YtN3b77bfvsff53e9+l1unvLw8iYjkjTfeyI1deOGFyemnn77XetauXZtERLJ06dLc2DvvvJN06tQp+da3vpUUFxcnP/zhD/f5/X24l1yzZk0SEcn3v//93NgzzzyTREQuLDz//POTf/3Xf62xnSeffDI55JBDahyDD/r973+fRESyadOmJEn2fDx++9vfJhGx12180IABA5Jzzz13n9/n3va/Lz+rUFdu3wP26o033ojt27fHgAEDcmPt2rWLY489dr+31a9fvxrzO3fujGuvvTb69u0bRxxxRLRp0ybmzJkTq1at2q/tLlu2LD7/+c/XGPv85z8fy5cvj507d+bG+vbtm/vvTCYTJSUlNS5P/jgffH1xcXFERBx//PE1xt7f3l//+tdYvXp1fOMb34g2bdrkph/+8Ie5S8mXLVsWJ5xwQrRu3Tq3jQ8e5z3Z12P2wVojIkpLS/frvQJAXZxwwgnxxS9+MY4//vj42te+FrfffnusX79+n86LS5YsiRNPPDHatWtX5/2/f249/PDDc2Of//znY9euXTVud+rdu3e0aNEiN7+v58lly5ZFy5Yta/Q0PXv2rPNfvvtwb7Rly5aYMGFC9OrVKz7xiU9EmzZt4tVXX22w3mjZsmU1xj7YLxx++OFRWFi4z/3CrbfeGv369Ysjjzwy2rRpE7fffnutOo8//vgaz5F67bXXom/fvnHYYYflxj73uc/tcfsf7rtat24dxxxzTI2xD9b6xhtvxKhRo+KYY46JoqKi6Nq1a0REjZo++clPxh133JG7tfHf/u3f9um97q2m99/jh8fer+v555+P6dOn1/iZP/3002PXrl2xYsWKiIh48cUX46yzzoouXbpEYWFhDB48uFbdH953aWlpjf18lCVLlsQXv/jFvS7f1/1/+GcVGpInlAF7lSTJx66TyWRqrben5zJ8sEGMiLjhhhvipptuiptvvjmOP/74OPzww+Oyyy6L7du373eN7z9T4aPq/vCD1TOZTOzatWuf9/PB17+/vw+Pvb+99//39ttvj/79+9fYzvtN8L4c2w/b12NW3/cKAHXRokWLmDt3bixcuDDmzJkT//Vf/xWTJk2K3/zmNxHx0efFhnhQ9556gvd9cLyu58n3z91720dExCGHHFJj3Yg990URtXuj7373u/Hoo4/Gf/7nf0a3bt2ioKAg/vEf/3G/e6M91binY1PX4/CrX/0qvvOd78QNN9wQAwYMiMLCwvjxj38czz33XI31Pvz+9rVn+3BtmUzmY2sdMWJEdO7cOW6//fbo2LFj7Nq1K/r06VPr2C1YsCBatGgRb7/9dmzZsiWKioo+9v3uraa9jX2wH7zwwgvj29/+dq1tHXXUUbFly5YYNmxYDBs2LO6555448sgjY9WqVXH66ad/ZG/34f18lI/6d7U/+//wZwkNyZVSwF5169YtDj300Hj22WdzY+vXr6/xZ4ePPPLIWLNmTW5++fLlNR48uTdPPvlknHXWWXHeeefFCSecEMccc0yNh09GvPfX5z54tdOe9OrVK5566qkaYwsXLowePXrU+BY0TcXFxfGpT30q3nzzzejWrVuN6f1v7nr16hX/+7//G9u2bcu97oPHeU/25ZgBQD5lMpn4/Oc/H9dcc028+OKL0apVq3j66ac/9rzYt2/fWLJkSbzzzjt73O6+9gRLliyp8SDpp59+Og455JDcg7br47jjjosdO3bUeJj1a6+9VuOPrxx55JERETV6ow8+9PyjPPnkkzFmzJg4++yz4/jjj4+SkpJYuXJljXX25Tgcd9xxe+yNjjvuuH2qY1/qHDhwYIwbNy5OPPHE6NatW42Hiu9Nz54946WXXorq6urc2IcfDF4X69ati2XLlsX3vve9+OIXvxjHHXdcrF+/vtZ6CxcujOuvvz5+85vfRFFRUVxyySX13vdH+cxnPhMvv/xyrZ/5bt26RatWreLVV1+NysrKuO666+KUU06Jnj17NviV7X379o3HHntsj8vS2D/sC6EUsFdt2rSJb3zjG/Hd7343HnvssfjDH/4QY8aMyX0LGBFx2mmnxZQpU+KFF16IxYsXx9ixY2t9m7Un3bp1y32bumzZsrjwwgujoqKixjpHH310PPfcc7Fy5cqorKzc4zdCl19+eTz22GPxH//xH/H666/HXXfdFVOmTIkrrrii/gegHsrKyqK8vDxuueWWeP3112Pp0qUxbdq0uPHGGyMiYtSoUXHIIYfEN77xjXjllVfi4Ycfjv/8z//8yG3uyzEDgHx57rnnYvLkybF48eJYtWpVzJo1K/7617/Gcccd97HnxX/+53+OkpKS+MpXvhJPP/10vPnmm3H//ffHM888ExHv9QQrVqyIJUuWRGVlZY1g433nnntuHHbYYTF69Oj4wx/+EE888URccsklcf755+duraqPY489Ns4444y44IIL4rnnnovnn38+vvnNb9a4GqWgoCBOPvnkuO666+KVV16JBQsWxPe+97192n63bt1i1qxZsWTJkvjf//3fGDVqVK3e5+ijj44FCxbEn//856isrNzjdr773e/G9OnT49Zbb43ly5fHjTfeGLNmzWqw3qhbt26xePHiePTRR+P111+P73//+7Fo0aKPfd377+df//VfY9myZbmrwiI++uqzj/PJT34yjjjiiLjtttvij3/8Yzz++OMxfvz4Guts2rQpzj///Ljkkkti+PDhMWPGjPjVr34Vv/71r+u8349z5ZVXxjPPPBMXXXRRLFmyJJYvXx4PPfRQLgw76qijolWrVvFf//Vf8eabb8ZDDz0U//Ef/9GgNVx99dXxy1/+Mq6++upYtmxZLF26NK6//vrU9g/7QigFfKQf//jHceqpp8aXv/zl+NKXvhRf+MIX4rOf/Wxu+Q033BCdO3eOU089NUaNGhVXXHFFjeck7c33v//9+MxnPhOnn356DB48ONeIftAVV1wRLVq0iF69euUuKf6wz3zmM/GrX/0qZs6cGX369Ikf/OAH8e///u8xZsyY+r71evnmN78Zv/jFL2L69Olx/PHHx6BBg2L69Om5b4TbtGkTv/nNb+KVV16JE088MSZNmhQ/+tGPPnKb+3LMACBfioqKYsGCBXHmmWdGjx494nvf+17ccMMNMXz48I89L7Zq1SrmzJkTHTp0iDPPPDOOP/74uO6663JXPX/1q1+NM844I4YMGRJHHnlk/PKXv6y1/9atW8ejjz4a77zzTpx00knxj//4j/HFL34xpkyZ0mDvcdq0adG5c+cYNGhQjBw5Mv71X/81OnToUGOdO++8M959993o169fXHrppfHDH/5wn7Z90003xSc/+ckYOHBgjBgxIk4//fT4zGc+U2Odf//3f4+VK1fG3/3d3+Wuyvqwr3zlK3HLLbfEj3/84+jdu3f8/Oc/j2nTpuWeF1RfY8eOjZEjR8Y555wT/fv3j3Xr1sW4ceM+9nVFRUXxm9/8JpYsWRKf/vSnY9KkSfGDH/wgIqLGc6b21yGHHBIzZ86M559/Pvr06RPf+c534sc//nGNdS699NI4/PDDY/LkyRHx3nPFfvSjH8XYsWPjz3/+c533/VH69u0b8+fPj+XLl8cpp5wSJ554Ynz/+9/PPRPqyCOPjOnTp8evf/3r6NWrV1x33XUf+wXl/ho8eHD8+te/joceeig+/elPx2mnnZa7zTKN/cO+yCR1ebAJAAAA1MO9994bX//612Pjxo0N8lwxoOnxoHMAAAAOuLvvvjuOOeaY+NSnPhX/+7//G1deeWX8n//zfwRScBBz+x5wUJs8eXKNP9X7wWn48OH5Lg8ASMmTTz65156gTZs2+S4vNWPHjt3rMRg7dmy9tl1RURHnnXdeHHfccfGd73wnvva1r8Vtt93WQJXXTVP+3Hv37r3Xuu+99958lwf7xO17wEHtnXfe2etf+ikoKIhPfepTKVcEAOTDtm3bPvL5Qt26dUuxmvxZu3ZtVFVV7XFZUVFRrWdoNXVN+XN/66234t13393jsuLi4igsLEy5Ith/QikAAAAAUuf2PQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABS1zLfBRxou3btirfffjsKCwsjk8nkuxwAoIlJkiQ2bdoUHTt2jEMOOXi+z3v/fQMA1NXHZTHNPpR6++23o3PnzvkuAwBo4lavXh2dOnXKdxmpqaqqik984hP5LgMAaMI2bNgQbdu23evyZh9KFRYWRsR7jWRRUVGeqwEAmpqqqqro3Llzrqc42OihAID99X7/9HGafSj1/mViRUVFGioAoM4OtscA6KEAgPr6uP7p4HkwAgAAAACNhlAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABIXct8FwANYdWqVVFZWZnvMg5a7du3j6OOOirfZQAAAE2E3+HyrzH8HieUoslbtWpV9Ox5XGzbtjXfpRy0Cgpax6uvLsv7/6EBAACNn9/hGofG8HucUIomr7KyMrZt2xr9/+XqKCo9Ot/lHHSq1qyM5+68JiorK4VSAADAx/I7XP41lt/jhFI0G0WlR0e7o47NdxkAAADsA7/D4UHnAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKQur6HU1KlTo2/fvlFUVBRFRUUxYMCAeOSRR3LLx4wZE5lMpsZ08skn57FiAAAAABpCy3zuvFOnTnHddddFt27dIiLirrvuirPOOitefPHF6N27d0REnHHGGTFt2rTca1q1apWXWgEAAABoOHkNpUaMGFFj/tprr42pU6fGs88+mwulstlslJSU5KM8AAAAAA6QRvNMqZ07d8bMmTNjy5YtMWDAgNz4vHnzokOHDtGjR4+44IILYu3atR+5nerq6qiqqqoxAQAAANC45D2UWrp0abRp0yay2WyMHTs2HnjggejVq1dERAwfPjzuvffeePzxx+OGG26IRYsWxWmnnRbV1dV73V55eXm0bds2N3Xu3DmttwIAAADAPsrr7XsREccee2wsWbIkNmzYEPfff3+MHj065s+fH7169Ypzzjknt16fPn2iX79+0aVLl/jtb38bI0eO3OP2Jk6cGOPHj8/NV1VVCaYAAAAAGpm8h1KtWrXKPei8X79+sWjRorjlllvi5z//ea11S0tLo0uXLrF8+fK9bi+bzUY2mz1g9QIAAABQf3m/fe/DkiTZ6+1569ati9WrV0dpaWnKVQEAAADQkPJ6pdRVV10Vw4cPj86dO8emTZti5syZMW/evJg9e3Zs3rw5ysrK4qtf/WqUlpbGypUr46qrror27dvH2Wefnc+yAQAAAKinvIZSf/nLX+L888+PNWvWRNu2baNv374xe/bsGDp0aGzbti2WLl0ad999d2zYsCFKS0tjyJAhcd9990VhYWE+ywYAAACgnvIaSt1xxx17XVZQUBCPPvpoitUAAAAAkJZG90wpAAAAAJo/oRQAAAAAqRNKAQAAAJA6oRQAAAAA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Gz/77LPjscce2+ftXHTRRXHPPffEjBkzorCwMCoqKqKioiK2bdsWEe/dtnfZZZfF5MmT44EHHog//OEPMWbMmGjdunWMGjWqLqUDAORNQ/VQAADNQZ3/+t7TTz8drVq1qjHepUuX+POf/7zP25k6dWpERAwePLjG+LRp02LMmDERETFhwoTYtm1bjBs3LtavXx/9+/ePOXPmRGFhYV1KBwDIm4bqoQAAmoM6hVK7du2KnTt31hr/05/+tF9hUZIkH7tOJpOJsrKyKCsr258SAQAanYbqoQAAmoM63b43dOjQuPnmm3PzmUwmNm/eHFdffXWceeaZDVUbAECzoocCANitTldK3XTTTTFkyJDo1atX/O1vf4tRo0bF8uXLo3379vHLX/6yoWsEAGgW9FAAALvVKZTq2LFjLFmyJGbOnBnPP/987Nq1K77xjW/EueeeW+OhnQAA7KaHAgDYrU6hVEREQUFBfP3rX4+vf/3rDVkPAECzpocCAHhPnZ4pVV5eHnfeeWet8TvvvDN+9KMf1bsoAIDmSA8FALBbnUKpn//859GzZ89a4717945bb7213kUBADRHeigAgN3qFEpVVFREaWlprfEjjzwy1qxZU++iAACaIz0UAMBudQqlOnfuHE8//XSt8aeffjo6duxY76IAAJojPRQAwG51etD5N7/5zbjsssvi3XffjdNOOy0iIh577LGYMGFCXH755Q1aIABAc6GHAgDYrU6h1IQJE+Kdd96JcePGxfbt2yMi4rDDDosrr7wyJk6c2KAFAgA0F3ooAIDd9juU2rlzZzz11FNx5ZVXxve///1YtmxZFBQURPfu3SObzR6IGgEAmjw9FABATfsdSrVo0SJOP/30WLZsWXTt2jVOOumkA1EXAECzoocCAKipTg86P/744+PNN99s6FoAAJo1PRQAwG51CqWuvfbauOKKK+L//b//F2vWrImqqqoaEwAAtemhAAB2q9ODzs8444yIiPjyl78cmUwmN54kSWQymdi5c2fDVAcA0IzooQAAdqtTKPXEE080dB0AAM2eHgoAYLc6hVKDBg1q6DoAAJo9PRQAwG51eqZURMSTTz4Z5513XgwcODD+/Oc/R0TEf//3f8dTTz3VYMUBADQ3eigAgPfUKZS6//774/TTT4+CgoJ44YUXorq6OiIiNm3aFJMnT27QAgEAmgs9FADA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XlkfHwCAG/XZZ5+pUaNGkqRTp05pz549atGihWPxlIf5Xbp84/gNGzZo27Zteu6551SzZk21bNlS06ZNU926dRUVFSXp8pe9ZGZm6vnnn1d4eLiky7Vccby8vLRo0SINHjxY3bp108aNG0v1Yd6VgoKCFBoaqs8//1yxsbGSLn8zc3Jystq2bXtdrwmAb98DrrFt2zZNnz5d27dv15EjR7R8+XJ99913ioqK0uTJkzVjxgz96U9/0p49e7Rz504tXLhQs2bNkiQ9/PDDqlevnvr166fNmzfrwIEDev/997V161ZJl79t7uDBg0pJSVFmZqbOnz9/zfGHDBkiHx8fDRs2TP/617+0YcMGjRo1SkOHDnWfDn4jmjdvrl69eumxxx7Ttm3blJSUpEcffbTIpsbLL7+sd955R7t379aePXv07rvvql69eu5L/iIjI7V+/XplZGTo1KlTki5f0rZ8+XKlpKToq6++0uDBg0v0qdmVisvns88+q7fffluTJ0/W119/rdTUVC1btkwTJ04s9rVvueUW5eTk6LXXXtOBAwe0aNEivfHGG8Xu16JFC3Xv3l0jR47U559/ruTkZI0cOfKaM6quR0lyFh8fr/DwcE2cOFGzZs2SmenJJ5+8oeMWZciQIapdu7b69u2rxMREHTx4UJs2bdKYMWN07Ngxd9yLFi1Samqqtm3bpiFDhvykTbInnnhCp0+f1kMPPaTt27dr7969WrRokfty1rI+PgAAN+q5557T+vXr9a9//UvDhw9X7dq1Hf3GtvIwv0uXm1Iff/yxXC6XWrZs6V63ePHifJfuNWrUSNWqVXPXbStWrNDUqVNLdIwqVapo8eLFatOmjbp166aMjIzrjnfUqFGaMWOG/u///k9paWkaM2aMTp06dcM1IHAzoykFXCUwMFCffPKJ+vTpo2bNmmnixImaOXOmevfurUcffVRvvvmmEhIS1Lp1a8XFxSkhIUGNGzeWdPlMqDVr1qhu3brq06ePWrdureeff959ed8vfvEL9erVS3fddZfq1KmjpUuXXnN8Pz8/rV69WidPnlSHDh00cOBA3X333frzn//8k73HhQsXKjw8XHFxcRowYIBGjhypunXrFrp9jRo19MILL6h9+/bq0KGDDh06pFWrVrnPMJo5c6bWrl2r8PBw3XHHHZIuN7Jq1aqlmJgY3X///erZs2e++zCVRHH57Nmzp/7xj39o7dq16tChgzp37qxZs2YpIiKi2Ndu27atZs2apRdeeEG33XabFi9erBkzZpQorrfffluhoaH6+c9/rv79++uxxx5TQEBAsZcMFqe4nL399ttatWqVFi1aJG9vb/n5+Wnx4sV68803tWrVqhs6dmH8/Pz0ySefqFGjRhowYICioqL0yCOP6Ny5c+5PVhcsWKBTp07pjjvu0NChQzV69Ogif55KKyQkRP/85z+VnZ2tuLg4RUdHa968ee6zpsr6+AAA3Kjnn39eY8aMUXR0tNLT07VixQpVq1bNsXjKw/wuXb6vlCTFxcW5GztxcXG6dOlSvqZUnTp1lJCQoHfffVctW7bU888/r5deeqnEx/H29tbSpUvVqlUrdevWrVT367rS73//ez388MP61a9+pS5duqhGjRrq2bPnDdeAwM3MZVwECwA35NixYwoPD9e6det09913Ox0OAAAoJzZu3Ki77rpLp06dKvJLZVAx5ebmKioqSg8++GCJz9wCkB/3lAKAUso7a6d169ZKT0/XU089pcjISPenfQAAAKh8Dh8+rDVr1iguLk7nz5/Xn//8Zx08eFCDBw92OjSgwuLyPaCSSUxMdH+1b0HLzWLx4sWF5qBVq1Y39NoXL17U//7v/6pVq1bq37+/6tSpo40bNxZ4E25PKmrcExMTHY2tKPHx8YXGHR8f73R4AAA4ivm9/PDy8lJCQoI6dOigrl27aufOnVq3bp37huwASo/L94BK5ty5c/rmm28Kff56vqmuIsrKytK3335b4HNVq1Yt0X2nKpp9+/YV+lyDBg3K7c2/jx8/rtOnTxf4XGBgIPeHAgDc1JjfAVRmNKUAAAAAAADgcVy+BwAAAAAAAI+jKQUAAAAAAACPoykFAAAAAAAAj6MpBQAAAAAAAI+jKQUAAAAAAACPoykFAAAAAAAAj6MpBQAAAAAAAI/7f0pcqttxI7oWAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "==================================================\n" + ] + } + ], "source": [ "## TRIP SUMMARIES\n", "\n", @@ -749,12 +1679,63 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "id": "a8723e3d", "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For cluster -1:\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/4x/l9lw50rn7qvf79m01f21x70mlpd6gh/T/ipykernel_35596/2042025115.py:34: RuntimeWarning: Mean of empty slice\n", + " oc[cix][feature] = np.nanmean([ic[x].get(feature, np.nan) for x in oix])\n" + ] + }, + { + "data": { + "image/png": "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XrfmzMxMDRkyRHfccYc6dOigTZs2OdZde8Zv6dKlat++vaTLZ2GaNWum4cOHq02bNlq8eLEWLFig1q1bq3nz5mrWrJm++OILSdLLL7+s48ePq1evXmrWrJl27typhIQEjRo1SpKUk5OjUaNGKTIyUpGRkfrLX/6izMxMSdKAAQMUFxenTp066Y477lDPnj0d6wrTt29ftWzZUk2aNFG3bt0cQa6gmtetW6fGjRurSZMm+stf/qK6des65jksLEwTJkxQ27ZtFRoaqvfff1+vv/66WrVqpfr16+ubb76RdDmYxcbGqmXLlmrUqJH69OmjixcvSpJeeeUV9ejRQ8YYZWRkKCoqSgsXLiy09rwan376aTVu3FgtWrTQDz/84Pi9iomJ0fnz5yVJWVlZGjNmjFq1aqVmzZrp8ccf15kzZySp0J9F3uuaNGmS2rZtq/DwcP31r3+97nzmPdfAgQMVFRWlli1b6vvvv3fUe/UZwH//+9+6++671bRpUzVr1kybNm3Sq6++qiFDhji2OXPmjKpVq6ZTp05JKvi/gasdOnRI1apVczy+3u/49X6eAICSiwxFhiJDkaFwCzMAXGLRokUmJibG8fi3334z69evN127djWXLl0yxhizdu1a06RJE2OMMfPmzTP33HOPOXv2rDHGmFOnTpns7GyzevVqExUV5XTsunXrmt27dxtjjGnVqpV56623jDHG7N+/31SpUsUcOXLEGGOMJDN9+nRjjDF79+41FStWNFlZWYXW/MYbb5iYmBiTmZlpLly4YKKioswjjzxijDFm7ty5jn8bY8y//vUvEx0dbYwxZvXq1cZms5l169Y51qempprc3FxjjDHJycmmZs2aJjMzM1/9xhgzceJEM3LkSGOMMTNnzjTt27c3ly5dMllZWaZLly4mKSnJGGNM//79TZs2bczFixdNdna2adu2rVmwYMH1fgzm119/dfx78uTJZujQoQXWfOnSJVOrVi2zdu1aY8zln58kR51169Y1o0aNMsYYs3nzZuPr62v+8Y9/GGOMWbhwoWnTpo0xxpjc3FyTmprq+PfTTz9tXn31VcfjBx54wLz66qsmLi7ODBky5Lq1r1692nh5eZkdO3YYY4yJi4sztWrVMkePHjXGGNOlSxfHz/6VV14x/+///T/Hvi+//LIZPnz4Tf0s4uPjjTHGnDx50gQEBJhjx45dtyZJZvXq1Y7X3rBhQ8e6vN/Vffv2maCgILNv3z5jjDGZmZnmzJkz5vTp06ZGjRrmzJkzxhhjXnvtNTNo0CBjzM39N5CcnGyqVq3qqKew3/Eb/TwBACUXGYoMRYYiQ+HW5eWpZhhQ1jRt2lQ//fST4uLiFB0dra5du+qf//ynvv/+e7Vu3dqx3a+//qrMzEwtXbpUzzzzjAICAiRJlStXvuFznDt3Tjt37tTgwYMlSREREfrDH/6g9evX689//rMkOT6fftddd8nLy0spKSmqXbt2gcdbvXq1+vfvr/Lly6t8+fLq27ev1q9ff1Ov94477tAf/vAHx+Pk5GT16dNHx44dk5eXl1JTU3X48GHdfvvt1z3OypUrNXjwYNntdknSU089pdmzZ+v555+XJPXs2VO+vr6SpFatWt3wvhAffPCB3nvvPWVkZCg9PV3BwcEF1rxv3z75+vrqvvvukyQ9/PDDqlSpktOxHnvsMUlSixYtlJ6erkcffVSSFBUVpYMHD0qSjDGaNm2a/v3vfys7O1tnz55Vu3btJF0+I/X++++refPmqly5stNZ1MLceeedatasmeN5Dx8+7Pj5Xf28S5YsUVpamj799FNJl8/Y5n084UY/i7zfkerVq6tevXpKTk5WrVq1Cq3p9ttvd5zhffTRR/U///M/On78uNM2K1asUNeuXXXHHXdIksqXL6/AwEBJ0iOPPKJ58+Zp+PDhmjVrlj755BNJKtZ/A1fXf/Xv+KlTp2748wQAlExkKDIUGYoMhVsXTSnARerVq6e9e/dq1apVWrlypUaPHq3OnTtr0KBBevnll13yHMYYSZf/UF/t6sc+Pj6Of5crV+66n/vPO15BvLy8lJOT43h86dIlp/UVK1Z0evz444/rtdde00MPPSRJqlKlSr59CqvBVa9n/fr1mjFjhjZs2KDq1avr888/d5r7q2su6Hmvlffc5cqVy/c4r44FCxZozZo1Wrt2rfz9/fXGG29o7dq1jmMcPnxYubm5SktL04ULF5xez/WeM+95rn2cnp7uqH/mzJm6//778x3jRj+LosxpYW40d1cbPny4HnroIdWvX19BQUFq3rx5kZ/vagXVfzM/TwBAyUSGIkORoQpGhsKtgHtKAS5y7Ngx2Ww29ejRQ6+99pqMMerXr5/+7//+T0ePHpUk5ebmauvWrZKkHj16aNasWUpLS5N0+XPiOTk5CggI0NmzZwt8joCAADVr1kzz58+XJB04cEDffvut7r333mLV3LFjR7333nvKzs5Wenq6FixY4FhXv359ff/997p06ZKys7Od1hXk9OnTCgsLkyS9//77On36tFPdhb2mmJgYzZs3T5mZmcrOztY777yjTp06Fev1nD59WgEBAapSpYoyMzP11ltvFbptgwYNdOHCBX377beSpH/+85+O+wkU9TmrVq0qf39/nTt3TvPmzXOsS0tL05///Gf93//9n4YMGaInnnjiuiG2KHr06KGpU6c67h9w8eJF7dmzx1FTYT+L4vj5558dIfHTTz9VrVq1VLNmTadtYmNj9eWXX2r//v2SLt9DIe9n3qBBA4WFhemZZ57RsGHDnF5DQf8NFIerfp4AAOuRochQZCgyFG5dNKUAF9m9e7fatm2rJk2aqEWLFurXr5/atWunxMRE/fGPf1TTpk0VGRnpuEljv3799NBDD6lNmzZq1qyZunbtqoyMDDVp0kR33nmnIiMjHTfpvNoHH3yg999/X02bNtUjjzyi//3f/1WdOnWKVfP//M//KDQ0VA0bNtSDDz7ouGxXktq0aaPY2FhFRkbqgQceuOE317z++ut6+OGH9Yc//EHff/+9QkNDHeuGDx+ugQMHOm7SeW0NTZs2VYsWLdSsWTOFhYVp+PDhxXo9Xbp00e23364GDRooNjbWcQl3Qex2uxYsWKCnn35arVq10oYNGxQUFOS4XPpmPfHEEzp//rwaNmyonj17Os3h4MGD1bt3b91///164YUXZIxRUlJSsV7btcaMGaNmzZqpdevWatKkie655x7H3F7vZ1EczZo100cffaSWLVtq8uTJBYbr22+/Xe+8847+/Oc/q0mTJmrVqpX27dvnWP/UU08pOzvb6cavhf03UByu+nkCAKxHhiJDkaHIULh12YyrWs4AUMqcO3dO/v7+kq7cG+LQoUO67Tb69a4WFxenmjVr6qWXXnLbc/DzBADAGvzNtQ4ZCmUd95QCcMv67LPPNG3aNOXm5sput+vDDz/kj6+LHT9+XPfff7+qVKmiKVOmuPW5+HkCAGAN/ua6HxkKtwqulAJuAS1btsx3I8ZGjRrpgw8+8FBFv8/LL7+sRYsW5Rv/7LPPbniJfEnQo0cPHTlyxGmscuXKWr16tYcqKpk1AQDgaWSokqUk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6rXXXtN3332nLl26qGrVqurYsaO2bt16w31/+eUXSdLdd9+db44WLlyYb378/Pyc7r8AAABKDytyWh6bzaavv/5asbGxSkpKUosWLVS9enUNHz5c586du+H+Rc1wN3tlU17Wy7ti6mqnTp2SzWZTpUqVbupYADyDj+8BKFS5cuXUsWNHffnllzp27NhNNWPsdrsyMjLyjRcUFqTCz14VNF6tWjX5+vrq3XffLXCfatWq3bC+36N69eqSpGPHjhV5Xx8fnwLnJTU11aluLy8vjRgxQiNGjNCZM2e0cuVKvfjii4qNjdXRo0ev++14ecf59NNPVbdu3RvWxJlDAABKr+LktGvlXfl9bUa5tkkkXb55+DvvvCPp8tXjH3/8sRISEpSZmanZs2df93mKmuFuNqPUr19fvr6+2r17d751u3fv1u233879pIASjiulAFzX2LFjZYzRU089pczMzHzrs7Ky9K9//cvxOCwsTLt27XLaZtWqVTp//vzvrqVbt246cOCAqlatqpYtW+ZbbuaeUNfKuwHnzVw9dccdd6h+/fp69913C2wwXU9B87J//37t27ev0H0qVaqkXr16aejQoTp16pQOHTp03ZpjY2Pl5eWlAwcOFDg/efdwAAAAZUNRc9q18rLTtRnl888/v+7z3nHHHRo/frwaN26s7du3O8YLuyLdHRlOunwyr3v37lq0aJHTFVtHjhzR6tWrne55BaBk4kopANfVpk0bzZo1S3FxcYqKitIzzzyjRo0aKSsrSzt27NCcOXMUGRmp7t27S5L69eunl156SRMmTFB0dLT27t2rGTNmKDAw8HfXEh8fr88++0zt2rXTc889pyZNmig3N1dHjhzR8uXLNXLkSLVu3bpIx2zcuLEk6fXXX1f//v1Vvnx53XnnnU73orraP/7xD3Xv3l333HOPnnvuOYWGhurIkSNatmyZPvjgg0Kfp1+/furbt6/i4uL0yCOP6PDhw0pKSnJcfZWne/fuioyMVMuWLVW9enUdPnxY06dPV926dRUREXHdmsPCwvTyyy9r3LhxOnjwoB544AFVrlxZv/zyizZv3qwKFSpo0qRJRZofAABQchU1p10rODhYnTp10uTJk1W5cmXVrVtXX3/9tRYtWuS03a5duzRs2DD96U9/UkREhLy9vbVq1Srt2rVLY8aMcWzXuHFjffTRR1q4cKHq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vnx58+mnn3rqJZRKRZ33BQsWGC8vL/OPf/zD6ff7zJkznnoJpVZR5/5afHMMcGPkJ88hQ1mD/OQ5ZCjPIUO5H00p5PPbb7+ZPn36GH9/f+Pv72/69OljTp8+7bSNJDN37txCj0GoKrqizntycrKRVOCyevVqy+svbf7xj3+YunXrGm9vb9OiRQuzZs0ax7r+/fub6Ohop+2/+eYb07x5c+Pt7W3CwsLMrFmzLK64bCjKvEdHRxf4+92/f3/rCy8Divo7fzUCFXBj5CfPIUNZh/zkOWQozyFDuZfNmP//bnMAAAAAAACARfj2PQAAAAAAAFiOphQAAAAAAAAsR1MKAAAAAAAAlqMpBQAAAAAAAMvRlAIAAAAAAIDlaEoBAAAAAADAcjSlAAAAAAAAYDmaUgAAAAAAALAcTSkAZUqzZs2Unp5u2fN17dpVBw4cKHBd+/bttXTpUstqAQAAKA7yEwBP8fJ0AQDgSjt37rT0+b744gtLnw8AAMDVyE8APIUrpQCUKTabTefPn1dubq6GDRumBg0aqGnTpoqKitKlS5cK3W/AgAF66qmn1LFjRzVo0EADBgxQRkaGJGnBggVq3bq1mjdvrmbNmjkFqbCwMP3www+SpL1796p169Zq0aKF+vTpc93nAwAAKCnITwA8hSulAJRJ33//vb7++mvt3btXt912m86ePStvb+/r7rNp0yZt2LBBvr6+evjhh/X6669r9OjRio2N1Z///GfZbDYdOnRIbdu21eHDh1W+fHmn/fv166fhw4erf//++u6773Tvvfe68yUCAAC4FPkJgNW4UgpAmVSvXj1lZWVp0KBBmj9/vrKysnTbbdd/y3vsscdUsWJFlStXToMGDdLKlSslScnJyerSpYsiIyP10EMPKTU1VYcPH3baNy0tTT/88IP69esnSbrnnnvUuHFj97w4AAAANyA/AbAaTSkAZVJgYKD27Nmj3r1766efflKTJk30888/F+kYNptNkvT444/r6aef1g8//KCdO3eqYsWKBV5anrc9AABAaUR+AmA1mlIAyqRff/1VFy5cUOfOnZWYmKiwsDDt3bv3uvt88sknunDhgnJycjR37lx16tRJknT69GmFhYVJkt5//32dPn06374BAQGKjIzUBx98IEnavHmzdu/e7doXBQAA4EbkJwBW455SAMqko0eP6qmnnlJWVpZy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fv00adIkdevWTTU1Ndq3b5/WrVunKVOmqE+fPvU6Z3x8vCTpn//8p1JTU9W8eXNdfvnlbvei+q1nnnlGgwcP1lVXXaVJkyapY8eO2rdvn/79739r2bJlZ/x1Ro0apZEjRyotLU3/+Z//qb1792revHmuq69OGTx4sOLi4pSQkKCLL75Ye/fuVW5urqKiohQbG3vWmTt16qQ5c+ZoxowZ+vbbb3XjjTeqTZs2+vHHH7Vt2za1bNlSs2fPrtf+AACAxqu+Oe33wsLCdMMNNyg7O1tt2rRRVFSUNmzYoNWrV7sd9+mnn2rChAm64447FBsbq4CAAG3cuFGffvqppk2b5jouPj5eK1eu1KpVqxQTE6PAwEDFx8d7JcOdMnv2bF155ZW65ZZbNG3aNB07dkwzZ85U+/btNWXKlAadE4CFDACcg8LCQpOammo6duxoAgICTMuWLU3Pnj3NzJkzTUlJieu4yspKk5GRYSIjI01QUJBJSkoyhYWFJioqyqSmprqOW7x4sZFktm/fXufXSkpKMl27dj3tHEeOHDEPP/ywufzyy01AQIAJCQkx8fHxZtKkSaa4uNh1nCRz33331Xn97+cwxpjp06ebiIgI06xZMyPJbNq06ax78cEHH5ibbrrJhISEGKfTaS677DIzadKkOu+tqKjItVZTU2PmzZtnYmJiTGBgoElISDAbN240SUlJJikpyXXck08+aRITE0379u1NQECA6dixoxk7dqz57rvvznnmNWvWmP79+5vWrVsbp9NpoqKizO23327eeecd1zGpqammZcuWZ32fAACgaTjXnPb73GGMMQcPHjS33367adu2rQkJCTEjR440O3bsMJLM4sWLjTHG/Pjjj2b06NGmc+fOpmXLlqZVq1amW7du5qmnnjJVVVWuc3333XcmJSXFBAcHG0kmKirK9dz5Zriz2bFjh7n++utNixYtTOvWrc2tt95qvv7663qdA4A9HMYYY18lBgAAAAAAgAsR95QCAAAAAACA5SilAAAAAAAAYDlKKQAAAAAAAFjO1lJq8+bNGjx4sCIiIuRwOLRmzRq3540xyszMVEREhIKCgpScnKxdu3a5HVNZWam///3vat++vVq2bKkhQ4bowIEDFr4LAAAAa5GhAACAL7C1lPr111/VvXt35eXlnfb5efPmKScnR3l5edq+fbvCwsI0YMAAlZeX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fNrXZGdna/bs2XXWIyMjvTLjKTtf/odXzw8AwIUsKSnJq+cvLy9XSEiIV38NK9U3Q5GfAADwPXbnpyZfSp3icDjcHhtj6qydMn36dE2ePNn1uKamRocOHVK7du3O+JoLVVlZmSIjI7V//361bt3a7nEuKOy9fdh7+7D39mDfz84Yo/LyckVERNg9ileca4YiP9UPf67swb7bh723D3tvH/b+zM41PzX5Uqp9+/by8/Or84leSUlJnU/+TnE6nXI6nW5rF110kbdG9AmtW7fmD5lN2Hv7sPf2Ye/twb6fmS9dIXVKfTMU+alh+HNlD/bdPuy9fdh7+7D3p3cu+anJ3+g8ICBAvXr10vr1693W169fr8TERJumAgAAaNzIUAAAwG5N/kopSZo8ebJGjRqlhIQEXX311Xruuee0b98+jR8/3u7RAAAAGi0yFAAAsJNPlFLDhg3Tzz//rDlz5ujgwYOKi4vT2rVrFRUVZfdoTZ7T6dSsWbPqXK4P72Pv7cPe24e9twf7fuEiQ3kPf67swb7bh723D3tvH/b+/DmMr/18YwAAAAAAADR6Tf6eUgAAAAAAAGh6KKUAAAAAAABgOUopAAAAAAAAWI5SCgAAAAAAAJajlAIAAAAAAIDlKKWgBQsWKDo6WoGBgerVq5fee++9sx5fWVmpGTNmKCoqSk6nU5dddplefPFFi6b1LfXd+2XLlql79+5q0aKFwsPDNWbMGP38888WTesbNm/erMGDBysiIkIOh0Nr1qz5w9fk5+erV69eCgwMVExMjBYtWuT9QX1Qffd+9erVGjBggC6++GK1bt1aV199tf79739bM6yPaci/96e8//778vf3V48ePbw2H9AUkZ/sQ36yBxnKPmQoe5CfrEEpdYFbtWqV0tPTNWPGDBUUFKhv37666aabtG/fvjO+ZujQodqwYYNeeOEF7dmzRytWrFDnzp0tnNo31Hfvt2zZorvuuktjx47Vrl279Morr2j79u265557LJ68afv111/VvXt35eXlndPxRUVFGjRokPr27auCggI99NBDmjhxol577TUvT+p76rv3mzdv1oABA7R27Vrt3LlT/fv31+DBg1VQUODlSX1Pfff+lNLSUt111126/vrrvTQZ0DSRn+xDfrIPGco+ZCh7kJ8sYnBB6927txk/frzbWufOnc20adNOe/xbb71lQkJC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7q1u3bpp/PjxOnHixDnPDAAAvI/8dGbkJ+DCQCkFwCMCAwP10Ucfae3atZo4caKqqqokSVOnTtX27dtVWFio//7v/9akSZMkSS+//LI6deqkzz77TJ9++qlb8Pm9yspK3XnnnZo/f762bdumfv36ad++fW7H7Nu3Txs3bqzzCd/dd9+tJUuWuB4vWbJEI0aMUPPmzfX444+rVatW2rZtmwoLC9W1a1fNmjXLdeyWLVv06quvateuXXr77bd1+PBh7d69W5988olWrlzZoH3Kzs7WN998ox07duiTTz7RSy+9JElavny5vvzyS33wwQf6+OOP9be//U0TJkxwve6jjz7S0qVLtXv3bl1yySV69tlnXeebMmWKCgsL9fnnn+vOO++UJE2ZMkX9+vXTtm3b9Mknn6iqqsoV7AAAQONAfjo35CfAd/HtewA84tQ9CK644gr5+/uruLhYHTp00Lp16zR//nyVl5erpqZGZWVlkqSrrrpKTz31lKZMmaKkpCQNHDjwjOfes2ePWrRooeTkZEnS0KFD9V//9V9ux4wZM0YOh6POaxMTE3XixAnt2LFDvXr10tKlS133KlizZo3Kysr06quvSjr5Kdxll13meu3QoUPVqlUrSVL37t31f//3f0pLS1NSUpIGDRrUoH1688039eSTT8rpdEqSLr74Ytcsp2aUpOrqavn5+bled9NNN6lt27aSpKuvvlqfffaZJKl///569NFH9fXXX+u6667Ttdde6zrfhx9+6AqrFRUVCggIaNDMAADAO8hP54b8BPguSikAHhEYGOj6Zz8/P1VVVWnfvn2aOHGitm3bppiYGH366ae67rrrJJ0MBoWFhXrnnXf02muv6eGHH1ZBQYFbkDjlt5ean8mp8HM6o0eP1pIlS1RaWqpLLrlEcXFxrvMuWLDANdPZzhkTE6Pdu3dr48aNeuedd5SRkaHCwkK1adPmD2c7F8YYPfzww7r77rtP+/zp9leS0tPTNWTIEG3YsEEPPfSQ4uLitGDBAhljtGbNGsXExHhkPgAA4Hnkp/NDfgKaPr59D4DXlJaWKiAgQGFhYTLGuF3+XFRUpFatWmno0KGaP3++vvzyyzP+BJrOnTuroqJCmzdvliS9+uqrKi0tPec5UlNT9corr2jRokVu914YMmSIcnJydPToUUnS0aNHtWvXrtOe48CBA3I4HBoyZIieeOIJGWNc9yyojyFDhig3N1eVlZWSTt4b4tT6ggULXPc6OHHihAoKCv7wfHv27FFMTIzuvfdePfTQQ/rwww9d5/vHP/7hCl+HDx/W119/Xe95AQCAtchPdZGfAN/FlVIAvCY+Pl533HGHunbtqo4dO2rAgAGu5959913l5OTIz89P1dXVevzxxxUSEnLa8zidTq1YsUJpaWkKCgpScnKyOnbseM5zhIeHKyEhQW+++aaef/551/q0adM0e/Zs9enTx3Xp+tSpU9W1a9c65/jss880bdo0GWNUU1OjUaNGqVu3buc8wylTp07VjBkz1LNnTwUEBCgiIkJr167VqFGj9PPPPys5OVkOh0NVVVUaO3asevbsedbzzZ8/X5s2bVJAQID8/Pxcl5vn5uZq6tSp6tGjh5o1a6bmzZtr7ty5+tOf/lTvmQEAgHXIT3WRnwDf5TDncl0nAAAAAAAA4EF8+x4AAAAAAAAsx7fvAWg0/vWvf532x+7Onz9fffv2tWGis1u7dq0eeuihOuvTp0/XsGHDbJgIAABcaMhPAJoyvn0PAAAAAAAAluPb9wAAAAAAAGA5SikAAAAAAABYjlIKAAAAAAAAlqOUAgAAAAAAgOUopQAAAAAAAGA5SikAAAAAAABYjlIKAAAAAAAAlvv/u6/mEuFJIU0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==================================================\n", + "For cluster 0:\n" + ] + }, + { + "data": { + "image/png": "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t5KzJCcn6y9/+Yu+/vprDRo0SAEBARowYIC2b99+xX2PHTsmSbr99turrNGyZcuqrI+3t7f8/Pycch4AAMDxzMhmF1gsFq1fv15xcXFKT0/XbbfdplatWumZZ55RUVHRFfevbW6rKRNeatasWXbH69ChQ53OD0D9wNf3ANTIzc1NAwYM0Oeff64jR45cVTPGarWqtLS0yvgvv/xS7fzqfmmvpvGWLVvKy8tL7733XrX7tGzZ8or1XYtWrVpJko4cOVLrfT09Patdl+PHj9vV7e7urgkTJmjChAn69ddftW7dOr3wwguKi4vT4cOHL/vreBeO8/HHHys0NPSKNdW09gAAoH6qSza71IW7vS/NJZc2iSQpNDRU7777rqTzd4x/+OGHSklJUVlZmebNm3fZz6ltbrvaXPI///M/GjJkiO11dQ97B9Bw0JQCcFnJycn67LPP9Ic//EF/+9vf5OHhYff+uXPntHr1asXHx0s6/yssu3btspuzYcMGFRcXX3MtQ4YMUWpqqgICAhz2LIULQeZq7p66+eab1aFDB7333nuaMGFCrUJQdeuyb98+7d27t8Zm2g033KChQ4fqp59+UlJSkg4cOKDOnTvXWHNcXJzc3d31448/8rU8AAAaqdpms0tdeB7lrl277J5b+cknn1z2c2+++WZNmzZNy5cv13fffWcbr+kudGfkNkkKDg5WcHCww44HwLVoSgG4rDvvvFNvvfWWEhMT1bNnT/3xj39Uly5ddO7cOeXm5mr+/PmKiIiwBZ8RI0boxRdf1PTp0xUVFaXvv/9eWVlZ8vf3v+ZakpKStHz5cvXr10/jx49Xt27dVFlZqUOHDik7O1sTJ05Unz59anXMrl27SpJef/11JSQkqGnTpurYsaPds6h+680331R8fLzuuOMOjR8/XiEhITp06JDWrFmj999/v8bPGTFihIYPH67ExEQ99NBDOnjwoNLT0213X10QHx+viIgI9erVS61atdLBgweVmZmp0NBQhYeHX7bmdu3aadasWZo6dar279+ve++9V82bN9exY8f07bffysfHRzNnzqzV+gAAgPqlttnsUkFBQRo4cKDS0tLUvHlzhYaGav369VqxYoXdvF27dmncuHF6+OGHFR4eLg8PD23YsEG7du3SlClTbPO6du2qpUuXatmyZWrfvr08PT3VtWtXp+S2Kzlz5ow+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gQOyWCx2dz3t379fjz32mIKDg2W1WhUYGKgBAwZo586dks7nmz179ignJ8eWSdq1a2fbv7a5bd68ebrllltktVq1aNGiWq9Nkyb87y3Q0HCnFIAaVVRUaMOGDerZs6fatm3rlM8YPXq07rvvPi1evFinT59W06ZNJUlHjx7V8OHDNXnyZKWmpqpJkyY6c+aMoqKidOTIEb3wwgvq1q2b9uzZo+nTp2v37t1at26d3V1W//d//6dt27Zp1qxZatasmdLT0/XAAw9o7969at++vZ588kmdOHFCc+bM0YoVK9S6dWtJUufOnWusd82aNYqPj9ctt9yijIwMhYSE6MCBA8rOznbIeqSnpyslJUXTpk1Tv379dO7cOf2///f/bF/Vu1LNqampmjZtmkaNGqVp06aprKxMr7zyivr27atvv/3W7tzKysp0//33a+zYsZoyZYrKy8sdcg4AAMA5zMhmvzV48GBVVFQoPT1dISEhOn78uLZs2WLLJStXrtTQoUPl7++vuXPnSpKtUVbb3LZq1Sp9+eWXmj59uoKCgnTjjTc6/fwAuB5NKQA1On78uM6cOaOwsDCnfcaAAQP09ttvVxk/ceKEPvroI91zzz22sT//+c/atWuXvvnmG/Xq1cu2/0033aShQ4dq9erVGjRokG1+SUmJ1q1bJ19fX0nSbbfdpuDgYH344YeaMmWK2rRpo5CQEElSjx497K7s1eTpp59WSEiIvvnmG3l6etrGR40aVafzv9RXX32lrl272t1tFhcXZ/vny9V8+PBhzZgxQ+PGjdMbb7xhG4+JiVF4eLhmzpypZcuW2cbPnTun6dOnO6x2AADgXGZkswt++eUX7d27V5mZmRo+fLht/MEHH7T9c48ePeTl5SU/Pz/dcccddvu/8cYbtcptxcXF2r17t5o3b+7kMwNQn3B/IwCXeuihh6odb968uV1DSpI+/fRTRURE6NZbb1V5eblti4uLq/Y29P79+9saUpIUGBioG2+8UQcPHqxTrfv27dOPP/6oMWPG2DWkHKl37976xz/+ocTERK1Zs0aFhYVXve+aNWtUXl6uJ554wm59PD09FRUVVe3XEmtafwAAcH1r0aKFOnTooFdeeUUZGRnKzc1VZWXlVe9f29x2zz33XFVDqrKy0u54FRUVtT01APUITSkANWrZsqW8vb2Vl5fntM+48PWzqxk/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BKAx4zOlAASEbdu2afHixdqxY4fatm2r9957T/Pnz1fTpk31hz/8QX/729/UqlUrDRo0SK1bt77ktZo2ber8dUhIiBwOhyTJMAzZbDa34+tbu5QWLVp4dLyn1wcAALgc5CcAjR13SgEICOXl5YqMjNQ111yjs2fP6uWXX3a+Nn78eOXn5ysvL+83bz2/lD59+ujgwYP67LPPJElr1qzRddddp5iYmAbPiYyMVEVFhUdf56233tJPP/0kh8OhvLw8DRo0yOuZAQAAGkJ+AtDYUUoBCAh33323brjhBnXq1ElDhgxRjx49nK/16tVLklRSUqKUlBSvv0bbtm31+uuvKy0tTTfffLOWLl2qN99885LnPPbYY5o/f77zgzovR//+/fXAAw+oS5cuatWqlZ544gmvZwYAAGgI+QlAY2czDMOweggAuFqMHTtWSUlJmjJlitWjAAAABATyExC8uFMKAAAAAAAApuNOKQBBadKkSdq1a5fb+s6dOxUeHu7RtdavX69nnnnGbX327NkaNWqU1zMCAAA0JuQnAGajlAIAAAAAAIDp+Od7AAAAAAAAMB2lFAAAAAAAAExHKQUAAAAAAADTUUoBAAAAAADAdJRSAAAAAAAAMB2lFAAAAAAAAExHKQUAAAAAAADT/R9FkjIFMLShVwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==================================================\n" + ] + } + ], "source": [ "ic, oc = dict(), dict()\n", "\n", @@ -869,210 +1850,210 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "id": "d0288db8", "metadata": {}, "outputs": [], "source": [ - "from sklearn.cluster import AffinityPropagation\n", + "# from sklearn.cluster import AffinityPropagation\n", "\n", - "best_score = -np.inf\n", - "best_params = None" + "# best_score = -np.inf\n", + "# best_params = None" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "id": "1b14ad0c", "metadata": {}, "outputs": [], "source": [ - "cls = AffinityPropagation(random_state=13210).fit(target_df)\n", - "labels = cls.labels_\n", + "# cls = AffinityPropagation(random_state=13210).fit(target_df)\n", + "# labels = cls.labels_\n", "\n", - "print(labels)" + "# print(labels)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "id": "2562bbb6-66eb-4283-8c08-6e20a0b2ade5", "metadata": {}, "outputs": [], "source": [ - "center_embeddings = cls.cluster_centers_\n", - "centers_proj = PCA(n_components=2).fit_transform(center_embeddings)" + "# center_embeddings = cls.cluster_centers_\n", + "# centers_proj = PCA(n_components=2).fit_transform(center_embeddings)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "id": "c7aad38a", "metadata": {}, "outputs": [], "source": [ - "fig, ax = plt.subplots()\n", - "sns.scatterplot(x=tsfm[:,0], y=tsfm[:,1], c=cls.labels_, ax=ax)\n", - "ax.scatter(x=centers_proj[:,0], y=centers_proj[:,1], marker='X', c='red', alpha=0.5)\n", - "ax.set(xlabel='Latent Dim 0', ylabel='Latent Dim 1')\n", - "# plt.legend([str(x) for x in ap_labels], loc='best')\n", - "plt.show()" + "# fig, ax = plt.subplots()\n", + "# sns.scatterplot(x=tsfm[:,0], y=tsfm[:,1], c=cls.labels_, ax=ax)\n", + "# ax.scatter(x=centers_proj[:,0], y=centers_proj[:,1], marker='X', c='red', alpha=0.5)\n", + "# ax.set(xlabel='Latent Dim 0', ylabel='Latent Dim 1')\n", + "# # plt.legend([str(x) for x in ap_labels], loc='best')\n", + "# plt.show()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "id": "39ce0238-b3f2-4f46-a52f-13e3160cc52f", "metadata": {}, "outputs": [], "source": [ - "def get_data2(cix, labels):\n", - " users = target_df.iloc[labels == cix, :].index\n", + "# def get_data2(cix, labels):\n", + "# users = target_df.iloc[labels == cix, :].index\n", " \n", - " # Compute trip summaries.\n", - " X = df.loc[df.user_id.isin(users), [\n", - " 'section_distance_argmax', 'section_duration_argmax',\n", - " 'section_mode_argmax', 'distance',\n", - " 'duration', 'mph', 'user_id', 'target'\n", - " ]]\n", + "# # Compute trip summaries.\n", + "# X = df.loc[df.user_id.isin(users), [\n", + "# 'section_distance_argmax', 'section_duration_argmax',\n", + "# 'section_mode_argmax', 'distance',\n", + "# 'duration', 'mph', 'user_id', 'target'\n", + "# ]]\n", " \n", - " # Compute the target distribution and select the argmax.\n", - " target_distribution = X.target.value_counts(ascending=False, normalize=True)\n", - " target_distribution.rename(index=MAP, inplace=True)\n", + "# # Compute the target distribution and select the argmax.\n", + "# target_distribution = X.target.value_counts(ascending=False, normalize=True)\n", + "# target_distribution.rename(index=MAP, inplace=True)\n", " \n", - " # Caution - this summary df has NaNs. Use nanstd() to compute nan-aware std.\n", - " subset = get_trip_summary_df(users, X)\n", + "# # Caution - this summary df has NaNs. Use nanstd() to compute nan-aware std.\n", + "# subset = get_trip_summary_df(users, X)\n", " \n", - " norm_subset = pd.DataFrame(\n", - " MinMaxScaler().fit_transform(subset),\n", - " columns=subset.columns, index=subset.index\n", - " )\n", + "# norm_subset = pd.DataFrame(\n", + "# MinMaxScaler().fit_transform(subset),\n", + "# columns=subset.columns, index=subset.index\n", + "# )\n", " \n", - " return norm_subset, target_distribution" + "# return norm_subset, target_distribution" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "id": "ec27cf29", "metadata": { "scrolled": false }, "outputs": [], "source": [ - "## Analaysis for this data.\n", + "# ## Analaysis for this data.\n", "\n", - "ic, oc = dict(), dict()\n", - "labels = cls.labels_\n", + "# ic, oc = dict(), dict()\n", + "# labels = cls.labels_\n", "\n", - "for cix in np.unique(labels):\n", - " users = target_df[labels == cix].index\n", + "# for cix in np.unique(labels):\n", + "# users = target_df[labels == cix].index\n", " \n", - " ic[cix] = dict()\n", + "# ic[cix] = dict()\n", " \n", - " # Trip characteristics.\n", - " norm_subset, _ = get_data2(cix, labels)\n", - " for feature in norm_subset.columns:\n", - " ic[cix][feature] = np.nanstd(norm_subset[feature])\n", + "# # Trip characteristics.\n", + "# norm_subset, _ = get_data2(cix, labels)\n", + "# for feature in norm_subset.columns:\n", + "# ic[cix][feature] = np.nanstd(norm_subset[feature])\n", " \n", - " # Demographics.\n", - " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", - " processed = preprocess_demo_data(data)\n", + "# # Demographics.\n", + "# data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + "# processed = preprocess_demo_data(data)\n", " \n", - " for col in processed.columns:\n", - " # Numeric/ordinal values. Use std. to measure homogeneity.\n", - " if col == 'age' or col == 'income_category' or col == 'n_working_residents':\n", - " ic[cix][col] = np.nanstd(processed[col])\n", - " else:\n", - " ic[cix][col] = entropy(processed[col])\n", - "\n", - "for cix in ic.keys():\n", - " oc[cix] = dict()\n", - " oix = set(labels) - set([cix])\n", - " for feature in ic[cix].keys():\n", - " oc[cix][feature] = np.nanmean([ic[x].get(feature, np.nan) for x in oix])\n", + "# for col in processed.columns:\n", + "# # Numeric/ordinal values. Use std. to measure homogeneity.\n", + "# if col == 'age' or col == 'income_category' or col == 'n_working_residents':\n", + "# ic[cix][col] = np.nanstd(processed[col])\n", + "# else:\n", + "# ic[cix][col] = entropy(processed[col])\n", "\n", - "# # Now, compute the per-cluster homogeneity.\n", "# for cix in ic.keys():\n", + "# oc[cix] = dict()\n", + "# oix = set(labels) - set([cix])\n", + "# for feature in ic[cix].keys():\n", + "# oc[cix][feature] = np.nanmean([ic[x].get(feature, np.nan) for x in oix])\n", + "\n", + "# # # Now, compute the per-cluster homogeneity.\n", + "# # for cix in ic.keys():\n", " \n", - "# users = users = target_df[labels == cix].index\n", - "# norm_subset, target_dist = get_data(cix, labels)\n", - "# data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", - "# processed = preprocess_demo_data(data)\n", + "# # users = users = target_df[labels == cix].index\n", + "# # norm_subset, target_dist = get_data(cix, labels)\n", + "# # data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + "# # processed = preprocess_demo_data(data)\n", " \n", - "# concat = processed.merge(norm_subset, left_index=True, right_index=True)\n", + "# # concat = processed.merge(norm_subset, left_index=True, right_index=True)\n", " \n", - "# ch = list()\n", - "# for feature in ic[cix].keys():\n", - "# ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", - "# ch.append([feature, ratio])\n", + "# # ch = list()\n", + "# # for feature in ic[cix].keys():\n", + "# # ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", + "# # ch.append([feature, ratio])\n", " \n", - "# ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).head(TOP_K).reset_index(drop=True)\n", + "# # ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).head(TOP_K).reset_index(drop=True)\n", "\n", "\n", - "# Now, compute the per-cluster homogeneity.\n", - "ax_ix = 0\n", - "for cix in ic.keys():\n", + "# # Now, compute the per-cluster homogeneity.\n", + "# ax_ix = 0\n", + "# for cix in ic.keys():\n", "\n", - " print(f\"For cluster {cix}:\")\n", + "# print(f\"For cluster {cix}:\")\n", "\n", - " # For each, cluster, we will have (TOP_K x n_clusters) figures.\n", - " fig, ax = plt.subplots(nrows=5, ncols=len(ic.keys()), figsize=(12, 8))\n", + "# # For each, cluster, we will have (TOP_K x n_clusters) figures.\n", + "# fig, ax = plt.subplots(nrows=5, ncols=len(ic.keys()), figsize=(12, 8))\n", "\n", - " other_ix = set(ic.keys()) - set([cix])\n", + "# other_ix = set(ic.keys()) - set([cix])\n", " \n", - " ch = list()\n", - " for feature in ic[cix].keys():\n", - " ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", - " ch.append([feature, ratio])\n", + "# ch = list()\n", + "# for feature in ic[cix].keys():\n", + "# ratio = ic[cix][feature] / (oc[cix][feature] + 1e-6)\n", + "# ch.append([feature, ratio])\n", " \n", - " # Just the top k.\n", - " ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).reset_index(drop=True).head(5)\n", - " figure_data = dict()\n", + "# # Just the top k.\n", + "# ch_df = pd.DataFrame(ch, columns=['feature', 'ch']).sort_values(by=['ch']).reset_index(drop=True).head(5)\n", + "# figure_data = dict()\n", " \n", - " # Get the actual trip summary data.\n", - " trip_summary_data, target_dist = get_data(cix)\n", + "# # Get the actual trip summary data.\n", + "# trip_summary_data, target_dist = get_data(cix)\n", "\n", - " display(target_dist)\n", + "# display(target_dist)\n", " \n", - " # Get the actual demographic data.\n", - " users = target_df[labels == cix].index\n", - " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", - " processed = preprocess_demo_data(data)\n", - "\n", - " # Left-most subplot will be that of the current cluster's feature.\n", - " for row_ix, row in ch_df.iterrows():\n", - " if row.feature in trip_summary_data.columns:\n", - " sns.histplot(trip_summary_data[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", - " else:\n", - " sns.histplot(processed[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", - " ax[row_ix][0].set_xlabel(ax[row_ix][0].get_xlabel(), fontsize=6)\n", - " ax[row_ix][0].set_ylim(0., 100.)\n", + "# # Get the actual demographic data.\n", + "# users = target_df[labels == cix].index\n", + "# data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + "# processed = preprocess_demo_data(data)\n", "\n", - " offset_col_ix = 1\n", - " ## Now, others.\n", - " for oix in other_ix:\n", - " # Get the actual trip summary data.\n", - " other_summary_data, _ = get_data(oix)\n", + "# # Left-most subplot will be that of the current cluster's feature.\n", + "# for row_ix, row in ch_df.iterrows():\n", + "# if row.feature in trip_summary_data.columns:\n", + "# sns.histplot(trip_summary_data[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", + "# else:\n", + "# sns.histplot(processed[row.feature], ax=ax[row_ix][0], stat='percent').set_title(\"Current cluster\")\n", + "# ax[row_ix][0].set_xlabel(ax[row_ix][0].get_xlabel(), fontsize=6)\n", + "# ax[row_ix][0].set_ylim(0., 100.)\n", + "\n", + "# offset_col_ix = 1\n", + "# ## Now, others.\n", + "# for oix in other_ix:\n", + "# # Get the actual trip summary data.\n", + "# other_summary_data, _ = get_data(oix)\n", " \n", - " # Get the actual demographic data.\n", - " users = target_df[labels == oix].index\n", - " data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", - " other_demo = preprocess_demo_data(data)\n", - "\n", - " for row_ix, row in ch_df.iterrows():\n", - " if row.feature in other_summary_data.columns:\n", - " sns.histplot(other_summary_data[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", - " else:\n", - " sns.histplot(other_demo[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", - " ax[row_ix][offset_col_ix].set_xlabel(ax[row_ix][offset_col_ix].get_xlabel(), fontsize=6)\n", - " ax[row_ix][offset_col_ix].set_ylim(0., 100.)\n", + "# # Get the actual demographic data.\n", + "# users = target_df[labels == oix].index\n", + "# data = demographics.loc[demographics.index.isin(users), :].reset_index(drop=True)\n", + "# other_demo = preprocess_demo_data(data)\n", + "\n", + "# for row_ix, row in ch_df.iterrows():\n", + "# if row.feature in other_summary_data.columns:\n", + "# sns.histplot(other_summary_data[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", + "# else:\n", + "# sns.histplot(other_demo[row.feature], ax=ax[row_ix][offset_col_ix], stat='percent').set_title(f\"Cluster {oix}\")\n", + "# ax[row_ix][offset_col_ix].set_xlabel(ax[row_ix][offset_col_ix].get_xlabel(), fontsize=6)\n", + "# ax[row_ix][offset_col_ix].set_ylim(0., 100.)\n", " \n", - " offset_col_ix += 1\n", + "# offset_col_ix += 1\n", "\n", - " plt.tight_layout()\n", - " plt.show()\n", - " print(50 * '=')" + "# plt.tight_layout()\n", + "# plt.show()\n", + "# print(50 * '=')" ] }, { From ad2321670e9bc03382ed77bde4ef3908cae8b162 Mon Sep 17 00:00:00 2001 From: Rahul Kulhalli Date: Wed, 1 May 2024 14:58:59 -0400 Subject: [PATCH 5/6] Fixed transit bug in 02_run_trip_models.py; added biogeme notebook --- .../01_extract_db_data.ipynb | 96 +- .../02_run_trip_level_models.py | 33 +- .../03_user_level_models.ipynb | 176 +-- .../04_FeatureClustering.ipynb | 1205 ++--------------- .../05_biogeme_modeling.ipynb | 929 +++++++++++++ 5 files changed, 1229 insertions(+), 1210 deletions(-) create mode 100644 replacement_mode_modeling/05_biogeme_modeling.ipynb diff --git a/replacement_mode_modeling/01_extract_db_data.ipynb b/replacement_mode_modeling/01_extract_db_data.ipynb index bef2545e..eea9d642 100644 --- a/replacement_mode_modeling/01_extract_db_data.ipynb +++ b/replacement_mode_modeling/01_extract_db_data.ipynb @@ -45,7 +45,7 @@ "source": [ "# Add path to your emission server here. Uncommented because the notebooks are run in the server.\n", "# If running locally, you need to point this to the e-mission server repo.\n", - "# emission_path = Path(os.getcwd()).parent.parent.parent / 'my_emission_server' / 'e-mission-server'\n", + "# emission_path = Path(os.getcwd()).parent.parent / 'my_emission_server' / 'e-mission-server'\n", "# sys.path.append(str(emission_path))\n", "\n", "# # Also add the home (viz_scripts) to the path\n", @@ -63,34 +63,6 @@ "import emission.storage.timeseries.abstract_timeseries as esta" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "e171e277", - "metadata": {}, - "outputs": [], - "source": [ - "DB_SOURCE = [\n", - " \"Stage_database\", # Does NOT have composite trips BUT has section modes and distances\n", - " \"openpath_prod_durham\", # Has composite trips\n", - " \"openpath_prod_mm_masscec\", # Has composite trips\n", - " \"openpath_prod_ride2own\", # Has composite trips\n", - " \"openpath_prod_uprm_nicr\" # Has composite trips\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "70fa3112", - "metadata": {}, - "outputs": [], - "source": [ - "CURRENT_DB = DB_SOURCE[0]\n", - "\n", - "assert CURRENT_DB in DB_SOURCE" - ] - }, { "cell_type": "code", "execution_count": null, @@ -369,6 +341,34 @@ "}" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "e171e277", + "metadata": {}, + "outputs": [], + "source": [ + "DB_SOURCE = [\n", + " \"Stage_database\", # Does NOT have composite trips BUT has section modes and distances\n", + " \"openpath_prod_durham\", # Has composite trips\n", + " \"openpath_prod_mm_masscec\", # Has composite trips\n", + " \"openpath_prod_ride2own\", # Has composite trips\n", + " \"openpath_prod_uprm_nicr\" # Has composite trips\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70fa3112", + "metadata": {}, + "outputs": [], + "source": [ + "CURRENT_DB = DB_SOURCE[4]\n", + "\n", + "assert CURRENT_DB in DB_SOURCE" + ] + }, { "cell_type": "code", "execution_count": null, @@ -693,11 +693,13 @@ "survey_data['ft_job'] = survey_data.primary_job_type.apply(\n", " lambda x: 1 if str(x).lower() == 'full_time' else 0\n", ")\n", + "survey_data.loc[~survey_data.ft_job.isin([0, 1]), 'ft_job'] = 0\n", "\n", "# gtg\n", "survey_data['multiple_jobs'] = survey_data.has_multiple_jobs.apply(\n", " lambda x: 1 if str(x).lower() == 'yes' else 0\n", ")\n", + "survey_data.loc[~survey_data.multiple_jobs.isin([0, 1]), 'multiple_jobs'] = 0\n", "\n", "# gtg\n", "survey_data.loc[\n", @@ -714,6 +716,7 @@ "survey_data.has_drivers_license = survey_data.has_drivers_license.apply(\n", " lambda x: 1 if str(x).lower() == 'yes' else 0\n", ")\n", + "survey_data.loc[~survey_data.has_drivers_license.isin([0, 1]), 'has_drivers_license'] = 0\n", "\n", "survey_data.loc[survey_data.n_residents_u18 == 'prefer_not_to_say', 'n_residents_u18'] = 0\n", "survey_data.n_residents_u18 = survey_data.n_residents_u18.astype(int)\n", @@ -743,11 +746,14 @@ "\n", "# gtg\n", "survey_data.is_paid = survey_data.is_paid.apply(lambda x: 1 if x == 'Yes' else 0)\n", + "survey_data.loc[~survey_data.is_paid.isin([0, 1]), 'is_paid'] = 0\n", "\n", "# gtg\n", "survey_data.has_medical_condition = survey_data.has_medical_condition.apply(\n", " lambda x: 1 if str(x).lower() == 'yes' else 0\n", ")\n", + "survey_data.loc[~survey_data.has_medical_condition.isin([0, 1]), 'has_medical_condition'] = 0\n", + "\n", "\n", "## gtg\n", "survey_data.is_student.replace({\n", @@ -761,7 +767,10 @@ " 'Yes - Part-Time College/University': 1,\n", " 'Taking prerequisites missing for grad program ': 1, \n", " 'Graduate': 1,\n", + " 'Fire Fighter 2 Training': 0,\n", + " 'By hours ': 0,\n", " 'Custodian': 0, \n", + " 'taking classes toward early childhood licensure': 0,\n", " 'Work at csu': 0,\n", " 'not_a_student': 0, \n", " 'yes___vocation_technical_trade_school': 1,\n", @@ -769,7 +778,9 @@ " 'prefer_not_to_say': 0, \n", " 'yes___k_12th_grade_including_ged': 1,\n", " 'yes___full_time_college_university': 1\n", - "}, inplace=True)" + "}, inplace=True)\n", + "\n", + "survey_data.loc[~survey_data.is_student.isin([0, 1]), 'is_student'] = 0" ] }, { @@ -798,7 +809,8 @@ " survey_data['age'] = new_col\n", " \n", " survey_data.loc[survey_data.age.isin([\n", - " '66___70_years_old', '76___80_years_old', '81___85_years_old'\n", + " '66___70_years_old', '71___75_years_old', '76___80_years_old', '81___85_years_old',\n", + " '151___155_years_old', \n", " ]), 'age'] = '__65_years_old'\n", " \n", " survey_data.drop(columns=['birth_year'], inplace=True)\n", @@ -894,7 +906,14 @@ " ]), 'primary_job_description'\n", " ] = 'Manufacturing, construction, maintenance, or farming'\n", "\n", - " df.loc[df.primary_job_description.isna(), 'primary_job_description'] = 'Other'\n", + " # All others in Other\n", + " df.loc[\n", + " (df.primary_job_description.isna()) | (~df.primary_job_description.isin(\n", + " ['Education', 'Custodial', 'Clerical or administrative support', 'Sales or service'\n", + " 'Food service', 'Medical/healthcare', 'Manufacturing, construction, maintenance, or farming',\n", + " 'Other'])), \n", + " 'primary_job_description'\n", + " ] = 'Other'\n", "\n", " return df" ] @@ -1622,6 +1641,16 @@ "filtered_trips.replace({'target': {t: ix+1 for ix, t in enumerate(targets)}}, inplace=True)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe5a1909", + "metadata": {}, + "outputs": [], + "source": [ + "display(filtered_trips.info())" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1629,7 +1658,6 @@ "metadata": {}, "outputs": [], "source": [ - "# savepath = Path('./data/filtered_data')\n", "savepath = Path('./data/filtered_data')\n", "\n", "if not savepath.exists():\n", @@ -1641,7 +1669,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f16fb354", + "id": "065c1911", "metadata": {}, "outputs": [], "source": [] diff --git a/replacement_mode_modeling/02_run_trip_level_models.py b/replacement_mode_modeling/02_run_trip_level_models.py index 3976ee10..95f77ab4 100644 --- a/replacement_mode_modeling/02_run_trip_level_models.py +++ b/replacement_mode_modeling/02_run_trip_level_models.py @@ -186,6 +186,10 @@ def get_duration_estimate(df: pd.DataFrame, dset: SPLIT, model_dict: dict): X = section_data[X_features] Y = section_data[['section_duration_argmax']] + if section_mode not in model_dict.keys(): + print(f"Inference for section={section_mode} could not be done due to lack of samples. Skipping...") + continue + y_pred = model_dict[section_mode]['model'].predict(X) r2 = r2_score(y_pred=y_pred, y_true=Y.values.ravel()) print(f"\t-> Test R2 for {section_mode}: {r2}") @@ -196,6 +200,12 @@ def get_duration_estimate(df: pd.DataFrame, dset: SPLIT, model_dict: dict): df['temp'] = 0 for section in df.section_mode_argmax.unique(): + + # Cannot predict because the mode is present in test but not in train. + if section not in model_dict.keys(): + df.loc[df.section_mode_argmax == section, 'temp'] = 0. + continue + X_section = df.loc[df.section_mode_argmax == section, X_features] # broadcast to all columns. @@ -436,8 +446,8 @@ def save_metadata(dir_name: Path, **kwargs): if __name__ == "__main__": - - datasets = sorted(list(Path('./data/filtered_data').glob('preprocessed_data_*.csv'))) + + datasets = sorted(list(Path('../data/filtered_data').glob('preprocessed_data_*.csv'))) start = perf_counter() @@ -447,28 +457,35 @@ def save_metadata(dir_name: Path, **kwargs): print(f"Starting modeling for dataset = {name}") data = pd.read_csv(dataset) - data.drop_duplicates(inplace=True) - data.dropna(inplace=True) if 'deprecatedID' in data.columns: data.drop(columns=['deprecatedID'], inplace=True) if 'data.key' in data.columns: data.drop(columns=['data.key'], inplace=True) - # These two lines make all the difference. - data.sort_values(by=['user_id'], ascending=True, inplace=True) - data = data[sorted(data.columns.tolist())] + print(f"# Samples found: {len(data)}, # unique users: {len(data.user_id.unique())}") print("Beginning sweeps.") # args = parse_args() sweep_number = 1 - root = Path('./outputs/benchmark_results') + root = Path('../outputs/benchmark_results') if not root.exists(): root.mkdir() + + + if 'section_mode_argmax' in data.columns and (data.section_mode_argmax.value_counts() < 2).any(): + # Find which mode. + counts = data.section_mode_argmax.value_counts() + modes = counts[counts < 2].index.tolist() + print(f"Dropping {modes} because of sparsity (<2 samples)") + + data = data.loc[~data.section_mode_argmax.isin(modes), :].reset_index(drop=True) + for split in [SPLIT_TYPE.INTER_USER, SPLIT_TYPE.INTRA_USER, SPLIT_TYPE.TARGET, SPLIT_TYPE.MODE, SPLIT_TYPE.HIDE_USER]: + kwargs = { 'dataset': name, 'split': split diff --git a/replacement_mode_modeling/03_user_level_models.ipynb b/replacement_mode_modeling/03_user_level_models.ipynb index 616cd5e6..1f17a91c 100644 --- a/replacement_mode_modeling/03_user_level_models.ipynb +++ b/replacement_mode_modeling/03_user_level_models.ipynb @@ -309,118 +309,86 @@ " trip_group_key = trip_kwargs.pop('trip_grouping', 'section_mode_argmax')\n", " \n", " demographics = {\n", - " 'allceo': [\n", - " 'has_drivers_license', 'is_student', 'is_paid', 'income_category',\n", - " 'n_residence_members', 'n_residents_u18', 'n_residents_with_license',\n", - " 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs', 'n_working_residents',\n", - " \"highest_education_Bachelor's degree\",\n", - " 'highest_education_Graduate degree or professional degree',\n", - " 'highest_education_High school graduate or GED',\n", - " 'highest_education_Less than a high school graduate',\n", - " 'highest_education_Prefer not to say',\n", - " 'highest_education_Some college or associates degree',\n", - " 'primary_job_description_Clerical or administrative support',\n", - " 'primary_job_description_Custodial',\n", - " 'primary_job_description_Education',\n", - " 'primary_job_description_Food service',\n", - " 'primary_job_description_Linecook',\n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", - " 'primary_job_description_Medical/healthcare',\n", - " 'primary_job_description_Non-profit program manager',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Professional, managerial, or technical',\n", - " 'primary_job_description_Sales or service',\n", - " 'primary_job_description_Self employed',\n", - " 'primary_job_description_food service', 'gender_Man',\n", - " 'gender_Nonbinary/genderqueer/genderfluid', 'gender_Prefer not to say',\n", - " 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", - " 'age_16___20_years_old', 'age_21___25_years_old',\n", - " 'age_26___30_years_old', 'age_31___35_years_old',\n", - " 'age_36___40_years_old', 'age_41___45_years_old',\n", - " 'age_46___50_years_old', 'age_51___55_years_old',\n", - " 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old',\n", - " 'av_transit', 'av_no_trip', 'av_p_micro', 'av_s_micro', 'av_ridehail',\n", - " 'av_unknown', 'av_walk', 'av_car', 'av_s_car'\n", + " 'allceo': [ \n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category', 'n_residence_members', \n", + " 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles',\n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'n_working_residents', \n", + " \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", + " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", + " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + " 'primary_job_description_Education', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Medical/healthcare', 'primary_job_description_Other', 'gender_Man', \n", + " 'gender_Man;Nonbinary/genderqueer/genderfluid', 'gender_Nonbinary/genderqueer/genderfluid', \n", + " 'gender_Prefer not to say', 'gender_Test', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", + " 'age_16___20_years_old', 'age_1___5_years_old', 'age_21___25_years_old', 'age_26___30_years_old', \n", + " 'age_31___35_years_old', 'age_36___40_years_old', 'age_41___45_years_old', 'age_46___50_years_old', \n", + " 'age_51___55_years_old', 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old', \n", + " 'av_s_car', 'av_walk', 'av_ridehail', 'av_s_micro', 'av_transit', 'av_no_trip', 'av_car', 'av_unknown', \n", + " 'av_p_micro'\n", " ],\n", " 'durham': [\n", - " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18',\n", - " 'n_residence_members', 'income_category',\n", - " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles',\n", - " 'has_medical_condition', 'ft_job', 'multiple_jobs',\n", - " 'highest_education_bachelor_s_degree',\n", - " 'highest_education_graduate_degree_or_professional_degree',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_less_than_a_high_school_graduate',\n", - " 'highest_education_some_college_or_associates_degree',\n", - " 'primary_job_description_Clerical or administrative support',\n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Professional, Manegerial, or Technical',\n", - " 'primary_job_description_Sales or service', 'gender_man',\n", - " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman',\n", - " 'age_16___20_years_old', 'age_21___25_years_old',\n", - " 'age_26___30_years_old', 'age_31___35_years_old',\n", - " 'age_36___40_years_old', 'age_41___45_years_old',\n", - " 'age_51___55_years_old', 'age_56___60_years_old', 'av_walk',\n", - " 'av_unknown', 'av_no_trip', 'av_p_micro', 'av_transit', 'av_car',\n", - " 'av_ridehail', 'av_s_micro', 'av_s_car'\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', 'income_category',\n", + " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition', 'ft_job',\n", + " 'multiple_jobs', 'highest_education_bachelor_s_degree', 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged', 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_some_college_or_associates_degree', 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Other', 'primary_job_description_Prefer not to say', 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'primary_job_description_Sales or service', 'gender_man', 'gender_non_binary_genderqueer_gender_non_confor',\n", + " 'gender_prefer_not_to_say', 'gender_woman', 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old',\n", + " 'age_31___35_years_old', 'age_36___40_years_old', 'age_41___45_years_old', 'age_46___50_years_old',\n", + " 'age_51___55_years_old', 'age_56___60_years_old', 'av_unknown', 'av_no_trip', 'av_s_micro', 'av_s_car', 'av_car',\n", + " 'av_p_micro', 'av_walk', 'av_transit', 'av_ridehail'\n", " ],\n", " 'nicr': [\n", - " 'is_student', 'is_paid',\n", - " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", - " 'income_category', 'n_residents_with_license',\n", - " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_prefer_not_to_say', 'primary_job_description_Other',\n", - " 'gender_man', 'gender_woman', 'age_16___20_years_old', 'av_p_micro',\n", - " 'av_car', 'av_transit', 'av_ridehail', 'av_no_trip', 'av_s_car',\n", - " 'av_s_micro', 'av_unknown', 'av_walk'\n", + " \n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', \n", + " 'income_category', 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', \n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", + " 'highest_education_high_school_graduate_or_ged', 'highest_education_prefer_not_to_say', \n", + " 'highest_education_some_college_or_associates_degree', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Other', \n", + " 'gender_man', 'gender_woman', 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', \n", + " 'av_s_car', 'av_no_trip', 'av_s_micro', 'av_walk', 'av_unknown', 'av_p_micro', 'av_transit', 'av_car', \n", + " 'av_ridehail'\n", " ],\n", " 'masscec': [\n", - " 'is_student', 'is_paid',\n", - " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", - " 'income_category', 'n_residents_with_license',\n", - " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree',\n", - " 'highest_education_graduate_degree_or_professional_degree',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_less_than_a_high_school_graduate',\n", - " 'highest_education_prefer_not_to_say',\n", - " 'highest_education_some_college_or_associates_degree',\n", - " 'primary_job_description_Clerical or administrative support',\n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Prefer not to say',\n", - " 'primary_job_description_Professional, Manegerial, or Technical',\n", - " 'primary_job_description_Sales or service', 'gender_man',\n", - " 'gender_prefer_not_to_say', 'gender_woman', 'age_16___20_years_old',\n", - " 'age_21___25_years_old', 'age_26___30_years_old',\n", - " 'age_31___35_years_old', 'age_36___40_years_old',\n", - " 'age_41___45_years_old', 'age_46___50_years_old',\n", - " 'age_51___55_years_old', 'age_56___60_years_old',\n", - " 'age_61___65_years_old', 'age___65_years_old', 'av_p_micro', 'av_s_car',\n", - " 'av_s_micro', 'av_transit', 'av_car', 'av_no_trip', 'av_unknown',\n", - " 'av_ridehail', 'av_walk'\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', \n", + " 'income_category', 'n_residents_with_license', 'n_working_residents', \n", + " 'n_motor_vehicles', 'has_medical_condition', 'ft_job', 'multiple_jobs', \n", + " 'highest_education_bachelor_s_degree', 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged', \n", + " 'highest_education_less_than_a_high_school_graduate', 'highest_education_prefer_not_to_say', \n", + " 'highest_education_some_college_or_associates_degree', \n", + " 'primary_job_description_Clerical or administrative support', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Other', 'primary_job_description_Prefer not to say', \n", + " 'primary_job_description_Professional, Manegerial, or Technical', \n", + " 'primary_job_description_Sales or service', 'gender_man', \n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_prefer_not_to_say', 'gender_woman', \n", + " 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', \n", + " 'age_31___35_years_old', 'age_36___40_years_old', 'age_41___45_years_old', \n", + " 'age_46___50_years_old', 'age_51___55_years_old', 'age_56___60_years_old', \n", + " 'age_61___65_years_old', 'age___65_years_old', 'av_no_trip', 'av_transit', \n", + " 'av_ridehail', 'av_walk', 'av_car', 'av_p_micro', 'av_unknown', 'av_s_micro', 'av_s_car'\n", " ],\n", " 'ride2own': [\n", - " 'has_drivers_license', 'is_student',\n", - " 'is_paid', 'income_category', 'n_residence_members',\n", - " 'n_working_residents', 'n_residents_u18', 'n_residents_with_license',\n", - " 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs',\n", - " 'highest_education_bachelor_s_degree',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_less_than_a_high_school_graduate',\n", - " 'highest_education_some_college_or_associates_degree',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Professional, Manegerial, or Technical',\n", - " 'gender_man', 'gender_woman', 'age_31___35_years_old',\n", - " 'age_36___40_years_old', 'age_41___45_years_old',\n", - " 'age_51___55_years_old', 'av_no_trip', 'av_s_micro', 'av_transit',\n", - " 'av_car', 'av_ridehail', 'av_p_micro', 'av_s_car', 'av_walk',\n", - " 'av_unknown'\n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category', 'n_residence_members', \n", + " 'n_working_residents', 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles', \n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", + " 'highest_education_graduate_degree_or_professional_degree', \n", + " 'highest_education_high_school_graduate_or_ged', \n", + " 'highest_education_less_than_a_high_school_graduate', \n", + " 'highest_education_some_college_or_associates_degree', 'primary_job_description_Other', \n", + " 'primary_job_description_Professional, Manegerial, or Technical', \n", + " 'primary_job_description_Sales or service', 'gender_man', \n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman', 'age_16___20_years_old', \n", + " 'age_21___25_years_old', 'age_26___30_years_old', 'age_31___35_years_old', \n", + " 'age_36___40_years_old', 'age_41___45_years_old', 'age_51___55_years_old', \n", + " 'age_56___60_years_old', 'age___65_years_old', 'av_p_micro', 'av_s_car', 'av_car', \n", + " 'av_ridehail', 'av_walk', 'av_transit', 'av_no_trip', 'av_s_micro', 'av_unknown'\n", " ]\n", " }\n", " \n", diff --git a/replacement_mode_modeling/04_FeatureClustering.ipynb b/replacement_mode_modeling/04_FeatureClustering.ipynb index 1ee33f65..0c222fcf 100644 --- a/replacement_mode_modeling/04_FeatureClustering.ipynb +++ b/replacement_mode_modeling/04_FeatureClustering.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "789df947", "metadata": {}, "outputs": [], @@ -18,6 +18,7 @@ "import matplotlib.colors as mcolors\n", "import seaborn as sns\n", "\n", + "from pathlib import Path\n", "from sklearn.linear_model import LinearRegression\n", "from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances\n", "from sklearn.metrics import davies_bouldin_score, calinski_harabasz_score, silhouette_score\n", @@ -39,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "aea4dda7", "metadata": {}, "outputs": [], @@ -58,7 +59,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "33ef3275", "metadata": {}, "outputs": [], @@ -67,18 +68,21 @@ "PATH = DATA_SOURCE[DB_NUMBER][0]\n", "CURRENT_DB = DATA_SOURCE[DB_NUMBER][1]\n", "\n", + "OUTPUT_DIR = Path('./outputs')\n", + "\n", + "if not OUTPUT_DIR.exists():\n", + " OUTPUT_DIR.mkdir()\n", + "\n", "df = pd.read_csv(PATH)" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "d6f69976", "metadata": {}, "outputs": [], "source": [ - "df.dropna(inplace=True)\n", - "\n", "not_needed = ['deprecatedID', 'data.key']\n", "\n", "for col in not_needed:\n", @@ -88,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "b2281bdc", "metadata": {}, "outputs": [], @@ -101,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "9c22d6ac", "metadata": {}, "outputs": [], @@ -113,7 +117,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "063f6124", "metadata": {}, "outputs": [], @@ -123,7 +127,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "cef8d45b", "metadata": {}, "outputs": [], @@ -137,7 +141,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "68c6af2d", "metadata": {}, "outputs": [], @@ -147,7 +151,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "eff378a7", "metadata": {}, "outputs": [], @@ -157,7 +161,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "cffbd401", "metadata": {}, "outputs": [], @@ -167,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "f1eb1633", "metadata": {}, "outputs": [], @@ -181,7 +185,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "d9cc0a0f", "metadata": { "scrolled": true @@ -197,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "750fbd0c", "metadata": {}, "outputs": [], @@ -210,223 +214,17 @@ "\n", "figure1_df['n_trips'] = min_max_normalize(figure1_df['n_trips'])\n", "figure1_df['start:hour'] = np.sin(figure1_df['start:hour'].values)\n", - "figure1_df['end:hour'] = np.sin(figure1_df['end:hour'].values)" + "figure1_df['end:hour'] = np.sin(figure1_df['end:hour'].values)\n", + "\n", + "figure1_df.fillna(0., inplace=True)" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "1c3d1849", "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", - "
coverage_bicyclingcoverage_carcoverage_transitcoverage_unknowncoverage_walkingpct_distance_bicyclingpct_distance_carpct_distance_transitpct_distance_unknownpct_distance_walkingn_tripsstart:hourend:hour
user_id
0600d3df-c1aa-4ca2-83f2-1f6b8931280d0.0500000.8500000.00.0000000.1000000.0092820.9849540.00.0000000.0057640.0833330.4121180.650288
44eda4da-9223-4bb0-afd4-e7dd19fc6b270.0650410.7804880.00.0650410.0894310.0381800.9126930.00.0331710.0159570.7435900.1498770.149877
4c5436e9-4840-4872-9e8f-5d46ba81fe520.0000000.7142860.00.0000000.2857140.0000000.8472470.00.0000000.1527530.0000000.6502880.650288
7479810c-c602-4508-8ae2-da0bed87558d0.1162790.4534880.00.1279070.3023260.0155300.9264890.00.0270850.0308960.5064100.1498770.990607
7f7c9d3b-84ed-4c14-be8a-aa256daaed010.0175440.7719300.00.0350880.1754390.0051570.8543270.00.1100330.0304830.3205130.9906070.990607
\n", - "
" - ], - "text/plain": [ - " coverage_bicycling coverage_car \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.050000 0.850000 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.065041 0.780488 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 0.714286 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.116279 0.453488 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.017544 0.771930 \n", - "\n", - " coverage_transit coverage_unknown \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.0 0.000000 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.0 0.065041 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.0 0.000000 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.0 0.127907 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.0 0.035088 \n", - "\n", - " coverage_walking \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.100000 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.089431 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.285714 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.302326 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.175439 \n", - "\n", - " pct_distance_bicycling \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.009282 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.038180 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.015530 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.005157 \n", - "\n", - " pct_distance_car pct_distance_transit \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.984954 0.0 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.912693 0.0 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.847247 0.0 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.926489 0.0 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.854327 0.0 \n", - "\n", - " pct_distance_unknown \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.000000 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.033171 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.027085 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.110033 \n", - "\n", - " pct_distance_walking n_trips \\\n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.005764 0.083333 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.015957 0.743590 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.152753 0.000000 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.030896 0.506410 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.030483 0.320513 \n", - "\n", - " start:hour end:hour \n", - "user_id \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.412118 0.650288 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.149877 0.149877 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.650288 0.650288 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.149877 0.990607 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.990607 0.990607 " - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "figure1_df.head()" ] @@ -441,7 +239,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "598d82bc", "metadata": {}, "outputs": [], @@ -467,18 +265,10 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "bc89a42d", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Counter({0: 8, -1: 4})\n" - ] - } - ], + "outputs": [], "source": [ "'''\n", "AlLCEO: eps=0.542\n", @@ -493,47 +283,12 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "05c9a7c4", "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4 users in cluster -1\n" - ] - }, - { - "data": { - "image/png": "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v18333yzwsLC9OqrryokJERLly7VsGHD9Msvv+ipp56SdD4cxsTEyGq1as6cOapdu7aWLVvm8f6ApUuXasiQIerXr5/eeustWa1WvfHGG4qPj9dHH31U4g5mt9t1/PhxjRs3TvXq1VN+fr4+/vhj3X333Vq4cKGGDBni0n/16tXatGmTJk2apDp16igsLEzffPONevTo4QxfAQEBSk5O1tKlSz2OuXPnTiUmJmrChAkKDg7W1KlTdffddysxMVGffPKJ/vGPf8hisejpp59Wnz59dODAAedvhgcPHlTz5s117733qlatWsrJydHcuXN1ww036Ntvv1VoaKgsFouWLFmidu3aaeDAgdq0aZOsVqseeeQRHThwQF988YUCAwOLXSferPuLZWZm6p577tE999yjKVOmyM/PT4cOHdKnn34qSbr++uu1cOFCDR8+XM8884zzkkf9+vWdy8jPz9cdd9yhhx9+WH//+9917ty5Esdcs2aNNm7cqGnTpikwMFBz5szRoEGD5OPjowEDBpRa84VWrVqlAQMGKDg4WHPmzJF0/oxIcTIyMtSjRw+1adNG8+fPl81m05w5c9S3b1+9/fbbuueee1z6jxw5Ur1793YeK5588kk98MADzvXjyZw5c/T222/rueee08KFC9WiRQtdc801kqSkpCSNHz9egwYNUlJSko4dO6YpU6YoOjpa27Zt07XXXutcjrfrtSxK+7yl8yE4JiZGP/30k8aPH682bdpoz549mjRpknbt2qWPP/7YJeB42sdWrFihRx55RI899phmzpypKlWq6IcfftC3335b7trL81lI0kcffaS+ffsqKipKL7/8sho0aKCDBw9qw4YN5a7lQi+88IKmTJmiZ555Rl26dJHD4dC+ffucl2RGjhyp48eP67XXXtP777+v8PBwSVLLli0lSf/4xz/0zDPPOPex/Px8vfjii+rcubO+/PJLZz/pymwTV4xRSSxcuNCQZGzdutVwOBzGqVOnjA8//NCoU6eO0aVLF8PhcDj7tmjRwmjfvr1Lm2EYRp8+fYzw8HCjoKDAZZl33XWXS7/PP//ckGQ899xzzrahQ4caDRs2LLa+goICw+FwGIsXLzaqVq1qHD9+3DAMwzh16pQRFBRk3HrrrUZhYWGx85e15nvuucfw9/c3cnNznX3OnTtntGjRwpBkHDhwoNgxit6HJCMlJcXZ5nA4jGuuucaQZHz99dfO9mPHjhlVq1Y1EhISnG333nuvYbPZjOzsbJfl9uzZ0wgICDBOnDhhGIZhPP3004bFYjF27Njh0q9Hjx6GJGPjxo2GYRjG6dOnjVq1ahl9+/Z16VdQUGC0bdvWuPHGG0t8Pxc7d+6c4XA4jBEjRhjt27d3eU2SERwc7Pxsivztb38zAgMDjd9++81l/JYtW7qt04YNGxr+/v7GTz/95GzbsWOHIckIDw83Tp8+7WxfvXq1IclYs2ZNifX+8ccfRmBgoPHKK6+4vLZ582bDx8fHGDNmjLFgwQJDkjFv3rxS10FZ171huG/XM2fONCQ5P0dPtm3bZkgyFi5c6PZa0fa1YMECj69dvA9JKnZ7btq0qbNt8uTJhqfDWdE+fOFn1KpVKyMmJsat74EDB9zq7tSpkxEWFmacOnXKZfzWrVsb9evXd+6zReM88sgjLst84YUXDElGTk6O23ie6ty2bZuz7ffffzf8/f2NXr16ufTNzs42bDabcd999znbSlqvnhR3vLp4PZbl805KSjKqVKniUrthGMZ7771nSDJSU1OdbcXtY48++qhRo0aNMtV+MUnG5MmTndOX+lk0adLEaNKkifHnn38W28fTdtWwYUNj6NChbn1jYmJctrc+ffoY7dq1K7GGF1980ePxOjs72/Dx8TEee+wxl/ZTp04ZderUMQYOHOhs83abKKvAwECP7/NSVbrLNJ06dZLValX16tV1++23q2bNmvrggw/k43P+JNAPP/ygffv26f7775cknTt3zvnTq1cv5eTkaP/+/S7LLOpb5Oabb1bDhg21cePGEmvZvn277rjjDoWEhKhq1aqyWq0aMmSICgoK9N1330k6f6NSXl6eHnnkEY+nmb2teePGjYqNjVXt2rWd81etWtXtN7iSWCwW9erVyznt4+Ojpk2bKjw8XO3bt3e216pVS2FhYS6XED799FPFxsYqIiLCZZnDhg3TmTNnlJmZ6ayzVatWatu2rUu/++67z2V6y5YtOn78uIYOHeryvgsLC3X77bdr27ZtpV6SePfdd3XLLbeoWrVq8vHxkdVq1fz5891OdUtS9+7dVbNmTZe2jIwMde/eXaGhoc62KlWqaODAgR7Ha9eunerVq+ecjoqKknT+dO2F12uL2i9cf3/88YeefvppNW3aVD4+PvLx8VG1atV0+vRpt3pvueUWTZ8+XbNmzdL//u//6oEHHtCIESNKXBdS2de9J0WXYAYOHKh33nlHR44cKXUeT/r371/mvsVtzz/88IN++umnco1fFqdPn9YXX3yhAQMGqFq1ai7jDx48WD/99JPbseKOO+5wmW7Tpo0k18+4rDIzM/Xnn3+6namNiIhQ9+7dPV6m9Ga9lkVZPu9169apdevWateuncs+Gh8f7/HJOE/72I033qgTJ05o0KBB+uCDD3T06NFLrr08n8V3332nH3/8USNGjJCfn98l1+DJjTfeqJ07d+qRRx7RRx99pLy8vDLP+9FHH+ncuXMaMmSIy7r28/NTTEyMx6cQy7pNXLi8c+fOyTCMMtd1OVS6MLJ48WJt27ZNn376qR5++GHt3btXgwYNcr5edO/IuHHjZLVaXX4eeeQRSXLbEerUqeM2Tp06dXTs2LFi68jOzlbnzp115MgRvfLKK9q0aZO2bdum2bNnS5L+/PNPSdJvv/0myfU09sW8qfnYsWPF1ltWAQEBbjuir6+vatWq5dbX19dXZ8+edU4fO3bMeVrxQnXr1nW+7k2dRe99wIABbu/9+eefl2EYOn78eLHv5f3339fAgQNVr149LV26VJmZmdq2bZsefPBBl7qLeKr92LFjLv8ZFvHUJsltPRXdfV5c+4V13HfffXr99dc1cuRIffTRR/ryyy+1bds2XXPNNc5t5kL333+/fH19ZbfbndeZS3Mp20iXLl20evVq5wGxfv36at26td5+++0yjS2d376CgoLK3L+kWkvaBy/V77//LsMwyrQ9FwkJCXGZLroE5OmzK03Rsosb/+KxvV2vZVGWz/uXX37RN99847Z/Vq9eXYZhuB1PPb2fwYMHa8GCBTp06JD69++vsLAw3XTTTUpLSyt37eX5LMpyPL5UiYmJmjlzprZu3aqePXsqJCREsbGxbvePeVJ0PLzhhhvc1vfKlSvd1nVZt4mDBw+6LS8jI6N8b7CcKt09I1FRUc6bVrt166aCggLNmzdP7733ngYMGOD87TYxMVF33323x2U0b97cZTo3N9etT25urpo2bVpsHatXr9bp06f1/vvvq2HDhs72ix93LLo2XNJveN7UHBISUmy9f4WQkBDl5OS4tRfdOFb0XspaZ1H/1157rdi75osLBdL5+00aNWqklStXupx5stvtHvt7OjsVEhLidgO0p1ov1cmTJ7Vu3TpNnjxZf//7353tRfe9XKygoED333+/atasKZvNphEjRujzzz8v9dG7S91G+vXrp379+slut2vr1q1KSkrSfffdp8jISEVHR5c6f3FnAItTUq1F/+EUhWe73e5yD8il/IZds2ZNValSpUzb85VQ9N6KG//isb1Zr35+fh73AU/rq7TPOzQ0VP7+/i73wV2orHUOHz5cw4cP1+nTp/XZZ59p8uTJ6tOnj7777juXY+iVVJbjcXFKWqcXrgMfHx8lJCQoISFBJ06c0Mcff6zx48crPj5ehw8fLvFpl6LlvPfee2VaJ2XdJurWratt27a5tF38/+CVVunOjFzshRdeUM2aNTVp0iQVFhaqefPmuvbaa7Vz50517NjR48/Fz/cvW7bMZXrLli06dOiQyx3SFyvaCC48MBqGoX/9618u/W6++WYFBwcrOTm52NNi3tTcrVs3ffLJJy7/eRYUFGjlypWlr6zLIDY2Vp9++qnbXeuLFy9WQECAM1B069ZNe/bs0c6dO136XXyj7S233KIaNWro22+/Lfa9l/Sfr8Vicf4RqSK5ubken6YpTkxMjD799FOXA3VhYaHefffdMi+jLCwWiwzDcLuhct68eSooKHDrP3nyZG3atEnLli3TypUrtXPnzjKdHSnrui+NzWZTTEyMnn/+eUly3s1/KWcDPClue27SpInzN9iiJ0O++eYbl3nXrl3rse6y1BYYGKibbrpJ77//vkv/wsJCLV26VPXr13e5Mf5yi46Olr+/v9uN0j/99JPzcmh5RUZG6tdff3VZr/n5+froo4+Knae4z7tPnz768ccfFRIS4nH/9PaP5gUGBqpnz56aMGGC8vPznY89/xWaNWumJk2aaMGCBcX+wlKcyMhIt+3vu+++c7uUd6EaNWpowIABGj16tI4fP+586qu4fSg+Pl4+Pj768ccfiz0eloevr2+p/w9eaZXuzMjFatasqcTERD311FNavny5HnjgAb3xxhvq2bOn4uPjNWzYMNWrV0/Hjx/X3r179fXXX7v9J5OVlaWRI0fqb3/7mw4fPqwJEyaoXr16zksknvTo0UO+vr4aNGiQnnrqKZ09e1Zz5851++Nr1apV00svvaSRI0fqtttu00MPPaTatWvrhx9+0M6dO/X6669LUplrfuaZZ7RmzRp1795dkyZNUkBAgGbPnl3qfRWXy+TJk7Vu3Tp169ZNkyZNUq1atbRs2TKtX79eL7zwgoKDgyVJY8aM0YIFC9S7d28999xzzic69u3b57Z+XnvtNQ0dOlTHjx/XgAEDFBYWpt9++007d+7Ub7/9prlz5xZbT58+ffT+++/rkUce0YABA3T48GE9++yzCg8PL/Nf5p0wYYLWrl2r2NhYTZgwQf7+/kpOTnau08v12FtQUJC6dOmiF198UaGhoYqMjFRGRobmz5/v9tRWWlqakpKSNHHiROd/SklJSRo3bpy6du2qu+66q9hxyrruPZk0aZJ++uknxcbGqn79+jpx4oReeeUVWa1WxcTESDr/t0n8/f21bNkyRUVFqVq1aqpbt67z0oa3QkND1b17d02cONH5NM2+fftcHu/t1auXatWqpREjRmjatGny8fHRokWLdPjwYbflXXfddVqxYoVWrlypxo0by8/PT9ddd53HsZOSktSjRw9169ZN48aNk6+vr+bMmaPdu3fr7bff9vosjzdq1KihiRMnavz48RoyZIgGDRqkY8eOaerUqfLz89PkyZPLvex77rlHkyZN0r333qsnn3xSZ8+e1auvvuoWesvyeY8ZM0YpKSnq0qWLxo4dqzZt2qiwsFDZ2dnasGGDnnjiCd10000l1vPQQw/J399ft9xyi8LDw5Wbm6ukpCQFBwc771v5q8yePVt9+/ZVp06dNHbsWDVo0EDZ2dn66KOP3H4xvdDgwYP1wAMP6JFHHlH//v116NAhvfDCC86zLUX69u3r/HtY11xzjQ4dOqRZs2apYcOGzqejirbHV155RUOHDpXValXz5s0VGRmpadOmacKECfrPf/7jvC/yl19+0ZdffqnAwEBNnTr1sq+TjIwM5yWsgoICHTp0SO+9956k87+sXfwey+Wy3xJrEk93oxf5888/jQYNGhjXXnutce7cOcMwDGPnzp3GwIEDjbCwMMNqtRp16tQxunfvbiQnJ7stc8OGDcbgwYONGjVqOO9u//77713G8HR3+tq1a422bdsafn5+Rr169Ywnn3zS+Pe//+32xIJhGEZqaqoRExNjBAYGGgEBAUbLli2N559/3qVPWWo2jPNP+3Tq1Mmw2WxGnTp1jCeffNJ48803y/w0TWBgoFt7TEyM0apVK7f2hg0bGr1793Zp27Vrl9G3b18jODjY8PX1Ndq2bevx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O2Z2CcBV79SpU5IkwzBK7OdVGClisbgeMAzDcGsrrb+n9iJJSUmaOnWqW3ujRo28LRUArojQl8yuAKg4Tp06peDg4GJf9yqMhIaGqmrVqm5nQX799Ve3sx9F6tSp47G/j4+PQkJCPM6TmJiohIQE53RhYaGOHz+ukJCQEkMPgIonLy9PEREROnz4sIKCgswuB8BlZBiGTp06pbp165bYz6sw4uvrqw4dOigtLU133XWXsz0tLU39+vXzOE90dLTWrl3r0rZhwwZ17NhRVqvV4zw2m002m82lrUaNGt6UCqCCCQoKIowAlVBJZ0SKeP00TUJCgubNm6cFCxZo7969Gjt2rLKzszVq1ChJ589qDBkyxNl/1KhROnTokBISErR3714tWLBA8+fP17hx47wdGgAAVEJe3zNyzz336NixY5o2bZpycnLUunVrpaamqmHDhpKknJwcl7850qhRI6Wmpmrs2LGaPXu26tatq1dffVX9+/e/fO8CAABUWBajtFtcAeAKstvtSkpKUmJiotvlWQD/HQgjAADAVHxRHgAAMBVhBAAAmIowAgAATEUYAXBZpKeny2Kx6MSJE2aXAqCCIYwAAABTEUYAAICpCCMAJEmRkZGaNWuWS1u7du00ZcoUSee/2HLevHm66667FBAQoGuvvVZr1qwpdnl//vmnevfurU6dOun48eM6ePCgLBaL3n//fXXr1k0BAQFq27atMjMzXeZLSUlRq1atZLPZFBkZqZde+v/fSPfaa6/puuuuc06vXr1aFotFs2fPdrbFx8crMTFRkjRlyhS1a9dOS5YsUWRkpIKDg3Xvvfc6v0kUwNWBMAKgzKZOnaqBAwfqm2++Ua9evXT//ffr+PHjbv1OnjypuLg45efn65NPPlGtWrWcr02YMEHjxo3Tjh071KxZMw0aNEjnzp2TJH311VcaOHCg7r33Xu3atUtTpkzRxIkTtWjRIklS165dtWfPHh09elSSlJGRodDQUGVkZEiSzp07py1btigmJsY53o8//qjVq1dr3bp1WrdunTIyMjRjxowrtYoAlANhBECZDRs2TIMGDVLTpk31j3/8Q6dPn9aXX37p0ueXX35RTEyMwsLCtH79egUGBrq8Pm7cOPXu3VvNmjXT1KlTdejQIf3www+SpJdfflmxsbGaOHGimjVrpmHDhunRRx/Viy++KElq3bq1QkJCnOEjPT1dTzzxhHN627ZtOnv2rG699VbneIWFhVq0aJFat26tzp07a/Dgwfrkk0+u2DoC4D3CCIAya9OmjfPfgYGBql69un799VeXPrfddpsaN26sd955R76+viUuIzw8XJKcy9i7d69uueUWl/633HKLvv/+exUUFMhisahLly5KT0/XiRMntGfPHo0aNUoFBQXau3ev0tPTdf3116tatWrO+SMjI1W9enWXMS+uGYC5CCMAJElVqlTRxd8O4XA4XKatVqvLtMViUWFhoUtb7969tWnTJn377bcex7lwGRaLRZKcyzAMw9lW5OKaunbtqvT0dG3atElt27ZVjRo11KVLF2VkZCg9PV1du3b1umYA5iKMAJAkXXPNNcrJyXFO5+Xl6cCBA14vZ8aMGRo6dKhiY2OLDSTFadmypTZv3uzStmXLFjVr1kxVq1aV9P/vG3nvvfecwSMmJkYff/yx2/0iACoGwggASVL37t21ZMkSbdq0Sbt379bQoUOdAcBbM2fO1P3336/u3btr3759ZZ7viSee0CeffKJnn31W3333nd566y29/vrrGjdunLNP0X0jy5Ytc4aRrl27avXq1frzzz9d7hcBUDH4mF0AgKtDYmKi/vOf/6hPnz4KDg7Ws88+W64zI0X++c9/qqCgQN27d1d6errH+0cudv311+udd97RpEmT9Oyzzyo8PFzTpk3TsGHDnH0sFotiYmK0evVqde7cWdL5+1CCg4PVuHFjBQUFlbtmAOawGBdfkAUAAPgLcZkGAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGAqwggAADAVYQRAmVkslhJ/LvxLqX+1yMhIzZo1y7TxAZQffw4eQJld+EV6K1eu1KRJk7R//35nm7+/v1fLy8/PL9OfiQdQuXFmBECZ1alTx/kTHBwsi8XinLZarRo1apTq16+vgIAAXXfddXr77bdd5u/ataseffRRJSQkKDQ0VD169JAkrVmzRtdee638/f3VrVs3vfXWW7JYLDpx4oRz3i1btqhLly7y9/dXRESEHn/8cZ0+fdq53EOHDmns2LHOszQAKg7CCIDL4uzZs+rQoYPWrVun3bt363/+5380ePBgffHFFy793nrrLfn4+Ojzzz/XG2+8oYMHD2rAgAG68847tWPHDj388MOaMGGCyzy7du1SfHy87r77bn3zzTdauXKlNm/erEcffVSS9P7776t+/fqaNm2acnJyXM7gALj68UV5AMpl0aJFGjNmjMvZi4v17t1bUVFRmjlzpqTzZzBOnjyp7du3O/v8/e9/1/r167Vr1y5n2zPPPKPp06fr999/V40aNTRkyBD5+/vrjTfecPbZvHmzYmJidPr0afn5+SkyMlJjxozRmDFjLvt7BXBlcc8IgMuioKBAM2bM0MqVK3XkyBHZ7XbZ7XYFBga69OvYsaPL9P79+3XDDTe4tN14440u01999ZV++OEHLVu2zNlmGIYKCwt14MABRUVFXeZ3A+CvRBgBcFm89NJL+uc//6lZs2bpuuuuU2BgoMaMGaP8/HyXfheHE8Mw3O7xuPiEbWFhoR5++GE9/vjjbuM2aNDgMr0DAGYhjAC4LDZt2qR+/frpgQcekHQ+QHz//felnrVo0aKFUlNTXdqysrJcpq+//nrt2bNHTZs2LXY5vr6+KigoKGf1AMzEDawALoumTZsqLS1NW7Zs0d69e/Xwww8rNze31Pkefvhh7du3T08//bS+++47vfPOO1q0aJEkOc+YPP3008rMzNTo0aO1Y8cOff/991qzZo0ee+wx53IiIyP12Wef6ciRIzp69OgVeY8ArgzCCIDLYuLEibr++usVHx+vrl27qk6dOrrzzjtLna9Ro0Z677339P7776tNmzaaO3eu82kam80mSWrTpo0yMjL0/fffq3Pnzmrfvr0mTpyo8PBw53KmTZumgwcPqkmTJrrmmmuuyHsEcGXwNA2Aq8706dOVnJysw4cPm10KgL8A94wAMN2cOXN0ww03KCQkRJ9//rlefPFF598QAVD5EUYAmO7777/Xc889p+PHj6tBgwZ64oknlJiYaHZZAP4iXKYBAACm4gZWAABgKsIIAAAwFWEEAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGCq/wd9UcKr1s6aGAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "8 users in cluster 0\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAHFCAYAAACuBbDPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA6QElEQVR4nO3dd3RU1f7+8Wcgk0khCSQh0gKhiISOgjQlFAFpYkGaIiD60wvqRUQRaQmisV+8KqCigFLEgoiISlBBEFDwSlUElCqgApIgyDAk+/eHK/NlmLSJO4bg+7UWa3F29jn7M2fOOXlyyozDGGMEAABgQaniLgAAAFw4CBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAa877YDFz5kw5HA7vv6CgIFWsWFF9+/bVjh07inz8QYMGKSEhocjHKazs9bN79+7iLiVPy5cvl8Ph0PLly4u7lH+cnNZ9YbbrAwcOKDk5WRs2bAhovpzGcjgcuuuuuwJaTn6mTJmimTNn+rXv3r1bDocjx5/9HZ577jnVqlVLwcHBcjgcOnbsWLHUUdI4HA4lJyf/rWMW9fF09erVSk5O/tu3gd9//13Dhw9XpUqVFBISosaNG+uNN94osvHO+2CRbcaMGVqzZo2WLVumu+66S4sWLdIVV1yh3377rbhLA0qccePG6d133w1ongMHDiglJSXgYFGYsQojt2BRsWJFrVmzRt26dSvyGs61YcMG3XPPPWrXrp0+/fRTrVmzRhEREX97HSXRmjVrdNtttxV3GVatXr1aKSkpf3uwuP766zVr1ixNmDBBH374oZo1a6Z+/fpp7ty5RTJeUJEstQjUr19fTZs2lSS1bdtWmZmZmjBhghYuXKjBgwcXc3UoSYwxOnXqlEJDQ4u7lGJTs2bNIh/j5MmTCgsL+1vGyovL5VKLFi2KZeytW7dKkm6//XZdfvnlVpaZvV7PZzb2seJ6z0qivLaJJUuWKC0tTXPnzlW/fv0kSe3atdOePXt0//33q0+fPipdurTVekrMGYtzZYeMn3/+2ad9/fr1uuaaaxQdHa2QkBA1adJEb775pk+f7NNdaWlpGjx4sKKjoxUeHq4ePXroxx9/zHfsF154QW3atFFcXJzCw8PVoEEDPfHEE/J4PH59P/roI3Xo0EFRUVEKCwtTYmKiUlNTA65ZktauXavWrVsrJCRElSpV0ujRo3McMyeDBg1SmTJltG3bNnXu3Fnh4eGqWLGiHnvsMe+yr7jiCoWHh6t27dqaNWuW3zK2bNminj17qly5ct7TaTn127Ztm66++mqFhYUpNjZWd955p44fP55jXcuWLVOHDh0UGRmpsLAwtW7dWp988km+r+fUqVO677771LhxY0VFRSk6OlotW7bUe++959c3+7T7tGnTlJiYKJfL5a171apVatmypUJCQlS5cmWNGzdO06dP9zsdmpCQoO7du2vx4sVq0qSJQkNDlZiYqMWLF0v6c5tKTExUeHi4Lr/8cq1fv96nhvXr16tv375KSEhQaGioEhIS1K9fP+3Zs8fbxxijrl27KiYmRnv37vW2nzx5UvXq1VNiYqJOnDiR53op6LrP6fLEW2+9pebNm3u31Ro1aujWW2+V9OfllGbNmkmSBg8e7L00mX2qOnv72rx5szp16qSIiAh16NAh17Gyvfjii6pdu7ZcLpfq1q3rd3o2OTlZDofDb75zT1knJCRo69atWrFihbe27DFzuxSyatUqdejQQREREQoLC1OrVq30wQcf5DjOZ599pn/961+KjY1VTEyMrr/+eh04cCDH15Stbdu2uvnmmyVJzZs3l8Ph0KBBg7w/f/XVV9WoUSOFhIQoOjpa1113nb777jufZeS1XnOS27rOaT3m9X5ny8jI0MiRI1W9enUFBwercuXKGj58uN92mNc+NnXqVDVq1EhlypRRRESE6tSpo4ceeijPdZe9zLMvhfyV9yLbl19+qR49eigmJkYhISGqWbOmhg8fnuc8CQkJPu9btrZt26pt27be6aysLE2aNEmXXHKJQkNDVbZsWTVs2FDPPvuspD/fg/vvv1+SVL16de92evYlyvnz56tly5YKDw9XmTJl1LlzZ33zzTc+4wa6Tbz77rsqU6aMbrzxRp/2wYMH68CBA/ryyy/zfP2FUWLOWJxr165dkqTatWt72z777DNdffXVat68uaZNm6aoqCi98cYb6tOnj06ePOm3cQwZMkQdO3bU3LlztW/fPo0dO1Zt27bVpk2bVLZs2VzH/uGHH9S/f3/vzrZx40Y98sgj2rZtm1599VVvv1deeUW33367kpKSNG3aNMXFxWn79u3asmVLwDV/++236tChgxISEjRz5kyFhYVpypQpAZ3K8ng8uv7663XnnXfq/vvv19y5czV69GhlZGTonXfe0ahRo1SlShU999xzGjRokOrXr6/LLrtMkvT999+rVatWiouL03//+1/FxMRo9uzZGjRokH7++Wc98MADkv4MeklJSXI6nZoyZYouuugizZkzJ8fr6bNnz9Ytt9yinj17atasWXI6nXrxxRfVuXNnffzxx3nuLG63W0ePHtXIkSNVuXJlnT59WsuWLdP111+vGTNm6JZbbvHpv3DhQq1cuVLjx49XhQoVFBcXp02bNqljx47eIBUWFqZp06Zp9uzZOY65ceNGjR49WmPGjFFUVJRSUlJ0/fXXa/To0frkk0/06KOPyuFwaNSoUerevbt27drl/Ytt9+7duuSSS9S3b19FR0fr4MGDmjp1qpo1a6Zvv/1WsbGxcjgcev3119W4cWP17t1bK1eulNPp1NChQ7Vr1y59+eWXCg8Pz3WdBLLuz7VmzRr16dNHffr0UXJyskJCQrRnzx59+umnkqRLL71UM2bM0ODBgzV27FjvZYUqVap4l3H69Gldc801uuOOO/Tggw/qzJkzeY65aNEiffbZZ5o4caLCw8M1ZcoU9evXT0FBQerVq1e+NZ/t3XffVa9evRQVFaUpU6ZI+vNMRW5WrFihjh07qmHDhnrllVfkcrk0ZcoU9ejRQ/PmzVOfPn18+t92223q1q2b91hx//336+abb/aun5xMmTJF8+bN06RJkzRjxgzVqVNH5cuXlySlpqbqoYceUr9+/ZSamqojR44oOTlZLVu21Lp163TxxRd7lxPoei2I/N5v6c9Am5SUpP379+uhhx5Sw4YNtXXrVo0fP16bN2/WsmXLfMJKTvvYG2+8oaFDh+ruu+/WU089pVKlSmnnzp369ttvC117Yd4LSfr444/Vo0cPJSYm6plnnlHVqlW1e/duLV26tNC1nO2JJ55QcnKyxo4dqzZt2sjj8Wjbtm3eyx633Xabjh49queee04LFixQxYoVJUl169aVJD366KMaO3asdx87ffq0nnzySV155ZX66quvvP2kwLaJLVu2KDExUUFBvr/uGzZs6P15q1atrKwDL3OemzFjhpFk1q5dazwejzl+/Lj56KOPTIUKFUybNm2Mx+Px9q1Tp45p0qSJT5sxxnTv3t1UrFjRZGZm+izzuuuu8+n3xRdfGElm0qRJ3raBAweaatWq5Vpf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X6/bbrtNN954o/bt26cxY8aocuXK3ssQOenYsaOCg4PVr18/PfDAAzp16pSmTp3q90FdZcqU0dNPP63bbrtNV111lW6//XZddNFF2rlzpzZu3Kjnn39ekgpc89ixY7Vo0SK1b99e48ePV1hYmF544YV870OwZcKECVq8eLHatWun8ePHKzo6WnPmzNEHH3ygJ554QlFRUZKk4cOH69VXX1W3bt00adIk75MJ27Zt81s/zz33nAYOHKijR4+qV69eiouL06+//qqNGzfq119/1dSpU3Otp3v37lqwYIGGDh2qXr16ad++fXr44YdVsWLFAn8i65gxY/T++++rQ4cOGjNmjEJDQzVt2jTvOi1Vyk7ujoyMVJs2bfTkk08qNjZWCQkJWrFihV555RW/p4/S0tKUmpqqcePGeX/BpKamauTIkWrbtq2uu+66XMcp6LrPyfjx47V//3516NBBVapU0bFjx/Tss8/K6XQqKSlJ0p+ffREaGqo5c+YoMTFRZcqUUaVKlbyXDwIVGxur9u3ba9y4cd6nQrZt2+bzyGnXrl0VHR2tIUOGaOLEiQoKCtLMmTO1b98+v+U1aNBAb7zxhubPn68aNWooJCREDRo0yHHs1NRUdezYUe3atdPIkSMVHBysKVOmaMuWLZo3b16RXHfOVrZsWY0bN04PPfSQbrnlFvXr109HjhxRSkqKQkJCNGHChEIvu0+fPho/frz69u2r+++/X6dOndJ///tfvwBbkPd7+PDheuedd9SmTRvde++9atiwobKysrR3714tXbpU9913X76/lG6//XaFhoaqdevWqlixog4dOqTU1FRFRUV57/P4u7zwwgvq0aOHWrRooXvvvVdVq1bV3r179fHHH/v9kXm2AQMG6Oabb9bQoUN1ww03aM+ePXriiSe8Z0Gy9ejRw/t5S+XLl9eePXs0efJkVatWzfuUT/b2+Oyzz2rgwIFyOp265JJLlJCQoIkTJ2rMmDH68ccfvfcR/vzzz/rqq68UHh6ulJSUQr3uLl26qGPHjvrXv/6ljIwM1apVS/PmzdNHH32k2bNnW/8MC0kl56mQc+9MNsaYP/74w1StWtVcfPHF5syZM8YYYzZu3Gh69+5t4uLijNPpNBUqVDDt27c306ZN81vm0qVLzYABA0zZsmW9d2nv2LHDZ4yc7rJ+//33TaNGjUxISIipXLmy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AAAAawgWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAa/5SsEhNTZXD4dDw4cMtlQMAAEqyQgeLdevW6aWXXlLDhg1t1gMAAEqwQgWL33//XTfddJNefvlllStXznZNAACghCpUsBg2bJi6deumq666ynY9AACgBAsKdIY33nhD//vf/7Ru3boC9Xe73XK73d7pjIwMSZLH45HH4wl0eADnsex92lXKFHMlgeFYBOSvoPtJQMFi3759+ve//62lS5cqJCSkQPOkpqYqJSXFr33p0qUKCwsLZHgAJcTDTbOKu4SALFmypLhLAM57J0+eLFA/hzGmwH9aLFy4UNddd51Kly7tbcvMzJTD4VCpUqXkdrt9fiblfMYiPj5ehw8fVmRkZEGHBlACeDwepaWladz6UnJnOYq7nALbkty5uEsAznsZGRmKjY1Venp6nr+/Azpj0aFDB23evNmnbfDgwapTp45GjRrlFyokyeVyyeVy+bU7nU45nc5AhgdQQrizHHJnlpxgwbEIyF9B95OAgkVERITq16/v0xYeHq6YmBi/dgAA8M/DJ28CAABrAn4q5FzLly+3UAYAALgQcMYCAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWEOwAAAA1hAsAACANQQLAABgDcECAABYQ7AAAADWECwAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWBNQsJg6daoaNmyoyMhIRUZGqmXLlvrwww+LqjYAAFDCBBQsqlSposcee0zr16/X+vXr1b59e/Xs2VNbt24tqvoAAEAJEhRI5x49evhMP/LII5o6darWrl2revXqWS0MAACUPAEFi7NlZmbqrbfe0okTJ9SyZUubNQEAgBIq4GCxefNmtWzZUqdOnVKZMmX07rvvqm7durn2d7vdcrvd3umMjAxJksfjkcfjKUTJAM5X2fu0q5Qp5koCw7EIyF9B9xOHMSagI8Dp06e1d+9eHTt2TO+8846mT5+uFStW5BoukpOT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PDp58qSCPKWUmeUo7nIK7MiRI8VdAnDeO378uCTJGJNnv4CCRTaHw/eAYYzxa8uWmpqqlJQUv/bq1asXZmgAsC726eKuACg5jh8/rqioqFx/HlCwiI2NVenSpf3OTvzyyy9+ZzGyjR49WiNGjPBOZ2Vl6ejRo4qJick1jAAomTIyMhQfH699+/YpMjKyuMsBYJExRsePH1elSpXy7BdQsAgODtZll12mtLQ0XXfddd72tLQ09ezZM8d5XC6XXC6XT1vZsmUDGRZACRMZGUmwAC5AeZ2pyBbwpZARI0ZowIABatq0qVq2bKmXXnpJe/fu1Z133lmoIgEAwIUj4GDRp08fHTlyRBMnTtTBgwdVv359LVmyRNWqVSuK+gAAQAniMPnd3gkABeR2u5WamqrRo0f7XQIF8M9AsAAAANbwJWQAAMAaggUAALCGYAEAAKwhWADws3z5cjkcDh07dqy4SwFQwhAsAACANQQLAABgDcECuAAlJCRo8uTJPm2NGzdWcnKypD+/SHD69Om67rrrFBYWposvvliLFi3KdXl//PGHunXrphYtWujo0aPavXu3HA6HFixYoHbt2iksLEyNGjXSmjVrfOZ75513VK9ePblcLiUkJOjpp//v276ee+45NWjQwDu9cOFCORwOvfDCC962zp07a/To0ZKk5ORkNW7cWK+//roSEhIUFRWlvn37er9xEcD5gWAB/EOlpKSod+/e2rRpk7p27aqbbrpJR48e9euXnp6uTp066fTp0/rkk08UHR3t/dmYMWM0cuRIbdiwQbVr11a/fv105swZSdLXX3+t3r17q2/fvtq8ebOSk5M1btw4zZw5U5LUtm1bbd26VYcPH5YkrVixQrGxsVqxYoUk6cyZM1q9erWSkpK84/3www9auHChFi9erMWLF2vFihV67LHHimoVASgEggXwDzVo0CD169dPtWrV0qOPPqoTJ07oq6++8unz888/KykpSXFxcfrggw8UHh7u8/ORI0eqW7duql27tlJSUrRnzx7t3LlTkvTMM8+oQ4cOGjdunGrXrq1Bgwbprrvu0pNPPilJql+/vmJiYrxBYvny5brvvvu80+vWrdOpU6d0xRVXeMfLysrSzJkzVb9+fV155ZUaMGCAPvnkkyJbRwACR7AA/qEaNmzo/X94eLgiIiL0yy+/+PS56qqrVKNGDb355psKDg7OcxkVK1aUJO8yvvvuO7Vu3dqnf+vWrbVjxw5lZmbK4XCoTZs2Wr58uY4dO6atW7fqzjvvVGZmpr777jstX75cl156qcqUKeOdPyEhQRERET5jnlszgOJFsAAuQKVKldK5n9bv8Xh8pp1Op8+0w+FQVlaWT1u3bt20cuVKffvttzmOc/YyHA6HJHmXYYzxtmU7t6a2bdtq+fLlWrlypRo1aqSyZcuqTZs2WrFihZYvX662bdsGXDOA4kWwAC5A5cuX18GDB73TGRkZ2rVrV8DLeeyxxzRw4EB16NAh13CRm7p162rVqlU+batXr1bt2rVVunRpSf93n8Xbb7/tDRFJSUlatmyZ3/0VAEoGggVwAWrfvr1ef/11rVy5Ulu2bNHAgQO9v8wD9dRTT+mmm25S+/bttW3btgLPd9999+mTTz7Rww8/rO3bt2vWrFl6/vnnNXLkSG+f7Pss5syZ4w0Wbdu21cKFC/XHH3/43F8BoGQIKu4CANg3evRo/fjjj+revbuioqL08MMPF+qMRbb//Oc/yszMVPv27bV8+fIc77c416WXXqo333xT48eP18MPP6yKFStq4sSJGjRokLePw+FQUlKSFi5cqCuvvFLSn/dtREVFqUaNGoqMjCx0zQCKB1+bDgAArOFSCAAAsIZgAQAArCFYAAAAawgWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggXwD+VwOPL8d/YnZP7dEhISNHny5GIbH0Dh8ZHewD/U2V9SNn/+fI0fP17ff/+9ty00NDSg5Z0+fbpAH/UN4MLGGQvgH6pChQref1FRUXI4HN5pp9OpO++8U1WqVFFYWJgaNGigefPm+czftm1b3XXXXRoxYoRiY2PVsWNHSdKiRYt08cUXKzQ0VO3atdOsWbPkcDh07Ngx77yrV69WmzZtFBoaqvj4eN1zzz06ceKEd7l79uzRvffe6z17AqDkIFgA8HPq1ClddtllWrx4sbZs2aL/9//+nwYMGKAvv/zSp9+sWbMUFBSkL774Qi+++KJ2796tXr166dprr9WGDRt0xx13aMyYMT7zbN68WZ07d9b111+vTZs2af78+Vq1apXuuusuSdKCBQtUpUoVTZw4UQcPHvQ5swLg/MeXkAHQzJkzNXz4cJ+zCufq1q2bEhMT9dRTT0n688xCenq6vvnmG2+fBx98UB988IE2b97sbRs7dqweeeQR/fbbbypbtqxuueUWhYaG6sUXX/T2WbVqlZKSknTixAmFhIQoISFBw4cP1/Dhw62/VgBFi3ssAPjJzMzUY489pvnz5+unn36S2+2W2+1WeHi4T7+mTZv6TH///fdq1qyZT9vll1/uM/31119r586dmjNnjrfNGKOsrCzt2rVLiYmJll8NgL8TwQKAn6efflr/+c9/NHnyZDVo0EDh4eEaPny4Tp8+7dPv3KBhjPG7J+Lck6JZWVm64447dM899/iNW7VqVUuvAEBxIVgA8LNy5Ur17NlTN998s6Q/w8COHTvyPZtQp04dLVmyxKdt/fr1PtOXXnqptm7dqlq1auW6nODgYGVmZhayegDFiZs3AfipVauW0tLStHr1an333Xe64447dOjQoXznu+OOO7Rt2zaNGjVK27dv15tvvqmZM2dKkvdMxqhRo7RmzRoNGzZMGzZs0I4dO7Ro0SLdfffd3uUkJCTo888/108//aTDhw8XyWsEUDQIFgD8jBs3Tpdeeqk6d+6stm3bqkKFCrr22mvzna969ep6++23tWDBAjVs2FBTp071PhXicrkkSQ0bNtSKFSu0Y8cOXXnllWrSpInGjRunihUrepczceJE7d69WzVr1lT58uWL5DUCKBo8FQKgSD3yyCOaNm2a9u3bV9ylAPgbcI8FAKumTJmiZs2aKSYmRl988YWefPJJ72dUALjwESwAWLVjxw5NmjRJR48eVdWqVXXfffdp9OjRxV0WgL8Jl0IAAIA13LwJAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArPn/eYRvP2HTV5MAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# After clustering, we would like to see what the replaced mode argmax distribution in each cluster is.\n", "\n", @@ -555,14 +310,14 @@ " ax.set_title(f\"Replaced mode argmax distribution for users in cluster {cix}\")\n", " ax.set_xlabel(\"Target\")\n", " \n", - " plt.savefig(f'./outputs/{CURRENT_DB}__FIG1_cluster_{cix}_target_dist.png', dpi=300)\n", + " plt.savefig(OUTPUT_DIR / f'{CURRENT_DB}__FIG1_cluster_{cix}_target_dist.png', dpi=300)\n", " \n", " plt.show()" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "f2e8e117", "metadata": {}, "outputs": [], @@ -579,7 +334,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "99369dba", "metadata": {}, "outputs": [], @@ -589,7 +344,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "6cca3671", "metadata": {}, "outputs": [], @@ -610,7 +365,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "18093734", "metadata": {}, "outputs": [], @@ -623,200 +378,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "8001a140", "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", - "
pct_trips_unknownpct_trips_cardistance_unknowndistance_carduration_carduration_unknown
0600d3df-c1aa-4ca2-83f2-1f6b8931280d1.00.00.1669780.00.00.031289
44eda4da-9223-4bb0-afd4-e7dd19fc6b271.00.00.3763080.00.00.362037
4c5436e9-4840-4872-9e8f-5d46ba81fe521.00.00.0000000.00.00.000000
7479810c-c602-4508-8ae2-da0bed87558d1.00.00.8021320.00.00.447344
7f7c9d3b-84ed-4c14-be8a-aa256daaed011.00.00.2093200.00.00.172709
892088f9-4a27-4f39-91fb-0f5e48d189821.00.00.9825190.00.00.705049
993af3be-5011-44ad-b9cd-d4df7f0e67ad1.00.00.6593890.00.01.000000
c8158323-957d-43c7-bde6-193b99ee72b51.00.00.1004480.00.00.030035
cbed6b7b-555d-43a0-aadc-4a42540a024e1.00.00.3736100.00.00.228214
de83c290-7708-4f8b-8ca3-656072164ef60.01.00.5359491.01.00.700681
f3b93934-09ca-4b90-9089-51b5777bb9e71.00.01.0000000.00.00.740508
f8260067-8ba9-44ea-9c39-cd3e1bd003dd1.00.00.2326130.00.00.250613
\n", - "
" - ], - "text/plain": [ - " pct_trips_unknown pct_trips_car \\\n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 1.0 0.0 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 1.0 0.0 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 1.0 0.0 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 1.0 0.0 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 1.0 0.0 \n", - "892088f9-4a27-4f39-91fb-0f5e48d18982 1.0 0.0 \n", - "993af3be-5011-44ad-b9cd-d4df7f0e67ad 1.0 0.0 \n", - "c8158323-957d-43c7-bde6-193b99ee72b5 1.0 0.0 \n", - "cbed6b7b-555d-43a0-aadc-4a42540a024e 1.0 0.0 \n", - "de83c290-7708-4f8b-8ca3-656072164ef6 0.0 1.0 \n", - "f3b93934-09ca-4b90-9089-51b5777bb9e7 1.0 0.0 \n", - "f8260067-8ba9-44ea-9c39-cd3e1bd003dd 1.0 0.0 \n", - "\n", - " distance_unknown distance_car \\\n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.166978 0.0 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.376308 0.0 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.000000 0.0 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.802132 0.0 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.209320 0.0 \n", - "892088f9-4a27-4f39-91fb-0f5e48d18982 0.982519 0.0 \n", - "993af3be-5011-44ad-b9cd-d4df7f0e67ad 0.659389 0.0 \n", - "c8158323-957d-43c7-bde6-193b99ee72b5 0.100448 0.0 \n", - "cbed6b7b-555d-43a0-aadc-4a42540a024e 0.373610 0.0 \n", - "de83c290-7708-4f8b-8ca3-656072164ef6 0.535949 1.0 \n", - "f3b93934-09ca-4b90-9089-51b5777bb9e7 1.000000 0.0 \n", - "f8260067-8ba9-44ea-9c39-cd3e1bd003dd 0.232613 0.0 \n", - "\n", - " duration_car duration_unknown \n", - "0600d3df-c1aa-4ca2-83f2-1f6b8931280d 0.0 0.031289 \n", - "44eda4da-9223-4bb0-afd4-e7dd19fc6b27 0.0 0.362037 \n", - "4c5436e9-4840-4872-9e8f-5d46ba81fe52 0.0 0.000000 \n", - "7479810c-c602-4508-8ae2-da0bed87558d 0.0 0.447344 \n", - "7f7c9d3b-84ed-4c14-be8a-aa256daaed01 0.0 0.172709 \n", - "892088f9-4a27-4f39-91fb-0f5e48d18982 0.0 0.705049 \n", - "993af3be-5011-44ad-b9cd-d4df7f0e67ad 0.0 1.000000 \n", - "c8158323-957d-43c7-bde6-193b99ee72b5 0.0 0.030035 \n", - "cbed6b7b-555d-43a0-aadc-4a42540a024e 0.0 0.228214 \n", - "de83c290-7708-4f8b-8ca3-656072164ef6 1.0 0.700681 \n", - "f3b93934-09ca-4b90-9089-51b5777bb9e7 0.0 0.740508 \n", - "f8260067-8ba9-44ea-9c39-cd3e1bd003dd 0.0 0.250613 " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "target_df = user_target_pct.merge(right=target_distance, left_index=True, right_index=True).merge(\n", " right=target_duration, left_index=True, right_index=True\n", @@ -843,7 +408,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "31fecc00", "metadata": {}, "outputs": [], @@ -878,21 +443,10 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "id": "e39b41ba", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Counter({0: 11, -1: 1})" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# 0.35 is a good value\n", "\n", @@ -910,21 +464,10 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "1dbf8763", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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v//7v/U/f/HFF9q6datSU1PVtWtX3jsRFOxrw/smikT2YjbY2ZNPPmm6detmEhISzODBg837779fP3fDDTeYH/zgBw3Wv/fee2bQoEEmISHBdO/e3SxYsCDMie0lmNfn4YcfNj179jSJiYmmQ4cO5nvf+57585//HIHUrd/Jy7G/+7jhhhuMMbx3IinY14b3TfSwjPm/M+kAAABsiHOGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAACArVGGAOAMWJal119/PdIxAJwByhCAkJo4caJGjx592tsvWrRIKSkpIcvzbYFmmzhxoizLkmVZio+PV2Zmpn74wx/qhRdekM/na7C2tLRUo0aNCnnWkpISXXXVVUpKSlJ6erpuvfVW1dTUhPz3AKAMAYBfI0eOVGlpqXbt2qW33npLF198sW677TZdeeWVqqurq1/XsWNHuVyukP5ur9erK664QkeOHNG6dev0xz/+UcuWLdPtt98e0t8D4ATKEICweuyxxzRgwAAlJSUpKytLP//5z1VVVSVJeu+99zRp0iR5PJ76PTOzZ8+WJNXU1OjOO+9Uly5dlJSUpKFDh+q9996rf96Te5Tefvtt9e3bV+3atasvNJI0e/Zsvfjii3rjjTfqn/vb23+Xy+VSx44d1aVLFw0ePFh333233njjDb311ltatGhR/bpvHybbtWuXLMvSq6++quHDh6tNmzb6l3/5F3322Wf661//qiFDhtTn+vrrr5v83e+88462b9+ul19+WYMGDdJll12mRx99VM8++6wqKytP6787gKZRhgCElcPh0BNPPKG//e1vevHFF7Vq1SrdeeedkqS8vDzNmzdPycnJKi0tVWlpqWbMmCFJmjRpkj744AP98Y9/1LZt2/TjH/9YI0eO1Oeff17/3EePHtUjjzyil156SWvWrFFJSUn99jNmzNCYMWPqC1Jpaany8vKCyn7JJZdo4MCBWr58ebPr7r//ft1777366KOPFBcXp+uuu0533nmnHn/8ca1du1Y7d+7Ufffd1+T2GzZsUP/+/dW5c+f6sREjRqi6ulqbN28OKjOAU4uLdAAA9jJ16tT6f2dnZ+uBBx7Qz372M82fP18JCQlyu92yLEsdO3asX7dz50698sor+uqrr+oLwowZM7Ry5UotXLhQDz30kCSptrZWTz31lHr27ClJmjJliubOnStJateundq0aaPq6uoGzx2sPn36aNu2bc2umTFjhkaMGCFJuu2223Tdddfp3Xff1UUXXSRJuummmxrsXfqusrIyZWZmNhjr0KGDEhISVFZWdtrZAfhHGQIQVqtXr9ZDDz2k7du3q7KyUnV1dTp+/LiOHDmipKQkv9t89NFHMsbo3HPPbTBeXV2ttLS0+p/btm1bX4QkqVOnTiovLw9pfmOMLMtqds35559f/++TpWbAgAENxk6Vy9/vCOR3AwgeZQhA2Hz55Ze6/PLLVVhYqAceeECpqalat26dbrrpJtXW1ja5nc/nk9Pp1ObNm+V0OhvMtWvXrv7f8fHxDeYsy5IxJqR/w44dO5Sdnd3smm/nOFlevjv23avSvq1jx47auHFjg7GDBw+qtra20R4jAGeOMgQgbDZt2qS6ujo9+uijcjhOnLL46quvNliTkJAgr9fbYGzQoEHyer0qLy/X8OHDT/v3+3vuYKxatUqffPKJpk2bdtrPEYjc3Fz9+te/VmlpqTp16iTpxEnVLpdLOTk5Lfq7ATuiDAEIOY/Ho61btzYYS01NVc+ePVVXV6ff/e53uuqqq/TBBx/oqaeearCue/fuqqqq0rvvvquBAweqbdu2Ovfcc3X99ddrwoQJevTRRzVo0CBVVFRo1apVGjBggC6//PKAcnXv3l1vv/22Pv30U6Wlpcntdjfam3RSdXW1ysrK5PV6tW/fPq1cuVJFRUW68sorNWHChNP67xKo/Px8nXfeeSooKNBvf/tbHThwQDNmzNDkyZOVnJzcor8bsCOuJgMQcu+9954GDRrU4HHffffpggsu0GOPPaaHH35Y/fv315IlS1RUVNRg27y8PBUWFmrs2LE666yz9Jvf/EaStHDhQk2YMEG33367evfurauvvlobN25UVlZWwLkmT56s3r17a8iQITrrrLP0wQcfNLl25cqV6tSpk7p3766RI0dq9erVeuKJJ/TGG280OlQXak6nU3/+85+VmJioiy66SGPGjNHo0aP1yCOPtOjvBezKMqE+oA4AABBD2DMEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABsjTIEAABs7f8Di5ufrJdoRg0AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "from sklearn.decomposition import PCA\n", "\n", @@ -933,31 +476,23 @@ "fig, ax = plt.subplots()\n", "sns.scatterplot(x=tsfm[:,0], y=tsfm[:,1], c=cl2.labels_)\n", "ax.set(xlabel='Latent Dim 0', ylabel='Latent Dim 1')\n", - "plt.savefig(f'./outputs/{CURRENT_DB}__Fig2__PCA_w_colors.png', dpi=300)\n", + "plt.savefig(OUTPUT_DIR / f'{CURRENT_DB}__Fig2__PCA_w_colors.png', dpi=300)\n", "plt.show()" ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "id": "1e444316", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['duration', 'distance', 'start:hour', 'end:hour', 'user_id', 'target', 'section_mode_argmax', 'section_distance_argmax', 'section_duration_argmax', 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', 'income_category', 'available_modes', 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', 'highest_education_high_school_graduate_or_ged', 'highest_education_prefer_not_to_say', 'highest_education_some_college_or_associates_degree', 'primary_job_description_Clerical or administrative support', 'primary_job_description_Other', 'gender_man', 'gender_woman', 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', 'av_ridehail', 'av_p_micro', 'av_walk', 'av_transit', 'av_car', 'av_s_micro', 'av_s_car', 'av_unknown', 'av_no_trip', 'cost_ridehail', 'cost_p_micro', 'cost_walk', 'cost_transit', 'cost_car', 'cost_s_micro', 'cost_s_car', 'cost_unknown', 'cost_no_trip', 'mph']\n" - ] - } - ], + "outputs": [], "source": [ "print(df.columns.tolist())" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "id": "f0bc09b9", "metadata": {}, "outputs": [], @@ -972,119 +507,87 @@ "\n", "\n", "demographic_cols = {\n", - " 'allceo': [\n", - " 'has_drivers_license', 'is_student', 'is_paid', 'income_category',\n", - " 'n_residence_members', 'n_residents_u18', 'n_residents_with_license',\n", - " 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs', 'n_working_residents',\n", - " \"highest_education_Bachelor's degree\",\n", - " 'highest_education_Graduate degree or professional degree',\n", - " 'highest_education_High school graduate or GED',\n", - " 'highest_education_Less than a high school graduate',\n", - " 'highest_education_Prefer not to say',\n", - " 'highest_education_Some college or associates degree',\n", - " 'primary_job_description_Clerical or administrative support',\n", - " 'primary_job_description_Custodial',\n", - " 'primary_job_description_Education',\n", - " 'primary_job_description_Food service',\n", - " 'primary_job_description_Linecook',\n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", - " 'primary_job_description_Medical/healthcare',\n", - " 'primary_job_description_Non-profit program manager',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Professional, managerial, or technical',\n", - " 'primary_job_description_Sales or service',\n", - " 'primary_job_description_Self employed',\n", - " 'primary_job_description_food service', 'gender_Man',\n", - " 'gender_Nonbinary/genderqueer/genderfluid', 'gender_Prefer not to say',\n", - " 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", - " 'age_16___20_years_old', 'age_21___25_years_old',\n", - " 'age_26___30_years_old', 'age_31___35_years_old',\n", - " 'age_36___40_years_old', 'age_41___45_years_old',\n", - " 'age_46___50_years_old', 'age_51___55_years_old',\n", - " 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old',\n", - " 'av_transit', 'av_no_trip', 'av_p_micro', 'av_s_micro', 'av_ridehail',\n", - " 'av_unknown', 'av_walk', 'av_car', 'av_s_car'\n", - " ],\n", - " 'durham': [\n", - " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18',\n", - " 'n_residence_members', 'income_category',\n", - " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles',\n", - " 'has_medical_condition', 'ft_job', 'multiple_jobs',\n", - " 'highest_education_bachelor_s_degree',\n", - " 'highest_education_graduate_degree_or_professional_degree',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_less_than_a_high_school_graduate',\n", - " 'highest_education_some_college_or_associates_degree',\n", - " 'primary_job_description_Clerical or administrative support',\n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Professional, Manegerial, or Technical',\n", - " 'primary_job_description_Sales or service', 'gender_man',\n", - " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman',\n", - " 'age_16___20_years_old', 'age_21___25_years_old',\n", - " 'age_26___30_years_old', 'age_31___35_years_old',\n", - " 'age_36___40_years_old', 'age_41___45_years_old',\n", - " 'age_51___55_years_old', 'age_56___60_years_old', 'av_walk',\n", - " 'av_unknown', 'av_no_trip', 'av_p_micro', 'av_transit', 'av_car',\n", - " 'av_ridehail', 'av_s_micro', 'av_s_car'\n", - " ],\n", - " 'nicr': [\n", - " 'is_student', 'is_paid',\n", - " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", - " 'income_category', 'n_residents_with_license',\n", - " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_prefer_not_to_say', 'primary_job_description_Other',\n", - " 'gender_man', 'gender_woman', 'age_16___20_years_old', 'av_p_micro',\n", - " 'av_car', 'av_transit', 'av_ridehail', 'av_no_trip', 'av_s_car',\n", - " 'av_s_micro', 'av_unknown', 'av_walk'\n", - " ],\n", - " 'masscec': [\n", - " 'is_student', 'is_paid',\n", - " 'has_drivers_license', 'n_residents_u18', 'n_residence_members',\n", - " 'income_category', 'n_residents_with_license',\n", - " 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree',\n", - " 'highest_education_graduate_degree_or_professional_degree',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_less_than_a_high_school_graduate',\n", - " 'highest_education_prefer_not_to_say',\n", - " 'highest_education_some_college_or_associates_degree',\n", - " 'primary_job_description_Clerical or administrative support',\n", - " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Prefer not to say',\n", - " 'primary_job_description_Professional, Manegerial, or Technical',\n", - " 'primary_job_description_Sales or service', 'gender_man',\n", - " 'gender_prefer_not_to_say', 'gender_woman', 'age_16___20_years_old',\n", - " 'age_21___25_years_old', 'age_26___30_years_old',\n", - " 'age_31___35_years_old', 'age_36___40_years_old',\n", - " 'age_41___45_years_old', 'age_46___50_years_old',\n", - " 'age_51___55_years_old', 'age_56___60_years_old',\n", - " 'age_61___65_years_old', 'age___65_years_old', 'av_p_micro', 'av_s_car',\n", - " 'av_s_micro', 'av_transit', 'av_car', 'av_no_trip', 'av_unknown',\n", - " 'av_ridehail', 'av_walk'\n", - " ],\n", - " 'ride2own': [\n", - " 'has_drivers_license', 'is_student',\n", - " 'is_paid', 'income_category', 'n_residence_members',\n", - " 'n_working_residents', 'n_residents_u18', 'n_residents_with_license',\n", - " 'n_motor_vehicles', 'has_medical_condition',\n", - " 'ft_job', 'multiple_jobs',\n", - " 'highest_education_bachelor_s_degree',\n", - " 'highest_education_high_school_graduate_or_ged',\n", - " 'highest_education_less_than_a_high_school_graduate',\n", - " 'highest_education_some_college_or_associates_degree',\n", - " 'primary_job_description_Other',\n", - " 'primary_job_description_Professional, Manegerial, or Technical',\n", - " 'gender_man', 'gender_woman', 'age_31___35_years_old',\n", - " 'age_36___40_years_old', 'age_41___45_years_old',\n", - " 'age_51___55_years_old', 'av_no_trip', 'av_s_micro', 'av_transit',\n", - " 'av_car', 'av_ridehail', 'av_p_micro', 'av_s_car', 'av_walk',\n", - " 'av_unknown'\n", - " ]\n", + " 'allceo': [ \n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category', 'n_residence_members', \n", + " 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles',\n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'n_working_residents', \n", + " \"highest_education_Bachelor's degree\", 'highest_education_Graduate degree or professional degree', \n", + " 'highest_education_High school graduate or GED', 'highest_education_Less than a high school graduate', \n", + " 'highest_education_Prefer not to say', 'highest_education_Some college or associates degree', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + " 'primary_job_description_Education', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Medical/healthcare', 'primary_job_description_Other', 'gender_Man', \n", + " 'gender_Man;Nonbinary/genderqueer/genderfluid', 'gender_Nonbinary/genderqueer/genderfluid', \n", + " 'gender_Prefer not to say', 'gender_Test', 'gender_Woman', 'gender_Woman;Nonbinary/genderqueer/genderfluid', \n", + " 'age_16___20_years_old', 'age_1___5_years_old', 'age_21___25_years_old', 'age_26___30_years_old', \n", + " 'age_31___35_years_old', 'age_36___40_years_old', 'age_41___45_years_old', 'age_46___50_years_old', \n", + " 'age_51___55_years_old', 'age_56___60_years_old', 'age_61___65_years_old', 'age___65_years_old', \n", + " 'av_s_car', 'av_walk', 'av_ridehail', 'av_s_micro', 'av_transit', 'av_no_trip', 'av_car', 'av_unknown', \n", + " 'av_p_micro'\n", + " ],\n", + " 'durham': [\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', 'income_category',\n", + " 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', 'has_medical_condition', 'ft_job',\n", + " 'multiple_jobs', 'highest_education_bachelor_s_degree', 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged', 'highest_education_less_than_a_high_school_graduate',\n", + " 'highest_education_some_college_or_associates_degree', 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Other', 'primary_job_description_Prefer not to say', 'primary_job_description_Professional, Manegerial, or Technical',\n", + " 'primary_job_description_Sales or service', 'gender_man', 'gender_non_binary_genderqueer_gender_non_confor',\n", + " 'gender_prefer_not_to_say', 'gender_woman', 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old',\n", + " 'age_31___35_years_old', 'age_36___40_years_old', 'age_41___45_years_old', 'age_46___50_years_old',\n", + " 'age_51___55_years_old', 'age_56___60_years_old', 'av_unknown', 'av_no_trip', 'av_s_micro', 'av_s_car', 'av_car',\n", + " 'av_p_micro', 'av_walk', 'av_transit', 'av_ridehail'\n", + " ],\n", + " 'nicr': [\n", + "\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', \n", + " 'income_category', 'n_residents_with_license', 'n_working_residents', 'n_motor_vehicles', \n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", + " 'highest_education_high_school_graduate_or_ged', 'highest_education_prefer_not_to_say', \n", + " 'highest_education_some_college_or_associates_degree', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Other', \n", + " 'gender_man', 'gender_woman', 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', \n", + " 'av_s_car', 'av_no_trip', 'av_s_micro', 'av_walk', 'av_unknown', 'av_p_micro', 'av_transit', 'av_car', \n", + " 'av_ridehail'\n", + " ],\n", + " 'masscec': [\n", + " 'is_student', 'is_paid', 'has_drivers_license', 'n_residents_u18', 'n_residence_members', \n", + " 'income_category', 'n_residents_with_license', 'n_working_residents', \n", + " 'n_motor_vehicles', 'has_medical_condition', 'ft_job', 'multiple_jobs', \n", + " 'highest_education_bachelor_s_degree', 'highest_education_graduate_degree_or_professional_degree',\n", + " 'highest_education_high_school_graduate_or_ged', \n", + " 'highest_education_less_than_a_high_school_graduate', 'highest_education_prefer_not_to_say', \n", + " 'highest_education_some_college_or_associates_degree', \n", + " 'primary_job_description_Clerical or administrative support', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Other', 'primary_job_description_Prefer not to say', \n", + " 'primary_job_description_Professional, Manegerial, or Technical', \n", + " 'primary_job_description_Sales or service', 'gender_man', \n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_prefer_not_to_say', 'gender_woman', \n", + " 'age_16___20_years_old', 'age_21___25_years_old', 'age_26___30_years_old', \n", + " 'age_31___35_years_old', 'age_36___40_years_old', 'age_41___45_years_old', \n", + " 'age_46___50_years_old', 'age_51___55_years_old', 'age_56___60_years_old', \n", + " 'age_61___65_years_old', 'age___65_years_old', 'av_no_trip', 'av_transit', \n", + " 'av_ridehail', 'av_walk', 'av_car', 'av_p_micro', 'av_unknown', 'av_s_micro', 'av_s_car'\n", + " ],\n", + " 'ride2own': [\n", + " 'has_drivers_license', 'is_student', 'is_paid', 'income_category', 'n_residence_members', \n", + " 'n_working_residents', 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles', \n", + " 'has_medical_condition', 'ft_job', 'multiple_jobs', 'highest_education_bachelor_s_degree', \n", + " 'highest_education_graduate_degree_or_professional_degree', \n", + " 'highest_education_high_school_graduate_or_ged', \n", + " 'highest_education_less_than_a_high_school_graduate', \n", + " 'highest_education_some_college_or_associates_degree', 'primary_job_description_Other', \n", + " 'primary_job_description_Professional, Manegerial, or Technical', \n", + " 'primary_job_description_Sales or service', 'gender_man', \n", + " 'gender_non_binary_genderqueer_gender_non_confor', 'gender_woman', 'age_16___20_years_old', \n", + " 'age_21___25_years_old', 'age_26___30_years_old', 'age_31___35_years_old', \n", + " 'age_36___40_years_old', 'age_41___45_years_old', 'age_51___55_years_old', \n", + " 'age_56___60_years_old', 'age___65_years_old', 'av_p_micro', 'av_s_car', 'av_car', \n", + " 'av_ridehail', 'av_walk', 'av_transit', 'av_no_trip', 'av_s_micro', 'av_unknown'\n", + " ]\n", "}\n", "\n", "\n", @@ -1095,191 +598,12 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "id": "5a3c6355", "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "For cluster -1:\n" - ] - }, - { - "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", - "
featurech
0is_student-0.0
24av_s_micro-0.0
23av_s_car-0.0
22av_no_trip-0.0
\n", - "
" - ], - "text/plain": [ - " feature ch\n", - "0 is_student -0.0\n", - "24 av_s_micro -0.0\n", - "23 av_s_car -0.0\n", - "22 av_no_trip -0.0" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "image/png": "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AQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAyRV0KbVx48a47rrrolevXlFWVha9e/eOH/3oR7F58+b6Y7Isi5qamqiqqoqysrIYMGBALFy4MI9TAwDklwwFALQFBV1K3XjjjTFx4sSYMGFCvPTSSzF27Nj4yU9+EjfffHP9MWPHjo1x48bFhAkTYu7cuVFZWRkDBw6M1atX53FyAID8kaEAgLagJN8DfJRnnnkmvvrVr8Ypp5wSERH77rtvTJ06NZ577rmI+OATvvHjx8e1114bZ555ZkRE3HXXXVFRURFTpkyJoUOHbvN16+rqoq6urv7+qlWrWvmdAACk0xoZSn4CAFpaQZ8p9cUvfjEee+yxePnllyMi4s9//nPMnj07Tj755IiIWLx4cdTW1sagQYPqn1NaWhr9+/ePOXPmbPd1x4wZE127dq2/9ezZs3XfCABAQq2RoeQnAKClFfSZUldffXWsXLky9t9//2jXrl1s2rQpbrjhhvjWt74VERG1tbUREVFRUdHgeRUVFfHaa69t93VHjhwZl19+ef39VatWCVYAQNFojQwlPwEALa2gS6l77703fvOb38SUKVPioIMOigULFsTw4cOjqqoqzjvvvPrjcrlcg+dlWdZo7cNKS0ujtLS01eYGAMin1shQ8hMA0NIKupS66qqr4pprrolvfvObERFxyCGHxGuvvRZjxoyJ8847LyorKyPig0/7evToUf+85cuXN/rkDwBgRyFDAQBtQUFfU2rt2rWx004NR2zXrl39jzPu1atXVFZWxowZM+ofX79+fcyaNSv69euXdFYAgEIhQwEAbUFBnyl12mmnxQ033BB77713HHTQQTF//vwYN25cfOc734mID045Hz58eIwePTqqq6ujuro6Ro8eHZ06dYrBgwfneXoAgPyQoQCAtqCgS6mbb745fvCDH8SwYcNi+fLlUVVVFUOHDo0f/vCH9ceMGDEi1q1bF8OGDYsVK1bEUUcdFdOnT4/y8vI8Tg4AkD8yFADQFhR0KVVeXh7jx4+P8ePHb/eYXC4XNTU1UVNTk2wuAIBCJkMBAG1BQV9TCgAAAIDipJQCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOQKvpR644034pxzzolu3bpFp06d4vDDD4958+bVP55lWdTU1ERVVVWUlZXFgAEDYuHChXmcGAAg/2QoAKDQFXQptWLFijjmmGOiffv28fDDD8eLL74YP/3pT2OXXXapP2bs2LExbty4mDBhQsydOzcqKytj4MCBsXr16vwNDgCQRzIUANAWlOR7gI9y4403Rs+ePWPSpEn1a/vuu2/9f2dZFuPHj49rr702zjzzzIiIuOuuu6KioiKmTJkSQ4cO3ebr1tXVRV1dXf39VatWtc4bAADIg9bIUPITANDSCvpMqQcffDD69u0b3/jGN2KPPfaIz33uc3H77bfXP7548eKora2NQYMG1a+VlpZG//79Y86cOdt93TFjxkTXrl3rbz179mzV9wEAkFJrZCj5CQBoaQVdSr3yyitx6623RnV1dTz66KNx8cUXx6WXXhr//u//HhERtbW1ERFRUVHR4HkVFRX1j23LyJEjY+XKlfW3pUuXtt6bAABIrDUylPwEALS0gv72vc2bN0ffvn1j9OjRERHxuc99LhYuXBi33nprfPvb364/LpfLNXhelmWN1j6stLQ0SktLW2doAIA8a40MJT8BAC2toM+U6tGjRxx44IEN1g444IBYsmRJRERUVlZGRDT6RG/58uWNPvkDANhRyFAAQFtQ0KXUMcccE4sWLWqw9vLLL8c+++wTERG9evWKysrKmDFjRv3j69evj1mzZkW/fv2SzgoAUChkKACgLSjob9/7/ve/H/369YvRo0fHWWedFX/605/itttui9tuuy0iPjjlfPjw4TF69Oiorq6O6urqGD16dHTq1CkGDx6c5+kBAPJDhgIA2oKCLqWOOOKIuP/++2PkyJHxox/9KHr16hXjx4+PIUOG1B8zYsSIWLduXQwbNixWrFgRRx11VEyfPj3Ky8vzODkAQP7IUABAW1DQpVRExKmnnhqnnnrqdh/P5XJRU1MTNTU16YYCAChwMhQAUOgK+ppSAAAAABSnZpVS7dq1i+XLlzdaf/vtt6Ndu3afeigAgGIkQwEAbNWsUirLsm2u19XVRYcOHT7VQAAAxUqGAgDYqknXlPr5z38eER9cg+BXv/pV7LzzzvWPbdq0KZ588snYf//9W3ZCAIA2ToYCAGisSaXUTTfdFBEffMo3ceLEBqeZd+jQIfbdd9+YOHFiy04IANDGyVAAAI01qZRavHhxREQcf/zxMW3atNh1111bZSgAgGIiQwEANNakUmqLmTNntvQcAABFT4YCANiqWaXUpk2bYvLkyfHYY4/F8uXLY/PmzQ0ef/zxx1tkOACAYiJDAQBs1axS6rLLLovJkyfHKaecEgcffHDkcrmWngsAoOjIUAAAWzWrlLrnnnviP/7jP+Lkk09u6XkAAIqWDAUAsNVOzXlShw4d4jOf+UxLzwIAUNRkKACArZpVSl1xxRXxs5/9LLIsa+l5AACKlgwFALBVs759b/bs2TFz5sx4+OGH46CDDor27ds3eHzatGktMhwAQDGRoQAAtmpWKbXLLrvEGWec0dKzAAAUNRkKAGCrZpVSkyZNauk5AACKngwFALBVs64pFRGxcePG+K//+q/45S9/GatXr46IiDfffDPWrFnTYsMBABQbGQoA4APNOlPqtddeiy9/+cuxZMmSqKuri4EDB0Z5eXmMHTs23n///Zg4cWJLzwkA0ObJUAAAWzXrTKnLLrss+vbtGytWrIiysrL69TPOOCMee+yxFhsOAKCYyFAAAFs1+6fvPf3009GhQ4cG6/vss0+88cYbLTIYAECxkaEAALZq1plSmzdvjk2bNjVaf/3116O8vPxTDwUAUIxkKACArZpVSg0cODDGjx9ffz+Xy8WaNWvi+uuvj5NPPrmlZgMAKCoyFADAVs369r2bbropjj/++DjwwAPj/fffj8GDB8df//rX6N69e0ydOrWlZwQAKAoyFADAVs0qpaqqqmLBggVxzz33xLx582Lz5s1x4YUXxpAhQxpctBMAgK1kKACArZpVSkVElJWVxQUXXBAXXHBBS84DAFDUZCgAgA8065pSY8aMiTvvvLPR+p133hk33njjpx4KAKAYyVAAAFs1q5T65S9/Gfvvv3+j9YMOOigmTpz4qYcCAChGMhQAwFbNKqVqa2ujR48ejdZ33333WLZs2aceCgCgGMlQAABbNauU6tmzZzz99NON1p9++umoqqr61EMBABQjGQoAYKtmXej8oosuiuHDh8eGDRviS1/6UkREPPbYYzFixIi44oorWnRAAIBiIUMBAGzVrFJqxIgR8c4778SwYcNi/fr1ERHRsWPHuPrqq2PkyJEtOiAAQLGQoQAAtmpyKbVp06aYPXt2XH311fGDH/wgXnrppSgrK4vq6uooLS1tjRkBANo8GQoAoKEml1Lt2rWLk046KV566aXo1atXHHHEEa0xFwBAUZGhAAAaataFzg855JB45ZVXWnoWAICiJkMBAGzVrFLqhhtuiCuvvDL+8Ic/xLJly2LVqlUNbgAANCZDAQBs1awLnX/5y1+OiIjTTz89crlc/XqWZZHL5WLTpk0tMx0AQBGRoQAAtmpWKTVz5syWngMAoOjJUAAAWzWrlOrfv39LzwEAUPRkKACArZp1TamIiKeeeirOOeec6NevX7zxxhsREfHrX/86Zs+e3WLDAQAUGxkKAOADzSqlfve738VJJ50UZWVl8fzzz0ddXV1ERKxevTpGjx7dogMCABQLGQoAYKtmlVI//vGPY+LEiXH77bdH+/bt69f79esXzz//fIsNBwBQTGQoAICtmlVKLVq0KI477rhG6126dIl33333084EAFCUZCgAgK2aVUr16NEj/va3vzVanz17dvTu3ftTDwUAUIxkKACArZpVSg0dOjQuu+yyePbZZyOXy8Wbb74Zd999d1x55ZUxbNiwlp4RAKAoyFAAAFuVNOdJI0aMiFWrVsXxxx8f77//fhx33HFRWloaV155ZVxyySUtPSMAQFGQoQAAtmpSKbV27dq46qqr4oEHHogNGzbEaaedFldccUVERBx44IGx8847t8qQAABtmQwFANBYk0qp66+/PiZPnhxDhgyJsrKymDJlSmzevDnuu+++1poPAKDNk6EAABprUik1bdq0uOOOO+Kb3/xmREQMGTIkjjnmmNi0aVO0a9euVQYEAGjrZCgAgMaadKHzpUuXxrHHHlt//8gjj4ySkpJ48803W3wwAIBiIUMBADTWpFJq06ZN0aFDhwZrJSUlsXHjxhYdCgCgmMhQAACNNenb97Isi/PPPz9KS0vr195///24+OKLo3PnzvVr06ZNa7kJAQDaOBkKAKCxJpVS5513XqO1c845p8WGAQAoRjIUAEBjTSqlJk2a1FpzAAAULRkKAKCxJl1TCgAAAABaglIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJNemSqkxY8ZELpeL4cOH169lWRY1NTVRVVUVZWVlMWDAgFi4cGH+hgQAKDAyFABQiNpMKTV37ty47bbb4tBDD22wPnbs2Bg3blxMmDAh5s6dG5WVlTFw4MBYvXp1niYFACgcMhQAUKjaRCm1Zs2aGDJkSNx+++2x66671q9nWRbjx4+Pa6+9Ns4888w4+OCD46677oq1a9fGlClT8jgxAED+yVAAQCFrE6XUd7/73TjllFPixBNPbLC+ePHiqK2tjUGDBtWvlZaWRv/+/WPOnDnbfb26urpYtWpVgxsAQLFpyQwlPwEALa0k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vjjfo7V5paWlcf311zc6XZ/WZ+/zx97nj73PD/u+45KhWo8/V/lh3/PH3uePvc8fe//p5bKsOH6+8S233BJjx46NZcuWxcEHHxw33XRTHHfccfkeCwCgoMlQAEC+FE0pBQAAAEDb0eavKQUAAABA26OUAgAAACA5pRQAAAAAySmlAAAAAEhOKUXccsst0atXr+jYsWP06dMnnnrqqY88vq6uLq699trYZ599orS0NP7lX/4l7rzzzkTTFpem7v3dd98dhx12WHTq1Cl69OgRF1xwQbz99tuJpi0OTz75ZJx22mlRVVUVuVwuHnjggY99zqxZs6JPnz7RsWPH6N27d0ycOLH1By1CTd37adOmxcCBA2P33XePLl26xNFHHx2PPvpommGLTHN+32/x9NNPR0lJSRx++OGtNh+0RfJT/shP+SFD5Y8MlR/yUxpKqR3cvffeG8OHD49rr7025s+fH8cee2x85StfiSVLlmz3OWeddVY89thjcccdd8SiRYti6tSpsf/++yecujg0de9nz54d3/72t+PCCy+MhQsXxn333Rdz586Niy66KPHkbdt7770Xhx12WEyYMOETHb948eI4+eST49hjj4358+fHv/3bv8Wll14av/vd71p50uLT1L1/8sknY+DAgfHQQw/FvHnz4vjjj4/TTjst5s+f38qTFp+m7v0WK1eujG9/+9txwgkntNJk0DbJT/kjP+WPDJU/MlR+yE+JZOzQjjzyyOziiy9usLb//vtn11xzzTaPf/jhh7OuXbtmb7/9dorxilpT9/4nP/lJ1rt37wZrP//5z7O99tqr1WYsdhGR3X///R95zIgRI7L999+/wdrQoUOzL3zhC604WfH7JHu/LQceeGA2atSolh9oB9KUvT/77LOz6667Lrv++uuzww47rFXngrZEfsof+akwyFD5I0Plh/zUepwptQNbv359zJs3LwYNGtRgfdCgQTFnzpxtPufBBx+Mvn37xtixY2PPPfeM/fbbL6688spYt25dipGLRnP2vl+/fvH666/HQw89FFmWxf/+7//Gb3/72zjllFNSjLzDeuaZZxr9Op100knx3HPPxYYNG/I01Y5p8+bNsXr16thtt93yPcoOYdKkSfH3v/89rr/++nyPAgVFfsof+altkaEKhwyVjvzUdCX5HoD8eeutt2LTpk1RUVHRYL2ioiJqa2u3+ZxXXnklZs+eHR07doz7778/3nrrrRg2bFi88847rovQBM3Z+379+sXdd98dZ599drz//vuxcePGOP300+Pmm29OMfIOq7a2dpu/Ths3boy33norevTokafJdjw//elP47333ouzzjor36MUvb/+9a9xzTXXxFNPPRUlJaICfJj8lD/yU9siQxUOGSoN+al5nClF5HK5BvezLGu0tsXmzZsjl8vF3XffHUceeWScfPLJMW7cuJg8ebJP+5qhKXv/4osvxqWXXho//OEPY968efHII4/E4sWL4+KLL04x6g5tW79O21qn9UydOjVqamri3nvvjT322CPf4xS1TZs2xeDBg2PUqFGx33775XscKFjyU/7IT22HDJV/MlQa8lPzqe92YN27d4927do1+mRp+fLljT7V2KJHjx6x5557RteuXevXDjjggMiyLF5//fWorq5u1ZmLRXP2fsyYMXHMMcfEVVddFRERhx56aHTu3DmOPfbY+PGPf+zTplZSWVm5zV+nkpKS6NatW56m2rHce++9ceGFF8Z9990XJ554Yr7HKXqrV6+O5557LubPnx+XXHJJRHzwD+osy6KkpCSmT58eX/rSl/I8JeSP/JQ/8lPbIkPlnwyVjvzUfM6U2oF16NAh+vTpEzNmzGiwPmPGjOjXr982n3PMMcfEm2++GWvWrKlfe/nll2OnnXaKvfbaq1XnLSbN2fu1a9fGTjs1/CPbrl27iNj6qRMt7+ijj2706zR9+vTo27dvtG/fPk9T7TimTp0a559/fkyZMsX1PxLp0qVLvPDCC7FgwYL628UXXxyf/exnY8GCBXHUUUfle0TIK/kpf+SntkWGyi8ZKi356VPIx9XVKRz33HNP1r59++yOO+7IXnzxxWz48OFZ586ds1dffTXLsiy75pprsnPPPbf++NWrV2d77bVX9vWvfz1buHBhNmvWrKy6ujq76KKL8vUW2qym7v2kSZOykpKS7JZbbsn+/ve/Z7Nnz8769u2bHXnkkfl6C23S6tWrs/nz52fz58/PIiIbN25cNn/+/Oy1117Lsqzxvr/yyitZp06dsu9///vZiy++mN1xxx1Z+/bts9/+9rf5egttVlP3fsqUKVlJSUn2i1/8Ilu2bFn97d13383XW2izmrr3/8xPj4GG5Kf8kZ/yR4bKHxkqP+SnNJRSZL/4xS+yffbZJ+vQoUP2+c9/Pps1a1b9Y+edd17Wv3//Bse/9NJL2YknnpiVlZVle+21V3b55Zdna9euTTx1cWjq3v/85z/PDjzwwKysrCzr0aNHNmTIkOz1119PPHXbNnPmzCwiGt3OO++8LMu2ve9PPPFE9rnPfS7r0KFDtu+++2a33npr+sGLQFP3vn///h95PJ9cc37ff5hQBY3JT/kjP+WHDJU/MlR+yE9p5LLMeasAAAAApOWaUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgooGAMGDIjhw4fne4xPZPLkybHLLrvkewwAgDbviSeeiFwuF++++26+RwESK8n3AABbTJs2Ldq3b99qr3/++efHu+++Gw888ECrfY1P44knnojjjz8+VqxYofACAHYY/fr1i2XLlkXXrl3zPQqQmFIKKBi77bZbvkcAACCxDh06RGVlZbOfv379+ujQoUMLTgSk4tv3gILx4W/fu+WWW6K6ujo6duwYFRUV8fWvf/0TvcZvf/vbOOSQQ6KsrCy6desWJ554Yrz33ntRU1MTd911V/z+97+PXC4XuVwunnjiiW2eLr5gwYLI5XLx6quv1q9Nnjw59t577+jUqVOcccYZ8fbbbzf62v/5n/8Zffr0iY4dO0bv3r1j1KhRsXHjxvrHc7lc/OpXv4ozzjgjOnXqFNXV1fHggw9GRMSrr74axx9/fERE7LrrrpHL5eL8889v2gYCADuURx55JL74xS/GLrvsEt26dYtTTz01/v73v0dExNFHHx3XXHNNg+P/8Y9/RPv27WPmzJkf+9rNzWIDBgyI733vezF8+PDYddddo6KiIm677bZ477334oILLojy8vL4l3/5l3j44Yfrn7OtPPb0009H//79o1OnTrHrrrvGSSedFCtWrKj/Gpdccklcfvnl0b179xg4cGBERMyaNSuOPPLIKC0tjR49esQ111zTIIsBhUcpBRSc5557Li699NL40Y9+FIsWLYpHHnkkjjvuuI993rJly+Jb3/pWfOc734mXXnopnnjiiTjzzDMjy7K48sor46yzzoovf/nLsWzZsli2bFn069fvE83z7LPPxne+850YNmxYLFiwII4//vj48Y9/3OCYRx99NM4555y49NJL48UXX4xf/vKXMXny5LjhhhsaHDdq1Kg466yz4i9/+UucfPLJMWTIkHjnnXeiZ8+e8bvf/S4iIhYtWhTLli2Ln/3sZ59wxwCAHdF7770Xl19+ecydOzcee+yx2GmnneKMM86IzZs3x5AhQ2Lq1KmRZVn98ffee29UVFRE//79P/J1m5vFtrjrrruie/fu8ac//Sm+973vxf/9v/83vvGNb0S/fv3i+eefj5NOOinOPffcWLt27Tafv2DBgjjhhBPioIMOimeeeSZmz54dp512WmzatKnB1ygpKYmnn346fvnLX8Ybb7wRJ598chxxxBHx5z//OW699da44447GmU2oMBkAAWif//+2WWXXZb97ne/y7p06ZKtWrWqSc+fN29eFhHZq6++us3HzzvvvOyrX/1qg7WZM2dmEZGtWLGifm3+/PlZRGSLFy/OsizLvvWtb2Vf/vKXGzzv7LPPzrp27Vp//9hjj81Gjx7d4Jhf//rXWY8ePervR0R23XXX1d9fs2ZNlsvlsocffni7swAAfFLLly/PIiJ74YUXsuXLl2clJSXZk08+Wf/40UcfnV111VUf+zrNzWJZ9kGe++IXv1h/f+PGjVnnzp2zc889t35t2bJlWURkzzzzTJZljTPQt771reyYY475yK9x+OGHN1j7t3/7t+yzn/1stnnz5vq1X/ziF9nOO++cbdq0qcnvA0jDmVJAwRk4cGDss88+0bt37zj33HPj7rvv3u4naR922GGHxQknnBCHHHJIfOMb34jbb7+9/jTvT+Oll16Ko48+usHaP9+fN29e/OhHP4qdd965/vav//qvsWzZsgazH3roofX/3blz5ygvL4/ly5d/6hkBgB3P3//+9xg8eHD07t07unTpEr169YqIiCVLlsTuu+8eAwcOjLvvvjsiIhYvXhzPPPNMDBky5GNft7lZbIsP55127dpFt27d4pBDDqlfq6ioiIjYbgbacqbUR+nbt2+D+1vyWi6Xq1875phjYs2aNfH6669/4tmBtJRSQMEpLy+P559/PqZOnRo9evSIH/7wh3HYYYd97I8JbteuXcyYMSMefvjhOPDAA+Pmm2+Oz372s7F48eLtPmennT7432D2oVPbN2zY0OCYDz+2PZs3b45Ro0bFggUL6m8vvPBC/PWvf42OHTvWH/fPP10wl8vF5s2bP/b1AQD+2WmnnRZvv/123H777fHss8/Gs88+GxEfXPg7ImLIkCHx29/+NjZs2BBTpkyJgw46KA477LCPfd3mZrEttpV3Pry2pTjaXgYqKyv72K/RuXPnBvezLGtQSG1Z+/DXAwqPUgooSCUlJXHiiSfG2LFj4y9/+Uu8+uqr8fjjj3/s83K5XBxzzDExatSomD9/fnTo0CHuv//+iPjgJ7t8+FoEERG77757RHxwPaotFixY0OCYAw88MP74xz82WPvn+5///Odj0aJF8ZnPfKbRbUvx9XG2/NSYf54RAOCfvf322/HSSy/FddddFyeccEIccMABjc4Q/9rXvhbvv/9+PPLIIzFlypQ455xzPvHrNzeLtYRDDz00HnvssSY958ADD4w5c+Y0+DBxzpw5UV5eHnvuuWdLjwi0kJJ8DwDwz/7whz/EK6+8Escdd1zsuuuu8dBDD8XmzZvjs5/97Ec+79lnn43HHnssBg0aFHvssUc8++yz8Y9//CMOOOCAiIjYd99949FHH41FixZFt27domvXrvGZz3wmevbsGTU1NfHjH/84/vrXv8ZPf/rTBq976aWXRr9+/WLs2LHxta99LaZPnx6PPPJIg2N++MMfxqmnnho9e/aMb3zjG7HTTjvFX/7yl3jhhRc+8QU299lnn8jlcvGHP/whTj755CgrK4udd965CTsHAOwodt111+jWrVvcdttt0aNHj1iyZEmjn7bXuXPn+OpXvxo/+MEP4qWXXorBgwd/otdubhZrKSNHjoxDDjkkhg0bFhdffHF06NAhZs6cGd/4xjeie/fu23zOsGHDYvz48fG9730vLrnkkli0aFFcf/31cfnll3/iDwiB9PzpBArOLrvsEtOmTYsvfelLccABB8TEiRNj6tSpcdBBB33k87p06RJPPvlknHzyybHffvvFddddFz/96U/jK1/5SkRE/Ou//mt89rOfjb59+8buu+8eTz/9dLRv3z6mTp0a//M//xOHHXZY3HjjjY1KpC984Qvxq1/9Km6++eY4/PDDY/r06XHdddc1OOakk06KP/zhDzFjxow44ogj4gtf+EKMGzcu9tlnn0/8vvfcc88YNWpUXHPNNVFRURGXXHLJJ34uALBj2WmnneKee+6JefPmxcEHHxzf//734yc/+Umj44YMGRJ//vOf49hjj4299977E712c7NYS9lvv/1i+vTp8ec//zmOPPLIOProo+P3v/99lJRs/5yKPffcMx566KH405/+FIcddlhcfPHFceGFFzbKbEBhyWWf5GIpAAAAANCCnCkFAAAAQHJKKaDNWLJkSey8887bvS1ZsiTfIwIAFLynnnrqIzPV9shiQEvz7XtAm7Fx48Z49dVXt/v4vvvu+5HXGgAAIGLdunXxxhtvbPfxz3zmM9tcl8WAlqaUAgAAACA5374HAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQXEm+BygEmzdvjjfffDPKy8sjl8vlexwAoIBkWRarV6+Oqqqq2Gknn+dtIT8BANvzSfOTUioi3nzzzejZs2e+xwAACtjSpUtjr732yvcYBUN+AgA+zsflJ6VURJSXl0fEB5vVpUuXPE8DABSSVatWRc+ePevzAh+QnwCA7fmk+UkpFVF/ynmXLl2EKgBgm3yLWkPyEwDwcT4uP7kwAgAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJJfXUurJJ5+M0047LaqqqiKXy8UDDzzQ4PEsy6KmpiaqqqqirKwsBgwYEAsXLmxwTF1dXXzve9+L7t27R+fOneP000+P119/PeG7AABIS4YCAIpBXkup9957Lw477LCYMGHCNh8fO3ZsjBs3LiZMmBBz586NysrKGDhwYKxevbr+mOHDh8f9998f99xzT8yePTvWrFkTp556amzatCnV2wAASEqGAgCKQS7LsizfQ0RE5HK5uP/+++NrX/taRHzwCV9VVVUMHz48rr766oj44BO9ioqKuPHGG2Po0KGxcuXK2H333ePXv/51nH322RER8eabb0bPnj3joYceipNOOmmbX6uuri7q6urq769atSp69uwZK1eujC5durTK+1uyZEm89dZbrfLaALCj6969e+y9996t8tqrVq2Krl27tmpO+DRSZSj5CQCKSyHkp5JW+eotYPHixVFbWxuDBg2qXystLY3+/fvHnDlzYujQoTFv3rzYsGFDg2Oqqqri4IMPjjlz5my3lBozZkyMGjWq1d/DFkuWLIn99z8g1q1bm+xrAsCOpKysU/zP/7zUasGqLWmtDCU/AUBxKYT8VLClVG1tbUREVFRUNFivqKiI1157rf6YDh06xK677tromC3P35aRI0fG5ZdfXn9/yyd9reWtt96KdevWxlHfuT669Ni31b4OAOyIVi17NZ69c1S89dZbSqlovQwlPwFA8SiU/FSwpdQWuVyuwf0syxqt/bOPO6a0tDRKS0tbZL6m6NJj39ht788m/7oAwI6npTOU/AQAtLS8Xuj8o1RWVkZENPq0bvny5fWf/FVWVsb69etjxYoV2z0GAGBHIkMBAG1FwZZSvXr1isrKypgxY0b92vr162PWrFnRr1+/iIjo06dPtG/fvsExy5Yti//+7/+uPwYAYEciQwEAbUVev31vzZo18be//a3+/uLFi2PBggWx2267xd577x3Dhw+P0aNHR3V1dVRXV8fo0aOjU6dOMXjw4IiI6Nq1a1x44YVxxRVXRLdu3WK33XaLK6+8Mg455JA48cQT8/W2AABalQwFABSDvJZSzz33XBx//PH197dcPPO8886LyZMnx4gRI2LdunUxbNiwWLFiRRx11FExffr0KC8vr3/OTTfdFCUlJXHWWWfFunXr4oQTTojJkydHu3btkr8fAIAUZCgAoBjktZQaMGBAZFm23cdzuVzU1NRETU3Ndo/p2LFj3HzzzXHzzTe3woQAAIVHhgIAikHBXlMKAAAAgOKllAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJBcQZdSGzdujOuuuy569eoVZWVl0bt37/jRj34Umzdvrj8my7KoqamJqqqqKCsriwEDBsTChQvzODUAQH7JUABAW1DQpdSNN94YEydOjAkTJsRLL70UY8eOjZ/85Cdx88031x8zduzYGDduXEyYMCHmzp0blZWVMXDgwFi9enUeJwcAyB8ZCgBoCwq6lHrmmWfiq1/9apxyyimx7777xte//vUYNGhQPPfccxHxwSd848ePj2uvvTbOPPPMOPjgg+Ouu+6KtWvXxpQpU/I8PQBAfshQAEBbUNCl1Be/+MV47LHH4uWXX46IiD//+c8xe/bsOPnkkyMiYvHixVFbWxuDBg2qf05paWn0798/5syZs93Xrauri1WrVjW4AQAUi9bIUPITANDSSvI9wEe5+uqrY+XKlbH//vtHu3btYtOmTXHDDTfEt771rYiIqK2tjYiIioqKBs+rqKiI1157bbuvO2bMmBg1alTrDQ4AkEetkaHkJwCgpRX0mVL33ntv/OY3v4kpU6bE888/H3fddVf8v//3/+Kuu+5qcFwul2twP8uyRmsfNnLkyFi5cmX9benSpa0yPwBAPrRGhpKfAICWVtBnSl111VVxzTXXxDe/+c2IiDjkkEPitddeizFjxsR5550XlZWVEfHBp309evSof97y5csbffL3YaWlpVFaWtq6wwMA5ElrZCj5CQBoaQV9ptTatWtjp50ajtiuXbv6H2fcq1evqKysjBkzZtQ/vn79+pg1a1b069cv6awAAIVChgIA2oKCPlPqtNNOixtuuCH23nvvOOigg2L+/Pkxbty4+M53vhMRH5xyPnz48Bg9enRUV1dHdXV1jB49Ojp16hSDBw/O8/QAAPkhQwEAbUFBl1I333xz/OAHP4hhw4bF8uXLo6qqKoYOHRo//OEP648ZMWJErFu3LoYNGxYrVqyIo446KqZPnx7l5eV5nBwAIH9kKACgLSjoUqq8vDzGjx8f48eP3+4xuVwuampqoqam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KQUAAABAckop4pZbbolevXpFx44do0+fPvHUU0995PF1dXVx7bXXxj777BOlpaXxL//yL3HnnXcmmra4NHXv77777jjssMOiU6dO0aNHj7jgggvi7bffTjRtcXjyySfjtNNOi6qqqsjlcvHAAw987HNmzZoVffr0iY4dO0bv3r1j4sSJrT9oEWrq3k+bNi0GDhwYu+++e3Tp0iWOPvroePTRR9MMW2Sa8/t+i6effjpKSkri8MMPb7X5oBisWLEizj333OjatWt07do1zj333Hj33Xc/8fOHDh0auVwuxo8f32ozFqum7v2GDRvi6quvjkMOOSQ6d+4cVVVV8e1vfzvefPPNdEO3UU3NrjJUy2nK3stQLaupv++3kKE+GaXUDu7ee++N4cOHx7XXXhvz58+PY489Nr7yla/EkiVLtvucs846Kx577LG44447YtGiRTF16tTYf//9E05dHJq697Nnz45vf/vbceGFF8bChQvjvvvui7lz58ZFF12UePK27b333ovDDjssJkyY8ImOX7x4cZx88slx7LHHxvz58+Pf/u3f4tJLL43f/e53rTxp8Wnq3j/55JMxcODAeOihh2LevHlx/PHHx2mnnRbz589v5UmLT1P3fouVK1fGt7/97TjhhBNaaTIoHoMHD44FCxbEI488Eo888kgsWLAgzj333E/03AceeCCeffbZqKqqauUpi1NT937t2rXx/PPPxw9+8IN4/vnnY9q0afHyyy/H6aefnnDqtqep2VWGajlN3XsZquU059/LETJUk2Ts0I488sjs4osvbrC2//77Z9dcc802j3/44Yezrl27Zm+//XaK8YpaU/f+Jz/5Sda7d+8Gaz//+c+zvfbaq9VmLHYRkd1///0fecyIESOy/fffv8Ha0KFDsy984QutOFnx+yR7vy0HHnhgNmrUqJYfaAfSlL0/++yzs+uuuy67/vrrs8MOO6xV54K27MUXX8wiIvvjH/9Yv/bMM89kEZH9z//8z0c+9/XXX8/23HPP7L//+7+zffbZJ7vppptaedri8mn2/sP+9Kc/ZRGRvfbaa60xZlFoanaVoVpOU/d+W2So5mnu3stQn5wzpXZg69evj3nz5sWgQYMarA8aNCjmzJmzzec8+OCD0bdv3xg7dmzsueeesd9++8WVV14Z69atSzFy0WjO3vfr1y9ef/31eOihhyLLsvjf//3f+O1vfxunnHJKipF3WM8880yjX6eTTjopnnvuudiwYUOeptoxbd68OVavXh277bZbvkfZIUyaNCn+/ve/x/XXX5/vUaDgPfPMM9G1a9c46qij6te+8IUvRNeuXbf793rEB/9fO/fcc+Oqq66Kgw46KMWoRae5e//PVq5cGblcLnbZZZdWmLLta052laFaRnP2/p/JUM3T3L2XoZqmJN8DkD9vvfVWbNq0KSoqKhqsV1RURG1t7Taf88orr8Ts2bOjY8eOcf/998dbb70Vw4YNi3feecd1pZqgOXvfr1+/uPvuu+Pss8+O999/PzZu3Binn3563HzzzSlG3mHV1tZu89dp48aN8dZbb0WPHj3yNNmO56c//Wm89957cdZZZ+V7lKL317/+Na655pp46qmnoqREVICPU1tbG3vssUej9T322GO7f69HRNx4441RUlISl156aWuOV9Sau/cf9v7778c111wTgwcPji5durT0iEWhOdlVhmoZzdn7fyZDNU9z9l6GajpnShG5XK7B/SzLGq1tsXnz5sjlcnH33XfHkUceGSeffHKMGzcuJk+e7GypZmjK3r/44otx6aWXxg9/+MOYN29ePPLII7F48eK4+OKLU4y6Q9vWr9O21mk9U6dOjZqamrj33nu3+Y8PWs6mTZti8ODBMWrUqNhvv/3yPQ7kVU1NTeRyuY+8PffccxGx7b8TPurv9Xnz5sXPfvazmDx5sr9PtqE19/7DNmzYEN/85jdj8+bNccstt7T4+yg2Tcmu2zt+W+t8vKbu/RYy1Kf3Sfdehmoe1d0OrHv37tGuXbtGLe/y5csbtcFb9OjRI/bcc8/o2rVr/doBBxwQWZbF66+/HtXV1a06c7Fozt6PGTMmjjnmmLjqqqsiIuLQQw+Nzp07x7HHHhs//vGPfdrUSiorK7f561RSUhLdunXL01Q7lnvvvTcuvPDCuO++++LEE0/M9zhFb/Xq1fHcc8/F/Pnz45JLLomIDz6QyLIsSkpKYvr06fGlL30pz1NCGpdcckl885vf/Mhj9t133/jLX/4S//u//9vosX/84x/b/Xv9qaeeiuXLl8fee+9dv7Zp06a44oorYvz48fHqq69+qtnbutbc+y02bNgQZ511VixevDgef/xxZ0l9hOZkVxmqZTRn77eQoT6dpu69DNU8SqkdWIcOHaJPnz4xY8aMOOOMM+rXZ8yYEV/96le3+Zxjjjkm7rvvvlizZk3svPPOERHx8ssvx0477RR77bVXkrmLQXP2fu3atY1OAW3Xrl1EbP3UiZZ39NFHx3/+5382WJs+fXr07ds32rdvn6epdhxTp06N73znOzF16lTXT0ukS5cu8cILLzRYu+WWW+Lxxx+P3/72t9GrV688TQbpde/ePbp37/6xxx199NGxcuXK+NOf/hRHHnlkREQ8++yzsXLlyujXr982n3Puuec2+kfiSSedFOeee25ccMEFn374Nq419z5iayH117/+NWbOnKkk+RjNya4yVMtozt5HyFAtoal7L0M1Uz6urk7huOeee7L27dtnd9xxR/biiy9mw4cPzzp37py9+uqrWZZl2TXXXJOde+659cevXr0622uvvbKvf/3r2cKFC7NZs2Zl1dXV2UUXXZSvt9BmNXXvJ02alJWUlGS33HJL9ve//z2bPXt21rdv3+zII4/M11tok1avXp3Nnz8/mz9/fhYR2bhx47L58+fX/7Sdf973V155JevUqVP2/e9/P3vxxRezO+64I2vfvn3229/+Nl9voc1q6t5PmTIlKykpyX7xi19ky5Ytq7+9++67+XoLbVZT9/6f+ckx8PG+/OUvZ4ceemj2zDPPZM8880x2yCGHZKeeemqDYz772c9m06ZN2+5r+Ol7zdPUvd+wYUN2+umnZ3vttVe2YMGCBn/H1NXV5eMttAlNza4yVMtp6t7LUC2nqXv/z2Soj6eUIvvFL36R7bPPPlmHDh2yz3/+89msWbPqHzvvvPOy/v37Nzj+pZdeyk488cSsrKws22uvvbLLL788W7t2beKpi0NT9/7nP/95duCBB2ZlZWVZjx49siFDhmSvv/564qnbtpkzZ2YR0eh23nnnZVm27X1/4oknss997nNZhw4dsn333Te79dZb0w9eBJq69/379//I4/nkmvP7/sMEKvh4b7/9djZkyJCsvLw8Ky8vz4YMGZKtWLGiwTERkU2aNGm7r6GUap6m7v3ixYu3+f/EiMhmzpyZfP62pKnZVYZqOU3ZexmqZTX19/2HyVAfL5dlvu8HAAAAgLT89D0AAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAAre5MmTY5dddsn3GEALymVZluV7CAAAAHY8559/frz77rvxwAMPfOyx69ati9WrV8cee+zR+oMBSZTkewAAPrBhw4Zo3759vscAACg4GzZsiLKysigrK8v3KEAL8u17QJvwyCOPxBe/+MXYZZddolu3bnHqqafG3//+94iIOProo+Oaa65pcPw//vGPaN++fcycOfNjX/uWW26J6urq6NixY1RUVMTXv/71TzTT5s2b48Ybb4zPfOYzUVpaGnvvvXfccMMN9Y9fffXVsd9++0WnTp2id+/e8YMf/CA2bNhQ/3hNTU0cfvjhceedd0bv3r2jtLQ0nLwKADRVa+akfffdN0aPHh3f+c53ory8PPbee++47bbbGhzzwgsvxJe+9KUoKyuLbt26xf/5P/8n1qxZ87GvXVNTE3fddVf8/ve/j1wuF7lcLp544ol49dVXI5fLxX/8x3/EgAEDomPHjvGb3/ym0bfvbclSv/zlL6Nnz57RqVOn+MY3vhHvvvvux28a/P/bu7uQJtswDuD/rWWaXw1ZTgpnMpOlZNA8MMsgsyyIVYSFUzyIDiob2JeEzUlnWVFBVOhBnTittIK0JmQHyTKxchW5BEt7ohYTCyTte/d78L6OfF9103Lmy/8Hgs/9cV3PvaOLi2d76I/AphQRTQsDAwPYu3cv2tra0NTUBLlcjk2bNsHj8cBoNKK6unpYQ+fSpUuIjo7GypUrx4z74MEDmEwmHDlyBJ2dnbDZbMjIyPDrng4dOoSjR4/CbDajo6MDVqsV0dHR3vnw8HBcvHgRHR0dOH36NCorK3Hy5MlhMbq6unD58mXU1dXB4XD4/4EQERER/WOy6qQhJ06cgF6vR3t7O3bt2oWdO3fi+fPnAIDBwUFkZ2dDqVSira0NV65cwe3bt1FYWOgz7v79+5GTk4Ps7Gy4XC64XC4sW7bMO19cXAyTyQSn04m1a9eOGGOolrpx4wZsNhscDgd2797t17mI6A8giIimIbfbLQCIp0+fCrfbLRQKhbh79653Pi0tTRw4cMBnnLq6OhERESH6+/vHlb+/v1/MmjVLVFZW+r2nvLxcLF261HttsVjEzJkzhdvtHlduIiIiorH8rjpJCCE0Go3Iy8vzXns8HjF37lxx7tw5IYQQFRUVQqlUio8fP3rXNDQ0CLlcLt69e+czfkFBgTAYDMPGuru7BQBx6tSpYeMXLlwQkZGR3muLxSJmzJghXr9+7R27deuWkMvlwuVy+XU+IppafFKKiKaFFy9eIDc3F/Hx8YiIiMCCBQsAAJIkQaVSISsrC1VVVQCA7u5utLS0wGg0+oyblZUFjUaD+Ph45Ofno6qqCoODgz73OZ1OfPnyBZmZmaOuqa2txfLly6FWqxEWFgaz2QxJkoat0Wg0UKlUPvMRERERjWay6qQhixcv9v4vk8mgVqvhdrsB/F0TpaSkIDQ01LsmPT0dHo8HnZ2dv3QuvV7vc01sbCzmz5/vvU5LS/stuYkoMNiUIqJpYcOGDejr60NlZSVaW1vR2toKAPj69SsAwGg0ora2Ft++fYPVakVSUhJSUlJ8xg0PD8ejR49QXV2NmJgYlJaWIiUlxedvEfj6kc379+9j27ZtWLduHerr69He3o6SkhLv/Q75uYAjIiIimojJqpOG/PtFLDKZDB6PBwAghIBMJhtx32jj/ppInTSU81dzE1FgsClFRH+8vr4+OJ1OHD58GJmZmdDpdPjw4cOwNRs3bsTnz59hs9lgtVqRl5fnd3yFQoHVq1ejvLwcT548QU9PD+7cuTPmnoSEBISEhKCpqWnEebvdDo1Gg5KSEuj1eiQkJODVq1d+3xMRERGRPya7TvJl0aJFcDgcGBgY8I7Z7XbI5XIsXLjQ5/6goCD8+PFjwvklScLbt2+91y0tLX7nJqKpp5jqGyAi8kWpVCIqKgoVFRWIiYmBJEn/eYtMaGgoDAYDzGYznE4ncnNz/YpdX1+Ply9fIiMjA0qlEjdv3oTH40FiYuKY+4KDg1FcXIyDBw8iKCgI6enp6O3txbNnz7B9+3ZotVpIkoSamhqkpqaioaEB165dm/BnQERERDSSyayT/GE0GmGxWFBQUICysjL09vZiz549yM/PH/YCmNHExcWhsbERnZ2diIqKQmRk5LjyBwcHo6CgAMePH0d/fz9MJhNycnKgVqsneiQiCiA+KUVEfzy5XI6amho8fPgQycnJKCoqwrFjx/6zzmg04vHjx1ixYgViY2P9ij1nzhxcvXoVq1atgk6nw/nz51FdXY2kpCSfe81mM/bt24fS0lLodDps3brV+/sKBoMBRUVFKCwsxJIlS3Dv3j2YzebxHZyIiIjIh8msk/wxe/ZsNDY24v3790hNTcWWLVuQmZmJM2fO+LV/x44dSExMhF6vh0qlgt1uH1d+rVaLzZs3Y/369VizZg2Sk5Nx9uzZiRyFiKaATIif3g1KRERERERENA2UlZXh+vXrcDgcU30rRDRBfFKKiIiIiIiIiIgCjk0pIvpfa25uRlhY2Kh/o5Ekacx9kiQF8BREREREv99E66TxGCt+c3Pzb8lBRNMXv75HRP9rnz59wps3b0ad12q1I45///4dPT09o+6Li4uDQsF3RRAREdH0NdE6aTy6urpGnZs3bx5CQkJ+OQcRTV9sShERERERERERUcDx63tERERERERERBRwbEoREREREREREVHAsSlFREREREREREQBx6YUEREREREREREFHJtSREREREREREQUcGxKERERERERERFRwLEpRUREREREREREAfcXzmcQWlVOk54AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "For cluster 0:\n" - ] - }, - { - "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", - "
featurech
0is_student-0.0
23av_s_car-0.0
22av_no_trip-0.0
21av_ridehail-0.0
\n", - "
" - ], - "text/plain": [ - " feature ch\n", - "0 is_student -0.0\n", - "23 av_s_car -0.0\n", - "22 av_no_trip -0.0\n", - "21 av_ridehail -0.0" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "image/png": "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uzjppJOirKwsnnnmmairq4uIiLVr18bYsWNbdEAAgGIhQwEAbNWsUuqHP/xhTJ48OW677bZo3759/Xr//v3jmWeeabHhAACKiQwFALBVs0qpF154IY477rhG6507d4633nrrk84EAFCUZCgAgK2aVUp169Yt/v73vzdanzt3bvTu3fsTDwUAUIxkKACArZpVSg0bNiwuv/zyeOqppyKXy8Xy5cvjrrvuiquuuiqGDx/e0jMCABQFGQoAYKuS5jxp5MiRsWbNmjj++OPjnXfeieOOOy5KS0vjqquuiksvvbSlZwQAKAoyFADAVk0qpdavXx/f+9734v77749NmzbFaaedFldeeWVERBx00EGx2267tcqQAABtmQwFANBYk0qp66+/PqZOnRpDhw6NsrKymDZtWmzZsiV++9vfttZ8AABtngwFANBYk0qpGTNmxO233x7nnHNOREQMHTo0jj766Ni8eXO0a9euVQYEAGjrZCgAgMaadKHzZcuWxbHHHlt//4gjjoiSkpJYvnx5iw8GAFAsZCgAgMaaVEpt3rw5OnTo0GCtpKQk3n333RYdCgCgmMhQAACNNenH97IsiwsuuCBKS0vr195555245JJLYtddd61fmzFjRstNCADQxslQAACNNamUOv/88xutnXvuuS02DABAMZKhAAAaa1IpNWXKlNaaAwCgaMlQAACNNemaUgAAAADQEpRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAILk2VUqNGzcucrlcjBgxon4ty7KoqamJqqqqKCsri4EDB8bixYvzNyQAQIGRoQCAQtRmSqn58+fHrbfeGp/97GcbrI8fPz4mTJgQkyZNivnz50dlZWUMGjQo1q5dm6dJAQAKhwwFABSqNlFKrVu3LoYOHRq33XZb7LHHHvXrWZbFxIkTY/To0XHmmWdGnz594s4774z169fHtGnT8jgxAED+yVAAQCFrE6XUt7/97TjllFPixBNPbLC+ZMmSqK2tjcGDB9evlZaWxoABA2LevHnbfb26urpYs2ZNgxsAQLFpyQwlPwEALa0k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trZ2m8956aWXYu7cudGxY8e477774vXXX4/hw4fHm2++6boITdCcve/fv3/cddddcfbZZ8c777wT7777bpx++ulx0003pRh5p1VbW7vNf0/vvvtuvP7669GtW7c8Tbbz+clPfhJvv/12nHXWWfkepej97W9/i2uuuSYef/zxKCkRFeCD5Kf8kZ/aFhmqcMhQachPzeNMKSKXyzW4n2VZo7X3bdmyJXK5XNx1111xxBFHxMknnxwTJkyIqVOn+rSvGZqy988991xcdtll8f3vfz8WLFgQDz30UCxZsiQuueSSFKPu1Lb172lb67Se6dOnR01NTdxzzz2xzz775HucorZ58+YYMmRIjBkzJvbff/98jwMFS37KH/mp7ZCh8k+GSkN+aj713U5sr732inbt2jX6ZGnlypWNPtV4X7du3eJTn/pUdOnSpX7twAMPjCzL4tVXX43q6upWnblYNGfvx40bF0cffXR873vfi4iIz372s7HrrrvGscceGz/84Q992tRKKisrt/nvqaSkJLp27ZqnqXYu99xzT1x00UXx29/+Nk488cR8j1P01q5dG08//XQsXLgwLr300oh473+osyyLkpKSmDlzZnzxi1/M85SQP/JT/shPbYsMlX8yVDryU/M5U2on1qFDh+jbt2/MmjWrwfqsWbOif//+23zO0UcfHcuXL49169bVr7344ouxyy67xL777tuq8xaT5uz9+vXrY5ddGn7LtmvXLiK2fupEyzvqqKMa/XuaOXNm9OvXL9q3b5+nqXYe06dPjwsuuCCmTZvm+h+JdO7cOZ599tlYtGhR/e2SSy6Jz3zmM7Fo0aI48sgj8z0i5JX8lD/yU9siQ+WXDJWW/PQJ5OPq6hSOu+++O2vfvn12++23Z88991w2YsSIbNddd81efvnlLMuy7JprrsnOO++8+uPXrl2b7bvvvtnXvva1bPHixdmcOXOy6urq7OKLL87XW2izmrr3U6ZMyUpKSrKbb745+8c//pHNnTs369evX3bEEUfk6y20SWvXrs0WLlyYLVy4MIuIbMKECdnChQuzV155Jcuyxvv+0ksvZZ06dcq++93vZs8991x2++23Z+3bt8/uvffefL2FNqupez9t2rSspKQk+/nPf56tWLGi/vbWW2/l6y20WU3d+w/z22OgIfkpf+Sn/JGh8keGyg/5KQ2lFNnPf/7zrEePHlmHDh2yz3/+89mcOXPqHzv//POzAQMGNDj++eefz0488cSsrKws23fffbMrrrgiW79+feKpi0NT9/5nP/tZdtBBB2VlZWVZt27dsqFDh2avvvpq4qnbtkceeSSLiEa3888/P8uybe/7o48+mn3uc5/LOnTokPXs2TO75ZZb0g9eBJq69wMGDPjI49lxzflz/0FCFTQmP+WP/JQfMlT+yFD5IT+lkcsy560CAAAAkJZrSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySimgYAwcODBGjBiR7zF2yNSpU2P33XfP9xgAAABtVkm+BwB434wZM6J9+/at9voXXHBBvPXWW3H//fe32tf4JB599NE4/vjjY9WqVQovAACg6CmlgIKx55575nsEAADakE2bNrXqh5pA6/Lje0DB+OCP7918881RXV0dHTt2jIqKivja1762Q69x7733xiGHHBJlZWXRtWvXOPHEE+Ptt9+OmpqauPPOO+P3v/995HK5yOVy8eijj8ajjz4auVwu3nrrrfrXWLRoUeRyuXj55Zfr16ZOnRr77bdfdOrUKc4444x44403Gn3tf//3f4++fftGx44do3fv3jFmzJh499136x/P5XLxy1/+Ms4444zo1KlTVFdXxx/+8IeIiHj55Zfj+OOPj4iIPfbYI3K5XFxwwQVN20AAgA946KGH4phjjondd989unbtGqeeemr84x//iIiIo446Kq655poGx//zn/+M9u3bxyOPPPKxr93crLZly5a44YYb4tOf/nSUlpbGfvvtFz/60Y/qH7/66qtj//33j06dOkXv3r3juuuui02bNtU/XlNTE4cddljccccd0bt37ygtLY0sy3boawOFRykFFJynn346LrvssvjBD34QL7zwQjz00ENx3HHHfezzVqxYEf/6r/8a3/zmN+P555+PRx99NM4888zIsiyuuuqqOOuss+JLX/pSrFixIlasWBH9+/ffoXmeeuqp+OY3vxnDhw+PRYsWxfHHHx8//OEPGxzzpz/9Kc4999y47LLL4rnnnotf/OIXMXXq1AYhKyJizJgxcdZZZ8Vf//rXOPnkk2Po0KHx5ptvRvfu3eN3v/tdRES88MILsWLFivjpT3+6gzsGANDY22+/HVdccUXMnz8/Zs+eHbvsskucccYZsWXLlhg6dGhMnz69QaFzzz33REVFRQwYMOAjX7e5WS0iYtSoUXHDDTfEddddF88991xMmzYtKioq6h8vLy+PqVOnxnPPPRc//elP47bbbosbb7yxwWv8/e9/j9/85jfxu9/9LhYtWrTjGwIUnFymVgYKxMCBA+Owww6L4447Li688MJ49dVXo7y8fIef/8wzz0Tfvn3j5Zdfjh49ejR6fFvXlNrWdZwWLVoUn/vc52LJkiXRs2fPGDJkSKxatSoefPDB+uedc8458dBDD9WfYXXcccfFl7/85Rg1alT9Mb/+9a9j5MiRsXz58oh470ypa6+9Nv7P//k/EfFeUCwvL48HHnggvvSlL7mmFADQqv75z3/GPvvsE88++2xUVFREVVVVPPzww3HsscdGRET//v3jmGOOifHjx3/k68yYMaNZWW3t2rWx9957x6RJk+Liiy/eoef8+Mc/jnvuuSeefvrpiHjvTKmxY8fGa6+9FnvvvfcOf22gMDlTCig4gwYNih49ekTv3r3jvPPOi7vuuivWr1//sc879NBD44QTTohDDjkkvv71r8dtt90Wq1at+sTzPP/883HUUUc1WPvw/QULFsQPfvCD2G233epv3/rWt2LFihUNZv/sZz9b/8+77rprlJeXx8qVKz/xjAAAH/aPf/wjhgwZEr17947OnTtHr169IiJi6dKlsffee8egQYPirrvuioiIJUuWxJNPPhlDhw792NdtblZ7/vnno66uLk444YTtHnPvvffGMcccE5WVlbHbbrvFddddF0uXLm1wTI8ePRRSUCSUUkDBKS8vj2eeeSamT58e3bp1i+9///tx6KGHNrju07a0a9cuZs2aFQ8++GAcdNBBcdNNN8VnPvOZWLJkyXafs8su7/01+MGTRj943YIPP7Y9W7ZsiTFjxsSiRYvqb88++2z87W9/i44dO9Yf9+ELceZyudiyZcvHvj4AQFOddtpp8cYbb8Rtt90WTz31VDz11FMREbFx48aIiBg6dGjce++9sWnTppg2bVocfPDBceihh37s6zY3q5WVlX3k43/+85/jnHPOiS9/+cvxxz/+MRYuXBijR4+un/d9u+6668fOCLQNSimgIJWUlMSJJ54Y48ePj7/+9a/x8ssvx8MPP/yxz8vlcnH00UfHmDFjYuHChdGhQ4e47777IiKiQ4cOsXnz5gbHv/8p24oVK+rXPnxtgoMOOij+/Oc/N1j78P3Pf/7z8cILL8SnP/3pRrf3i6+P06FDh4iIRjMCADTVG2+8Ec8//3xce+21ccIJJ8SBBx7Y6Azyr371q/HOO+/EQw89FNOmTYtzzz13h1+/OVmturo6ysrKYvbs2dt8/IknnogePXrE6NGjo1+/flFdXR2vvPLKDs8EtD0l+R4A4MP++Mc/xksvvRTHHXdc7LHHHvHAAw/Eli1b4jOf+cxHPu+pp56K2bNnx+DBg2OfffaJp556Kv75z3/GgQceGBERPXv2jD/96U/xwgsvRNeuXaNLly7x6U9/Orp37x41NTXxwx/+MP72t7/FT37ykwave9lll0X//v1j/Pjx8dWvfjVmzpwZDz30UINjvv/978epp54a3bt3j69//euxyy67xF//+td49tlnG10UfXt69OgRuVwu/vjHP8bJJ58cZWVlsdtuuzVh5wAA3rPHHntE165d49Zbb41u3brF0qVLG/22vV133TW+8pWvxHXXXRfPP/98DBkyZIdeu7lZrWPHjnH11VfHyJEjo0OHDnH00UfHP//5z1i8eHFcdNFF8elPfzqWLl0ad999dxx++OHx//7f/6v/cBEoTs6UAgrO7rvvHjNmzIgvfvGLceCBB8bkyZNj+vTpcfDBB3/k8zp37hyPPfZYnHzyybH//vvHtddeGz/5yU/iy1/+ckREfOtb34rPfOYz0a9fv9h7773jiSeeiPbt28f06dPjv//7v+PQQw+NG264oVGJ9IUvfCF++ctfxk033RSHHXZYzJw5M6699toGx5x00knxxz/+MWbNmhWHH354fOELX4gJEyZs84Lr2/OpT30qxowZE9dcc01UVFTEpZdeusPPBQD4oF122SXuvvvuWLBgQfTp0ye++93vxo9//ONGxw0dOjT+8z//M4499tjYb7/9dui1m5vVIiKuu+66uPLKK+P73/9+HHjggXH22WfXX1/zK1/5Snz3u9+NSy+9NA477LCYN29eXHfddU1740Cb4rfvAQAAAJCcM6UAAAAASE4pBbQZS5cujd122227tw//umAAAJru8ccf/8jMtT2yGtBUfnwPaDPefffdePnll7f7eM+ePaOkxO9vAAD4JDZs2BCvvfbadh//9Kc/vc11WQ1oKqUUAAAAAMn58T0AAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDkSvI9QCHYsmVLLF++PMrLyyOXy+V7HACggGRZFmvXro2qqqrYZRef571PfgIAtmdH85NSKiKWL18e3bt3z/cYAEABW7ZsWey77775HqNgyE8AwMf5uPyklIqI8vLyiHhvszp37pznaQCAQrJmzZro3r17fV7gPfITALA9O5qflFIR9aecd+7cWagCALbJj6g1JD8BAB/n4/KTCyMAAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEByeS2lHnvssTjttNOiqqoqcrlc3H///Q0ez7IsampqoqqqKsrKymLgwIGxePHiBsfU1dXFd77zndhrr71i1113jdNPPz1effXVhO8CACAtGQoAKAZ5LaXefvvtOPTQQ2PSpEnbfHz8+PExYcKEmDRpUsyfPz8qKytj0KBBsXbt2vpjRowYEffdd1/cfffdMXfu3Fi3bl2ceuqpsXnz5lRvAwAgKRkKACgGuSzLsnwPERGRy+Xivvvui69+9asR8d4nfFVVVTFixIi4+uqrI+K9T/QqKirihhtuiGHDhsXq1atj7733jl/96ldx9tlnR0TE8uXLo3v37vHAAw/ESSedtM2vVVdXF3V1dfX316xZE927d4/Vq1dH586dW+X9LV26NF5//fVWeW0A2Nnttddesd9++7XKa69Zsya6dOnSqjnhk0iVoeQnACguhZCfSlrlq7eAJUuWRG1tbQwePLh+rbS0NAYMGBDz5s2LYcOGxYIFC2LTpk0Njqmqqoo+ffrEvHnztltKjRs3LsaMGdPq7+F9S5cujQMOODA2bFif7GsCwM6krKxT/Pd/P99qwaotaa0MJT8BQHEphPxUsKVUbW1tRERUVFQ0WK+oqIhXXnml/pgOHTrEHnvs0eiY95+/LaNGjYorrrii/v77n/S1ltdffz02bFgfR37z+ujcrWerfR0A2BmtWfFyPHXHmHj99deVUtF6GUp+AoDiUSj5qWBLqfflcrkG97Msa7T2YR93TGlpaZSWlrbI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lsUVV1wRxxxzTPTp0yciImprayMioqKiosGxFRUV9Y9ty7hx46JLly71t+7du7fe4AAAedRSGUp+AgBaWpsppS699NL461//GtOnT2/0WC6Xa3A/y7JGax80atSoWL16df1t2bJlLT4vAEAhaKkMJT8BAC2toK8p9b7vfOc78Yc//CEee+yx2HfffevXKysrI+K9T/u6detWv75y5cpGn/x9UGlpaZSWlrbewAAABaAlM5T8BAC0tII+UyrLsrj00ktjxowZ8fDDD0evXr0aPN6rV6+orKyMWbNm1a9t3Lgx5syZE/379089LgBAQZChAIC2oKDPlPr2t78d06ZNi9///vdRXl5ef42DLl26RFlZWeRyuRgxYkSMHTs2qquro7q6OsaOHRudOnWKIUOG5Hl6AID8kKEAgLagoEupW265JSIiBg4c2GB9ypQpccEFF0RExMiRI2PDhg0xfPjwWLVqVRx55JExc+bMKC8vTzwtAEBhkKEAgLagoEupLMs+9phcLhc1NTVRU1PT+gMBALQBMhQA0BYU9DWlAAAAAChOSikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASK5oSqmbb745evXqFR07doy+ffvG448/nu+RAAAKngwFAORLUZRS99xzT4wYMSJGjx4dCxcujGOPPTa+/OUvx9KlS/M9GgBAwZKhAIB8KopSasKECXHRRRfFxRdfHAceeGBMnDgxunfvHrfccku+RwMAKFgyFACQTyX5HuCT2rhxYyxYsCCuueaaBuuDBw+OefPmbfM5dXV1UVdXV39/9erVERGxZs2aVplx3bp1ERHx5isvxLt1G1rlawDAzmpN7Xtn9axbt65V/lv+/mtmWdbir51PTc1Q8hMAFI9CyU9tvpR6/fXXY/PmzVFRUdFgvaKiImpra7f5nHHjxsWYMWMarXfv3r1VZnzfgl///1r19QFgZzZgwIBWff21a9dGly5dWvVrpNTUDCU/AUDxyXd+avOl1PtyuVyD+1mWNVp736hRo+KKK66ov79ly5Z48803o2vXrtt9zs5qzZo10b1791i2bFl07tw53+PsVOx9/tj7/LH3+WHfP1qWZbF27dqoqqrK9yitYkczlPzUNL6v8sO+54+9zx97nz/2fvt2ND+1+VJqr732inbt2jX6RG/lypWNPvl7X2lpaZSWljZY23333VtrxKLQuXNn32R5Yu/zx97nj73PD/u+fcV0htT7mpqh5Kfm8X2VH/Y9f+x9/tj7/LH327Yj+anNX+i8Q4cO0bdv35g1a1aD9VmzZkX//v3zNBUAQGGToQCAfGvzZ0pFRFxxxRVx3nnnRb9+/eKoo46KW2+9NZYuXRqXXHJJvkcDAChYMhQAkE9FUUqdffbZ8cYbb8QPfvCDWLFiRfTp0yceeOCB6NGjR75Ha/NKS0vj+uuvb3S6Pq3P3uePvc8fe58f9n3nJUO1Ht9X+WHf88fe54+9zx97/8nlsmL7/cYAAAAAFLw2f00pAAAAANoepRQAAAAAySmlAAAAAEhOKQUAAABAckopGlm1alWcd9550aVLl+jSpUucd9558dZbb+3w84cNGxa5XC4mTpzYajMWo6bu+6ZNm+Lqq6+OQw45JHbdddeoqqqKb3zjG7F8+fJ0Q7dhN998c/Tq1Ss6duwYffv2jccff/wjj58zZ0707ds3OnbsGL17947JkycnmrS4NGXfZ8yYEYMGDYq99947OnfuHEcddVT86U9/SjhtcWnqn/n3PfHEE1FSUhKHHXZY6w4IbUxTv6fq6upi9OjR0aNHjygtLY1/+Zd/iTvuuCPRtMWlqXt/1113xaGHHhqdOnWKbt26xYUXXhhvvPFGommLx2OPPRannXZaVFVVRS6Xi/vvv/9jnyM/tYym7r0M1TKa82f+ffLTjlNK0ciQIUNi0aJF8dBDD8VDDz0UixYtivPOO2+Hnnv//ffHU089FVVVVa08ZfFp6r6vX78+nnnmmbjuuuvimWeeiRkzZsSLL74Yp59+esKp26Z77rknRowYEaNHj46FCxfGscceG1/+8pdj6dKl2zx+yZIlcfLJJ8exxx4bCxcujP/9v/93XHbZZfG73/0u8eRtW1P3/bHHHotBgwbFAw88EAsWLIjjjz8+TjvttFi4cGHiydu+pu79+1avXh3f+MY34oQTTkg0KbQNzfmeOuuss2L27Nlx++23xwsvvBDTp0+PAw44IOHUxaGpez937tz4xje+ERdddFEsXrw4fvvb38b8+fPj4osvTjx52/f222/HoYceGpMmTdqh4+WnltPUvZehWkZT9/198lMTZfABzz33XBYR2Z///Of6tSeffDKLiOy///u/P/K5r776avapT30q+6//+q+sR48e2Y033tjK0xaPT7LvH/SXv/wli4jslVdeaY0xi8YRRxyRXXLJJQ3WDjjggOyaa67Z5vEjR47MDjjggAZrw4YNy77whS+02ozFqKn7vi0HHXRQNmbMmJYereg1d+/PPvvs7Nprr82uv/767NBDD23FCaFtaer31IMPPph16dIle+ONN1KMV9Sauvc//vGPs969ezdY+9nPfpbtu+++rTbjziAisvvuu+8jj5GfWseO7P22yFCfTFP2XX5qGmdK0cCTTz4ZXbp0iSOPPLJ+7Qtf+EJ06dIl5s2bt93nbdmyJc4777z43ve+FwcffHCKUYtKc/f9w1avXh25XC523333VpiyOGzcuDEWLFgQgwcPbrA+ePDg7e71k08+2ej4k046KZ5++unYtGlTq81aTJqz7x+2ZcuWWLt2bey5556tMWLRau7eT5kyJf7xj3/E9ddf39ojQpvSnO+pP/zhD9GvX78YP358fOpTn4r9998/rrrqqtiwYUOKkYtGc/a+f//+8eqrr8YDDzwQWZbF//zP/8S9994bp5xySoqRd2ryU+GQodKRn5quJN8DUFhqa2tjn332abS+zz77RG1t7Xafd8MNN0RJSUlcdtllrTle0Wruvn/QO++8E9dcc00MGTIkOnfu3NIjFo3XX389Nm/eHBUVFQ3WKyoqtrvXtbW12zz+3Xffjddffz26devWavMWi+bs+4f95Cc/ibfffjvOOuus1hixaDVn7//2t7/FNddcE48//niUlIgK8EHN+Z566aWXYu7cudGxY8e477774vXXX4/hw4fHm2++6bpSTdCcve/fv3/cddddcfbZZ8c777wT7777bpx++ulx0003pRh5pyY/FQ4ZKg35qXmcKbWTqKmpiVwu95G3p59+OiIicrlco+dnWbbN9YiIBQsWxE9/+tOYOnXqdo/ZWbXmvn/Qpk2b4pxzzoktW7bEzTff3OLvoxh9eF8/bq+3dfy21vloTd33902fPj1qamrinnvu2WaBy8fb0b3fvHlzDBkyJMaMGRP7779/qvGgzWnK32dbtmyJXC4Xd911VxxxxBFx8sknx4QJE2Lq1KnOlmqGpuz9c889F5dddll8//vfjwULFsRDDz0US5YsiUsuuSTFqDs9+Sn/ZKg05KfmU9/tJC699NI455xzPvKYnj17xl//+tf4n//5n0aP/fOf/2z0Scf7Hn/88Vi5cmXst99+9WubN2+OK6+8MiZOnBgvv/zyJ5q9LWvNfX/fpk2b4qyzzoolS5bEww8/7Cypj7HXXntFu3btGn2iunLlyu3udWVl5TaPLykpia5du7barMWkOfv+vnvuuScuuuii+O1vfxsnnnhia45ZlJq692vXro2nn346Fi5cGJdeemlEvPc/1FmWRUlJScycOTO++MUvJpkdClFz/j7r1q1bfOpTn4ouXbrUrx144IGRZVm8+uqrUV1d3aozF4vm7P24cePi6KOPju9973sREfHZz342dt111zj22GPjhz/8obN1WpH8lH8yVDryU/MppXYSe+21V+y1114fe9xRRx0Vq1evjr/85S9xxBFHRETEU089FatXr47+/ftv8znnnXdeo7/kTjrppDjvvPPiwgsv/OTDt2Gtue8RWwupv/3tb/HII4/4D/wO6NChQ/Tt2zdmzZoVZ5xxRv36rFmz4itf+co2n3PUUUfFv//7vzdYmzlzZvTr1y/at2/fqvMWi+bse8R7n+5985vfjOnTp7v+RzM1de87d+4czz77bIO1m2++OR5++OG49957o1evXq0+MxSy5vx9dvTRR8dvf/vbWLduXey2224REfHiiy/GLrvsEvvuu2+SuYtBc/Z+/fr1jX6Mpl27dhGx9awdWof8lF8yVFry0yeQj6urU9i+9KUvZZ/97GezJ598MnvyySezQw45JDv11FMbHPOZz3wmmzFjxnZfw2/fa7qm7vumTZuy008/Pdt3332zRYsWZStWrKi/1dXV5eMttBl333131r59++z222/PnnvuuWzEiBHZrrvumr388stZlmXZNddck5133nn1x7/00ktZp06dsu9+97vZc889l91+++1Z+/bts3vvvTdfb6FNauq+T5s2LSspKcl+/vOfN/jz/dZbb+XrLbRZTd37D/PbY6Chpn5PrV27Ntt3332zr33ta9nixYuzOXPmZNXV1dnFF1+cr7fQZjV176dMmZKVlJRkN998c/aPf/wjmzt3btavX7/siCOOyNdbaLPWrl2bLVy4MFu4cGEWEdmECROyhQsX1v/WZ/mp9TR172WoltHUff8w+WnHKKVo5I033siGDh2alZeXZ+Xl5dnQoUOzVatWNTgmIrIpU6Zs9zWUUk3X1H1fsmRJFhHbvD3yyCPJ529rfv7zn2c9evTIOnTokH3+85/P5syZU//Y+eefnw0YMKDB8Y8++mj2uc99LuvQoUPWs2fP7JZbbkk8cXFoyr4PGDBgm3++zz///PSDF4Gm/pn/IKEKGmvq99Tzzz+fnXjiiVlZWVm27777ZldccUW2fv36xFMXh6bu/c9+9rPsoIMOysrKyrJu3bplQ4cOzV599dXEU7d9jzzyyEf+d1l+aj1N3XsZqmU058/8B8lPOyaXZc5bBQAAACAtv30PAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgogD6ZOnRq77757vscAANhhL7/8cuRyuVi0aNF2j3n00Ucjl8vFW2+9tcOv27Nnz5g4ceInmq2mpiYOO+yw+vsXXHBBfPWrX/1Erwm0PqUUQAtpSvg5++yz48UXX2zdgQAAWlD37t1jxYoV0adPn3yP0shVV10Vs2fPzvcYQBOV5HsAgJ3Npk2boqysLMrKyvI9CgDADtm4cWN06NAhKisr8z3KNu22226x22675XsMoImcKQUU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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], + "outputs": [], "source": [ "### DEMOGRAPHICS\n", "\n", @@ -1354,7 +678,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "580bbd86", "metadata": {}, "outputs": [], @@ -1388,208 +712,12 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "id": "92ad2485", "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "For cluster -1:\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/4x/l9lw50rn7qvf79m01f21x70mlpd6gh/T/ipykernel_35596/1105737326.py:49: RuntimeWarning: Mean of empty slice\n", - " out_cluster_homogeneity[cix][feature] = np.nanmean([in_cluster_homogeneity[x].get(feature, np.nan) for x in oix])\n" - ] - }, - { - "data": { - "text/plain": [ - "unknown 0.986577\n", - "car 0.013423\n", - "Name: target, dtype: float64" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "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", - "
featurech
0section_duration_argmax_mean_bicycling0.0
25duration_median0.0
24duration_mean0.0
23mph_median_walking0.0
\n", - "
" - ], - "text/plain": [ - " feature ch\n", - "0 section_duration_argmax_mean_bicycling 0.0\n", - "25 duration_median 0.0\n", - "24 duration_mean 0.0\n", - "23 mph_median_walking 0.0" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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97+PXr16xamnnhq77bZbHHjggXHHHXfkty9YsCAqKytjwIAB+bWioqLo27dvzJw5c4vPO2rUqGjXrl3+1qlTp3p9HwAAKdVHhpKfAIC61qBLqVdeeSVuu+226NatWzz00ENx/vnnx8UXXxy/+MUvIiKisrIyIiJKS0urPa60tDS/bXOuvvrqWLFiRf62aNGi+nsTAACJ1UeGkp8AgLrWoL++t2HDhujVq1eMHDkyIiIOPPDAeP755+O2226Lb3zjG/n9crlctcdlWVZj7cOKioqiqKiofoYGACiw+shQ8hMAUNca9JlSHTt2jH322afa2t577x0LFy6MiIiysrKIiBqf6C1durTGJ38AAJ8WMhQA0Bg06FLq0EMPjRdffLHa2vz586Nz584REdG1a9coKyuLqVOn5revXbs2pk2bFn369Ek6KwBAQyFDAQCNQYP++t63v/3t6NOnT4wcOTJOO+20eOqpp+L222+P22+/PSI+OOV82LBhMXLkyOjWrVt069YtRo4cGa1bt46BAwcWeHoAgMKQoQCAxqBBl1IHH3xw/O53v4urr746rr/++ujatWuMHTs2Bg0alN9n+PDhsWbNmhg6dGgsX748evfuHVOmTImSkpICTg4AUDgyFADQGDToUioi4vjjj4/jjz9+i9tzuVxUVFRERUVFuqEAABo4GQoAaOga9DWlAAAAAGiaalVKNWvWLJYuXVpj/c0334xmzZp94qEAAJoiGQoAYJNalVJZlm12vaqqKlq2bPmJBgIAaKpkKACATbbrmlI/+tGPIuKDaxD87Gc/izZt2uS3rV+/Ph577LHo3r173U4IANDIyVAAADVtVyl18803R8QHn/KNHz++2mnmLVu2jC5dusT48ePrdkIAgEZOhgIAqGm7SqkFCxZERMQRRxwRkydPjp133rlehgIAaEpkKACAmrarlNro0Ucfres5AACaPBkKAGCTWpVS69evj4kTJ8bDDz8cS5cujQ0bNlTb/sgjj9TJcAAATYkMBQCwSa1KqUsuuSQmTpwYX/nKV6JHjx6Ry+Xqei4AgCZHhgIA2KRWpdQ999wT9913Xxx33HF1PQ8AQJMlQwEAbLJDbR7UsmXL2Guvvep6FgCAJk2GAgDYpFal1GWXXRa33HJLZFlW1/MAADRZMhQAwCa1+vrejBkz4tFHH40HH3ww9t1332jRokW1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CxcujPPPP7/QozV6RUVFce2119Y4XZ/659gXjmNfOI59YTjun14yVP3x96owHPfCcewLx7EvHMf+k8tlWdP4/cY/+clPYvTo0bFkyZLo0aNH3HzzzXH44YcXeiwAgAZNhgIACqXJlFIAAAAANB6N/ppSAAAAADQ+SikAAAAAklNKAQAAAJCcUgoAAACA5JRS1LB8+fI466yzol27dtGuXbs466yz4u23397mxw8ZMiRyuVyMHTu23mZsirb3uK9bty6uvPLK6NmzZ+y4445RXl4e3/jGN2Lx4sXphm7EfvKTn0TXrl2jVatWcdBBB8X06dM/dv9p06bFQQcdFK1atYo999wzxo8fn2jSpmV7jvvkyZOjf//+seuuu0bbtm3jkEMOiYceeijhtE3L9v7Mb/T4449H8+bN44ADDqjfAaGRk58KR4ZKR34qHBmqcGSo+qWUooaBAwfG3Llz409/+lP86U9/irlz58ZZZ521TY994IEH4sknn4zy8vJ6nrLp2d7j/u6778YzzzwT11xzTTzzzDMxefLkmD9/fnz1q19NOHXjdO+998awYcNixIgRMWfOnDjssMPi2GOPjYULF252/wULFsRxxx0Xhx12WMyZMyf+67/+Ky6++OK4//77E0/euG3vcX/ssceif//+8cc//jFmz54dRxxxRJxwwgkxZ86cxJM3ftt77DdasWJFfOMb34gjjzwy0aTQeMlPhSNDpSE/FY4MVTgyVAIZfMgLL7yQRUT217/+Nb/2xBNPZBGR/eMf//jYx77++uvZZz7zmezvf/971rlz5+zmm2+u52mbjk9y3D/sqaeeyiIie+211+pjzCbjC1/4Qnb++edXW+vevXt21VVXbXb/4cOHZ927d6+2NmTIkOyLX/xivc3YFG3vcd+cffbZJ7vuuuvqerQmr7bH/vTTT8++853vZNdee222//771+OE0LjJT4UjQ6UjPxWODFU4MlT9c6YU1TzxxBPRrl276N27d37ti1/8YrRr1y5mzpy5xcdt2LAhzjrrrLjiiiti3333TTFqk1Lb4/5RK1asiFwuFzvttFM9TNk0rF27NmbPnh0DBgyotj5gwIAtHusnnniixv5HH310PP3007Fu3bp6m7Upqc1x/6gNGzbEqlWron379vUxYpNV22M/YcKEePnll+Paa6+t7xGh0ZOfCkeGSkN+KhwZqnBkqDSaF3oAGpbKysrYbbfdaqzvtttuUVlZucXH3XjjjdG8efO4+OKL63O8Jqu2x/3D3nvvvbjqqqti4MCB0bZt27oesclYtmxZrF+/PkpLS6utl5aWbvFYV1ZWbnb/999/P5YtWxYdO3ast3mbitoc94+66aab4p133onTTjutPkZssmpz7F966aW46qqrYvr06dG8uagAWyM/FY4MlYb8VDgyVOHIUGk4U+pToqKiInK53Mfenn766YiIyOVyNR6fZdlm1yMiZs+eHbfccktMnDhxi/t8WtXncf+wdevWxRlnnBEbNmyIn/zkJ3X+Ppqijx7XrR3rze2/uXU+3vYe943uvvvuqKioiHvvvXez//HB1m3rsV+/fn0MHDgwrrvuuvjsZz+bajxokOSnwpGhGib5qXBkqMKRoeqX6u5T4sILL4wzzjjjY/fp0qVLPPvss/H//X//X41t//rXv2o0xBtNnz49li5dGnvssUd+bf369XHZZZfF2LFj49VXX/1Eszdm9XncN1q3bl2cdtppsWDBgnjkkUd8wrcVu+yySzRr1qzGpxtLly7d4rEuKyvb7P7NmzePDh061NusTUltjvtG9957b5x77rnxm9/8Jo466qj6HLNJ2t5jv2rVqnj66adjzpw5ceGFF0bEB6f9Z1kWzZs3jylTpsSXv/zlJLNDoclPhSNDNSzyU+HIUIUjQ6WhlPqU2GWXXWKXXXbZ6n6HHHJIrFixIp566qn4whe+EBERTz75ZKxYsSL69Omz2cecddZZNf5P7uijj46zzjorvvnNb37y4Rux+jzuEZvC1EsvvRSPPvqof+C3QcuWLeOggw6KqVOnxsknn5xfnzp1apx44ombfcwhhxwSf/jDH6qtTZkyJXr16hUtWrSo13mbitoc94gPPt0755xz4u67746vfOUrKUZtcrb32Ldt2zaee+65ams/+clP4pFHHonf/va30bVr13qfGRoK+alwZKiGRX4qHBmqcGSoRApxdXUatmOOOSbbb7/9sieeeCJ74oknsp49e2bHH398tX0+97nPZZMnT97ic/jtMdtve4/7unXrsq9+9avZ7rvvns2dOzdbsmRJ/lZVVVWIt9Bo3HPPPVmLFi2yn//859kLL7yQDRs2LNtxxx2zV199NcuyLLvqqquys846K7//K6+8krVu3Tr79re/nb3wwgvZz3/+86xFixbZb3/720K9hUZpe4/7pEmTsubNm2c//vGPq/18v/3224V6C43W9h77j/KbY2Dr5KfCkaHSkJ8KR4YqHBmq/imlqOHNN9/MBg0alJWUlGQlJSXZoEGDsuXLl1fbJyKyCRMmbPE5hKrtt73HfcGCBVlEbPb26KOPJp+/sfnxj3+cde7cOWvZsmX2+c9/Pps2bVp+2+DBg7O+fftW2/8vf/lLduCBB2YtW7bMunTpkt12222JJ24atue49+3bd7M/34MHD04/eBOwvT/zHyZQwdbJT4UjQ6UjPxWODFU4MlT9ymXZ/7vaHAAAAAAk4rfvAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKagjuVwuHnjggYLO0KVLlxg7dmzBXn/ixImx0047Fez1abgqKirigAMO+Nh9zj777DjppJOSzPOXv/wlcrlcvP322xHhZxeAwujXr18MGzasIK/90X8Lm5JXX301crlczJ07NyKa9nuFxk4pBdtpS/9xvWTJkjj22GPTD1QgmyvATj/99Jg/f35hBqLRu+WWW2LixIkFeW0/uwA0ZZsrv/r06RNLliyJdu3aFWaohD5N7xUam+aFHgCairKyskKP8IllWRbr16+P5s1r938NxcXFUVxcXMdT1a21a9dGy5YtCz0Gm1HIoNgYfnYB4KPWrVsXLVq0qNVjW7Zs2STy67b4NL1XaGycKUWT9dvf/jZ69uwZxcXF0aFDhzjqqKPinXfeiYiICRMmxN577x2tWrWK7t27x09+8pNqj3399dfjjDPOiPbt28eOO+4YvXr1iieffDImTpwY1113Xfztb3+LXC4XuVwuf2bHR7++99xzz8WXv/zl/Ov/x3/8R6xevTq/feNXlX74wx9Gx44do0OHDnHBBRfEunXrtun9LV26NE444YQoLi6Orl27xq9//etq2z962nJExNtvvx25XC7+8pe/RMSmU5kfeuih6NWrVxQVFcX06dPj5ZdfjhNPPDFKS0ujTZs2cfDBB8ef//zn/PP069cvXnvttfj2t7+dPw4Rm/8K1G233Rb/9m//Fi1btozPfe5z8ctf/rLa9lwuFz/72c/i5JNPjtatW0e3bt3i97///TYdg/Xr18e5554bXbt2jeLi4vjc5z4Xt9xyS7V9Nh7nUaNGRXl5eXz2s5+NiIiZM2fGAQccEK1atYpevXrFAw88sNnTvB966KE48MADo7i4OL785S/H0qVL48EHH4y999472rZtG1//+tfj3Xffzb/en/70p/jSl74UO+20U3To0CGOP/74ePnll/Pbf/GLX0SbNm3ipZdeyq9ddNFF8dnPfjb/8/lxunTpEt/73vfiG9/4RrRp0yY6d+4c//M//xP/+te/4sQTT4w2bdpEz5494+mnn672uJkzZ8bhhx8excXF0alTp7j44ourvd6vfvWr6NWrV5SUlERZWVkMHDgwli5dmt++8Xg8/PDD0atXr2jdunX06dMnXnzxxW34k9rkpz/9aXTq1Clat24dp556arXT6D/69b0NGzbEjTfeGHvttVcUFRXFHnvsETfccENERHz5y1+OCy+8sNpzv/nmm1FUVBSPPPJIRERUVVXF8OHDo1OnTlFUVBTdunWLn//855ud66M/uxvPiPzlL38ZXbp0iXbt2sUZZ5wRq1atyu+zatWqGDRoUOy4447RsWPHuPnmmwv6NQwAGrZ33nkn/+93x44d46abbqq2fXOXgthpp53yWXNjtrvvvvuiX79+0apVq/jVr34Vb775Znz961+P3XffPVq3bh09e/aMu+++O/8cZ599dkybNi1uueWWfG579dVXN/uVtvvvvz/23XffKCoqii5dutSYsUuXLjFy5Mg455xzoqSkJPbYY4+4/fbbt+n9f3j+ww47LIqLi+Pggw+O+fPnx6xZs6JXr17Rpk2bOOaYY+Jf//pXtcduLbs/9dRTceCBB+Zz3Zw5c6pt/+h73doxi/gg71588cUxfPjwaN++fZSVlUVFRcU2vVdgO2TQBC1evDhr3rx5NmbMmGzBggXZs88+m/34xz/OVq1ald1+++1Zx44ds/vvvz975ZVXsvvvvz9r3759NnHixCzLsmzVqlXZnnvumR122GHZ9OnTs5deeim79957s5kzZ2bvvvtudtlll2X77rtvtmTJkmzJkiXZu+++m2VZlkVE9rvf/S7Lsix75513svLy8uyUU07Jnnvuuezhhx/Ounbtmg0ePDg/4+DBg7O2bdtm559/fjZv3rzsD3/4Q9a6devs9ttv36b3eOyxx2Y9evTIZs6cmT399NNZnz59suLi4uzmm2/OsizLFixYkEVENmfOnPxjli9fnkVE9uijj2ZZlmWPPvpoFhHZfvvtl02ZMiX75z//mS1btiybO3duNn78+OzZZ5/N5s+fn40YMSJr1apV9tprr2VZlmVvvvlmtvvuu2fXX399/jhkWZZNmDAha9euXf71Jk+enLVo0SL78Y9/nL344ovZTTfdlDVr1ix75JFH8vtERLb77rtnkyZNyl566aXs4osvztq0aZO9+eabWz0Ga9euzb773e9mTz31VPbKK69kv/rVr7LWrVtn9957b7Xj3KZNm+yss87K/v73v2fPPfdctnLlyqx9+/bZmWeemT3//PPZH//4x+yzn/1steO18dh88YtfzGbMmJE988wz2V577ZX17ds3GzBgQPbMM89kjz32WNahQ4fs+9//fv71fvvb32b3339/Nn/+/GzOnDnZCSeckPXs2TNbv359fp9TTz01O/jgg7N169ZlDz74YNaiRYvsqaee2qY/986dO2ft27fPxo8fn82fPz/7z//8z6ykpCQ75phjsvvuuy978cUXs5NOOinbe++9sw0bNmRZlmXPPvts1qZNm+zmm2/O5s+fnz3++OPZgQcemJ199tn55/35z3+e/fGPf8xefvnl7Iknnsi++MUvZscee2x++8bj0bt37+wvf/lL9vzzz2eHHXZY1qdPn22a+9prr8123HHH7Mtf/nI2Z86cbNq0adlee+2VDRw4sNqf1Yknnpi/P3z48GznnXfOJk6cmP3zn//Mpk+fnt1xxx1ZlmXZr3/962znnXfO3nvvvfz+t9xyS9alS5f8+z7ttNOyTp06ZZMnT85efvnl7M9//nN2zz33VHs/y5cvz7Ks5s/utddem7Vp0yb/d/ixxx7LysrKsv/6r//K73PeeedlnTt3zv785z9nzz33XHbyySdnJSUl2SWXXLJNxwSAT5f//M//zHbfffdsypQp2bPPPpsdf/zxWZs2bfL/bnw4S27Url27bMKECVmWbcp2Xbp0yefYN954I3v99dezH/zgB9mcOXOyl19+OfvRj36UNWvWLPvrX/+aZVmWvf3229khhxySfetb38rntvfff7/Gv4VPP/10tsMOO2TXX3999uKLL2YTJkzIiouL86+fZZtyyI9//OPspZdeykaNGpXtsMMO2bx587b6/jfO37179+xPf/pT9sILL2Rf/OIXs89//vNZv379quWt888/P/+4rWX31atXZ7vuumt2+umnZ3//+9+zP/zhD9mee+652Vy38b1u7ZhlWZb17ds3a9u2bVZRUZHNnz8/u+uuu7JcLpdNmTJlG//EgW2hlKJJmj17dhYR2auvvlpjW6dOnbJJkyZVW/vv//7v7JBDDsmyLMt++tOfZiUlJVssRa699tps//33r7H+4SBx++23ZzvvvHO2evXq/Pb/+7//y3bYYYessrIyy7IP/gO8c+fO2fvvv5/f59RTT81OP/30rb6/F198MYuIav9wzps3L4uIWpVSDzzwwFZfc5999sluvfXW/P3OnTvnX2ujj/6HfZ8+fbJvfetb1fY59dRTs+OOOy5/PyKy73znO/n7q1evznK5XPbggw9udabNGTp0aPbv//7v+fuDBw/OSktLs6qqqvzabbfdlnXo0CFbs2ZNfu2OO+7YbHj585//nN9n1KhRWURkL7/8cn5tyJAh2dFHH73FeZYuXZpFRPbcc8/l1956661s9913z/7zP/8zKy0tzb73ve9t8/vr3LlzduaZZ+bvL1myJIuI7JprrsmvPfHEE1lE5MvCs846K/uP//iPas8zffr0bIcddqh2DD7sqaeeyiIiW7VqVZZlmz8e//d//5dFxBaf48OuvfbarFmzZtmiRYvyaw8++GC2ww475Of8cCm1cuXKrKioKF9CfdR7772XtW/fvloBecABB2QVFRVZlm36OzJ16tTNPn5bSqnWrVtnK1euzK9dccUVWe/evfPztWjRIvvNb36T3/72229nrVu3VkoBUMOqVauyli1b5j8cybIPPuQrLi7e7lJq7NixW3294447Lrvsssvy9/v27Vvj36eP/ls4cODArH///tX2ueKKK7J99tknf/+jOWTDhg3Zbrvtlt12221bnWnj/D/72c/ya3fffXcWEdnDDz+cXxs1alT2uc99Ln9/W7J7+/bts3feeSe//bbbbvvYUmpzNnfMvvSlL1Xb5+CDD86uvPLKrb5XYNv5+h5N0v777x9HHnlk9OzZM0499dS44447Yvny5fGvf/0rFi1aFOeee260adMmf/ve976X/4rV3Llz48ADD4z27dvX+vXnzZsX+++/f+y44475tUMPPTQ2bNhQ7etO++67bzRr1ix/v2PHjtW+MvVxz9+8efPo1atXfq179+61/u1hH36eiA9OLx8+fHjss88+sdNOO0WbNm3iH//4RyxcuHC7nnfevHlx6KGHVls79NBDY968edXW9ttvv/z/3nHHHaOkpGSbjkNExPjx46NXr16x6667Rps2beKOO+6oMWfPnj2rXUfqxRdfjP322y9atWqVX/vCF76w2ef/8GylpaXRunXr2HPPPautfXjWl19+OQYOHBh77rlntG3bNrp27RoRUW2mnXfeOX7+85/nv9p41VVXbdN73dJMG9/jR9c2zjV79uyYOHFitZ/5o48+OjZs2BALFiyIiIg5c+bEiSeeGJ07d46SkpLo169fjbk/+todO3as9jpbs8cee8Tuu++ev3/IIYfU+Dux0bx586KqqiqOPPLIzT5XUVFRnHnmmXHnnXdGxAd/b//2t7/F2Wefnb/frFmz6Nu37zbNtjldunSJkpKS/P0P//185ZVXYt26ddV+btq1axef+9znav16ADRdL7/8cqxduzYOOeSQ/Fr79u1r9e/GR3Pb+vXr44Ybboj99tsvOnToEG3atIkpU6bUWW576aWXYv369fm1D2eBXC4XZWVl25wFPvr4LeWYjc+3Ldl9Y+5u3bp1/jk+fJw3Z1uP2Ydnjdj2rA5sOxc6p0lq1qxZTJ06NWbOnBlTpkyJW2+9NUaMGBF/+MMfIiLijjvuiN69e9d4TETUycWOsyzLX2fpoz68/tELU+ZyudiwYcM2Pf9Hn+ujdthhh2r7RsQWr1f14fIsIuKKK66Ihx56KH74wx/GXnvtFcXFxfG1r30t1q5du9XZPuqjM27u2NT2ONx3333x7W9/O2666aY45JBDoqSkJH7wgx/Ek08+WW2/j76/zc3w4eO0pdlyudxWZz3hhBOiU6dOcccdd0R5eXls2LAhevToUePYPfbYY9GsWbNYvHhxvPPOO9G2bdutvt8tzbSltY1zbdiwIYYMGRIXX3xxjefaY4894p133okBAwbEgAED4le/+lXsuuuusXDhwjj66KNrzP1xr7O9Nj5+cz/H2/L38LzzzosDDjggXn/99bjzzjvjyCOPjM6dO2/z47fm4/6st/R3cEs/RwB8um3Lvw+5XK7GfpvLbh/NNTfddFPcfPPNMXbs2OjZs2fsuOOOMWzYsO3Obduaj2qb2zb3+C3lmA9nmIiPz+61+bd3W4/ZJ32vwNY5U4omK5fLxaGHHhrXXXddzJkzJ1q2bBmPP/54fOYzn4lXXnkl9tprr2q3jWe07LfffjF37tx46623Nvu8LVu2rPZp0ebss88+MXfu3GoXkn788cdjhx12yF9o+5PYe++94/333692MesXX3yx2oUqd91114iIWLJkSX7twxc9/zjTp0+Ps88+O04++eTo2bNnlJWVxauvvlptn205DnvvvXfMmDGj2trMmTNj77333qY5tmXOPn36xNChQ+PAAw+Mvfbaq9pFxbeke/fu8eyzz0ZVVVV+7aMXBq+NN998M+bNmxff+c534sgjj4y99947li9fXmO/mTNnxujRo+MPf/hDtG3bNi666KJP/Nof5/Of/3w8//zzNX7m99prr2jZsmX84x//iGXLlsX3v//9OOyww6J79+718ingwoULY/Hixfn7TzzxxBb/TnTr1i2Ki4vj4Ycf3uLz9ezZM3r16hV33HFHTJo0Kc4555xq2zZs2BDTpk2r2zfx//zbv/1btGjRIp566qn82sqVK6tdwB4ANtprr72iRYsW8de//jW/tnz58pg/f37+/q677lott7300kvVfpnKlkyfPj1OPPHEOPPMM2P//fePPffcs8a/R9uaXzeX2z772c9WO7M/pdLS0q1m93322Sf+9re/xZo1a/KP+/Bx3pxtOWZAGkopmqQnn3wyRo4cGU8//XQsXLgwJk+eHP/6179i7733joqKihg1alTccsstMX/+/HjuuediwoQJMWbMmIiI+PrXvx5lZWVx0kknxeOPPx6vvPJK3H///fHEE09ExAdf6VmwYEHMnTs3li1bVq3Y2GjQoEHRqlWrGDx4cPz973+PRx99NC666KI466yz8qcpfxKf+9zn4phjjolvfetb8eSTT8bs2bPjvPPOq3Z2SHFxcXzxi1+M73//+/HCCy/EY489Ft/5zne26fn32muvmDx5cv4rUQMHDqzxqVCXLl3iscceizfeeCOWLVu22ee54oorYuLEiTF+/Ph46aWXYsyYMTF58uS4/PLLa//mPzLn008/HQ899FDMnz8/rrnmmpg1a9ZWH7fx/fzHf/xHzJs3L39WWMTHn322NTvvvHN06NAhbr/99vjnP/8ZjzzySFx66aXV9lm1alWcddZZcdFFF8Wxxx4bkyZNivvuuy9+85vf1Pp1t+bKK6+MJ554Ii644IKYO3duvPTSS/H73/8+X4btscce0bJly7j11lvjlVdeid///vfx3//933U+x8a/E3/7299i+vTpcfHFF8dpp5222V/R3KpVq7jyyitj+PDh8Ytf/CJefvnl+Otf/1rjt+edd9558f3vfz/Wr18fJ598cn69S5cuMXjw4DjnnHPigQceiAULFsRf/vKXuO++++rkvZSUlMTgwYPjiiuuiEcffTSef/75OOecc2KHHXb4RD9DADRNbdq0iXPPPTeuuOKKePjhh+Pvf/97nH322fkz2yM++M2y48aNi2eeeSaefvrpOP/882ucqbM5e+21V/4bAvPmzYshQ4ZEZWVltX26dOkSTz75ZLz66quxbNmyzZ7tc9lll8XDDz8c//3f/x3z58+Pu+66K8aNG1dnua22tpbdBw4cGDvssEOce+658cILL8Qf//jHfK7bkm05ZkAaSimapLZt28Zjjz0Wxx13XHz2s5+N73znO3HTTTfFscceG+edd1787Gc/i4kTJ0bPnj2jb9++MXHixPynLS1btowpU6bEbrvtFscdd1z07Nkzvv/97+c/Ifr3f//3OOaYY+KII46IXXfdtcavj42IaN26dTz00EPx1ltvxcEHHxxf+9rX4sgjj4xx48bV2XucMGFCdOrUKfr27RunnHJK/Md//Efstttu1fa58847Y926ddGrV6+45JJL4nvf+942PffNN98cO++8c/Tp0ydOOOGEOProo+Pzn/98tX2uv/76ePXVV+Pf/u3f8mdlfdRJJ50Ut9xyS/zgBz+IfffdN37605/GhAkT8tcr+qTOP//8OOWUU+L000+P3r17x5tvvhlDhw7d6uPatm0bf/jDH2Lu3LlxwAEHxIgRI+K73/1uRES160xtrx122CHuueeemD17dvTo0SO+/e1vxw9+8INq+1xyySWx4447xsiRIyPig+uK3XjjjXH++efHG2+8UevX/jj77bdfTJs2LV566aU47LDD4sADD4xrrrkmf02oXXfdNSZOnBi/+c1vYp999onvf//7Ww1ztbHXXnvFKaecEscdd1wMGDAgevToUeNXOn/YNddcE5dddll897vfjb333jtOP/30Gmdwff3rX4/mzZvHwIEDa/zZ3XbbbfG1r30thg4dGt27d49vfetb1c5e/KTGjBkThxxySBx//PFx1FFHxaGHHpr/ddUA8FE/+MEP4vDDD4+vfvWrcdRRR8WXvvSlOOigg/Lbb7rppujUqVMcfvjhMXDgwLj88surXSdpS665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M888Mzp06BCtW7eOAw44IGbPnp3fnmVZVFRURHl5eRQXF0e/fv3i+eefL+DEAACFJ0MBAA1dgy6lli9fHoceemi0aNEiHnzwwXjhhRfipptuip122im/z+jRo2PMmDExbty4mDVrVpSVlUX//v1j1apVhRscAKCAZCgAoDFoXugBPs6NN94YnTp1igkTJuTXunTpkv/fWZbF2LFjY8SIEXHKKadERMRdd90VpaWlMWnSpBgyZEjqkQEACk6GAgAagwZ9ptTvf//76NWrV5x66qmx2267xYEHHhh33HFHfvuCBQuisrIyBgwYkF8rKiqKvn37xsyZM7f4vFVVVbFy5cpqNwCApqI+MpT8BADUtQZdSr3yyitx2223Rbdu3eKhhx6K888/Py6++OL4xS9+ERERlZWVERFRWlpa7XGlpaX5bZszatSoaNeuXf7WqVOn+nsTAACJ1UeGkp8AgLrWoEupDRs2xOc///kYOXJkHHjggTFkyJD41re+Fbfddlu1/XK5XLX7WZbVWPuwq6++OlasWJG/LVq0qF7mBwAohPrIUPITAFDXGnQp1bFjx9hnn32qre29996xcOHCiIgoKyuLiKjxid7SpUtrfPL3YUVFRdG2bdtqNwCApqI+MpT8BADUtQZdSh166KHx4osvVlubP39+dO7cOSIiunbtGmVlZTF16tT89rVr18a0adOiT58+SWcFAGgoZCgAoDFo0L9979vf/nb06dMnRo4cGaeddlo89dRTcfvtt8ftt98eER+ccj5s2LAYOXJkdOvWLbp16xYjR46M1q1bx8CBAws8PQBAYchQAEBj0KBLqYMPPjh+97vfxdVXXx3XX399dO3aNcaOHRuDBg3K7zN8+PBYs2ZNDB06NJYvXx69e/eOKVOmRElJSQEnBwAoHBkKAGgMGnQpFRFx/PHHx/HHH7/F7blcLioqKqKioiLdUAAADZwMBQA0dA36mlIAAAAANE1KKQAAAACSq1Up1axZs1i6dGmN9TfffDOaNWv2iYcCAGiKZCgAgE1qVUplWbbZ9aqqqmjZsuUnGggAoKmSoQAANtmuC53/6Ec/iogPLoz5s5/9LNq0aZPftn79+njssceie/fudTshAEAjJ0MBANS0XaXUzTffHBEffMo3fvz4aqeZt2zZMrp06RLjx4+v2wkBABo5GQoAoKbtKqUWLFgQERFHHHFETJ48OXbeeed6GQoAoCmRoQAAatquUmqjRx99tK7nAABo8mQoAIBNalVKrV+/PiZOnBgPP/xwLF26NDZs2FBt+yOPPFInwwEANCUyFADAJrUqpS655JKYOHFifOUrX4kePXpELper67kAAJocGQoAYJNalVL33HNP3HfffXHcccfV9TwAAE2WDAUAsMkOtXlQy5YtY6+99qrrWQAAmjQZCgBgk1qVUpdddlnccsstkWVZXc8DANBkyVAAAJvU6ut7M2bMiEcffTQefPDB2HfffaNFixbVtk+ePLlOhgMAaEpkKACATWpVSu20005x8skn1/UsAABNmgwFALBJrUqpCRMm1PUcAABNngwFALBJra4pFRHx/vvvx5///Of46U9/GqtWrYqIiMWLF8fq1avrbDgAgKZGhgIA+ECtzpR67bXX4phjjomFCxdGVVVV9O/fP0pKSmL06NHx3nvvxfjx4+t6TgCARk+GAgDYpFZnSl1yySXRq1evWL58eRQXF+fXTz755Hj44YfrbDgAgKZEhgIA2KTWv33v8ccfj5YtW1Zb79y5c7zxxht1MhgAQFMjQwEAbFKrM6U2bNgQ69evr7H++uuvR0lJySceCgCgKZKhAAA2qVUp1b9//xg7dmz+fi6Xi9WrV8e1114bxx13XF3NBgDQpMhQAACb1OrrezfffHMcccQRsc8++8R7770XAwcOjJdeeil22WWXuPvuu+t6RgCAJkGGAgDYpFalVHl5ecydOzfuueeemD17dmzYsCHOPffcGDRoULWLdgIAsIkMBQCwSa1KqYiI4uLi+OY3vxnf/OY363IeAIAmTYYCAPhAra4pNWrUqLjzzjtrrN95551x4403fuKhAACaIhkKAGCTWpVSP/3pT6N79+411vfdd98YP378Jx4KAKApkqEAADapVSlVWVkZHTt2rLG+6667xpIlSz7xUAAATZEMBQCwSa1KqU6dOsXjjz9eY/3xxx+P8vLyTzwUAEBTJEMBAGxSqwudn3feeTFs2LBYt25dfPnLX46IiIcffjiGDx8el112WZ0OCADQVMhQAACb1KqUGj58eLz11lsxdOjQWLt2bUREtGrVKq688sq4+uqr63RAAICmQoYCANhku0up9evXx4wZM+LKK6+Ma665JubNmxfFxcXRrVu3KCoqqo8ZAQAaPRkKAKC67S6lmjVrFkcffXTMmzcvunbtGgcffHB9zAUA0KTIUAAA1dXqQuc9e/aMV155pa5nAQBo0mQoAIBNalVK3XDDDXH55ZfH//7v/8aSJUti5cqV1W4AANQkQwEAbFKrC50fc8wxERHx1a9+NXK5XH49y7LI5XKxfv36upkOAKAJkaEAADapVSn16KOP1vUcAABNngwFALBJrUqpvn371vUcAABNngwFALBJra4pFRExffr0OPPMM6NPnz7xxhtvRETEL3/5y5gxY0adDQcA0NTIUAAAH6hVKXX//ffH0UcfHcXFxfHMM89EVVVVRESsWrUqRo4cWacDAgA0FTIUAMAmtSqlvve978X48ePjjjvuiBYtWuTX+/TpE88880ydDQcA0JTIUAAAm9SqlHrxxRfj8MMPr7Hetm3bePvttz/pTAAATZIMBQCwSa1KqY4dO8Y///nPGuszZsyIPffc8xMPBQDQFMlQAACb1KqUGjJkSFxyySXx5JNPRi6Xi8WLF8evf/3ruPzyy2Po0KF1PSMAQJMgQwEAbNK8Ng8aPnx4rFy5Mo444oh477334vDDD4+ioqK4/PLL48ILL6zrGQEAmgQZCgBgk+0qpd5999244oor4oEHHoh169bFCSecEJdddllEROyzzz7Rpk2behkSAKAxk6EAAGrarlLq2muvjYkTJ8agQYOiuLg4Jk2aFBs2bIjf/OY39TUfAECjJ0MBANS0XaXU5MmT4+c//3mcccYZERExaNCgOPTQQ2P9+vXRrFmzehkQAKCxk6EAAGrargudL1q0KA477LD8/S984QvRvHnzWLx4cZ0PBgDQVMhQAAA1bVcptX79+mjZsmW1tebNm8f7779fp0MBADQlMhQAQE3b9fW9LMvi7LPPjqKiovzae++9F+eff37suOOO+bXJkyfX3YQAAI2cDAUAUNN2lVKDBw+usXbmmWfW2TAAAE2RDAUAUNN2lVITJkyorzkAAJosGQoAoKbtuqYUAAAAANQFpRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABIrlGVUqNGjYpcLhfDhg3Lr2VZFhUVFVFeXh7FxcXRr1+/eP755ws3JABAAyNDAQANUaMppWbNmhW333577LffftXWR48eHWPGjIlx48bFrFmzoqysLPr37x+rVq0q0KQAAA2HDAUANFSNopRavXp1DBo0KO64447Yeeed8+tZlsXYsWNjxIgRccopp0SPHj3irrvuinfffTcmTZq0xeerqqqKlStXVrsBADQ1dZmh5CcAoK41ilLqggsuiK985Stx1FFHVVtfsGBBVFZWxoABA/JrRUVF0bdv35g5c+YWn2/UqFHRrl27/K1Tp071NjsAQKHUZYaSnwCAutbgS6l77rknnnnmmRg1alSNbZWVlRERUVpaWm29tLQ0v21zrr766lixYkX+tmjRorodGgCgwOo6Q8lPAEBda17oAT7OokWL4pJLLokpU6ZEq1attrhfLperdj/LshprH1ZUVBRFRUV1NicAQENSHxlKfgIA6lqDPlNq9uzZsXTp0jjooIOiefPm0bx585g2bVr86Ec/iubNm+c/3fvoJ3pLly6t8ckfAMCnhQwFADQGDbqUOvLII+O5556LuXPn5m+9evWKQYMGxdy5c2PPPfeMsrKymDp1av4xa9eujWnTpkWfPn0KODkAQOHIUABAY9Cgv75XUlISPXr0qLa24447RocOHfLrw4YNi5EjR0a3bt2iW7duMXLkyGjdunUMHDiwECMDABScDAUANAYNupTaFsOHD481a9bE0KFDY/ny5dG7d++YMmVKlJSUFHo0AIAGS4YCAAqt0ZVSf/nLX6rdz+VyUVFRERUVFQWZBwCgMZChAICGpkFfUwoAAACApkkpBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAIDmlFAAAAADJKaUAAAAASE4pBQAAAEBySikAAAAAklNKAQAAAJCcUgoAAACA5JRSAAAAACSnlAIAAAAgOaUUAAAAAMkppQAAAABITikFAAAAQHJKKQAAAACSU0oBAAAAkJxSCgAAAIDklFIAAAAAJKeUAgAAACA5pRQAAAAAySmlAAAAAEhOKQUAAABAckopAAAAAJJTSgEAAACQnFIKAAAAgOSUUgAAAAAkp5QCAAAAILkGXUqNGjUqDj744CgpKYnddtstTjrppHjxxRer7ZNlWVRUVER5eXkUFxdHv3794vnnny/QxAAAhSdDAQCNQYMupaZNmxYXXHBB/PWvf42pU6fG+++/HwMGDIh33nknv8/o0aNjzJgxMW7cuJg1a1aUlZVF//79Y9WqVQWcHACgcGQoAKAxaF7oAT7On/70p2r3J0yYELvttlvMnj07Dj/88MiyLMaOHRsjRoyIU045JSIi7rrrrigtLY1JkybFkCFDCjE2AEBByVAAQGPQoM+U+qgVK1ZERET79u0jImLBggVRWVkZAwYMyO9TVFQUffv2jZkzZ27xeaqqqmLlypXVbgAATVVdZCj5CQCoa42mlMqyLC699NL40pe+FD169IiIiMrKyoiIKC0trbZvaWlpftvmjBo1Ktq1a5e/derUqf4GBwAooLrKUPITAFDXGk0pdeGFF8azzz4bd999d41tuVyu2v0sy2qsfdjVV18dK1asyN8WLVpU5/MCADQEdZWh5CcAoK416GtKbXTRRRfF73//+3jsscdi9913z6+XlZVFxAef9nXs2DG/vnTp0hqf/H1YUVFRFBUV1d/AAAANQF1mKPkJAKhrDfpMqSzL4sILL4zJkyfHI488El27dq22vWvXrlFWVhZTp07Nr61duzamTZsWffr0ST0uAECDIEMBAI1Bgz5T6oILLohJkybF//zP/0RJSUn+Ggft2rWL4uLiyOVyMWzYsBg5cmR069YtunXrFiNHjozWrVvHwIEDCzw9AEBhyFAAQGPQoEup2267LSIi+vXrV219woQJcfbZZ0dExPDhw2PNmjUxdOjQWL58efTu3TumTJkSJSUliacFAGgYZCgAoDFo0KVUlmVb3SeXy0VFRUVU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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "==================================================\n", - "For cluster 0:\n" - ] - }, - { - "data": { - "text/plain": [ - "unknown 1.0\n", - "Name: target, dtype: float64" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "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", - "
featurech
31duration_median250175.825182
1section_duration_argmax_mean_car262552.009065
11section_distance_argmax_mean_car263103.437553
24mph_mean_walking264091.869648
\n", - "
" - ], - "text/plain": [ - " feature ch\n", - "31 duration_median 250175.825182\n", - "1 section_duration_argmax_mean_car 262552.009065\n", - "11 section_distance_argmax_mean_car 263103.437553\n", - "24 mph_mean_walking 264091.869648" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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0BzpoQAAdqvTg86/+c1vxmWXXRbvvvtunHbaaRER8dhjj8WECRPi8ssvb9ACAQCaCz0UAMBudQqlJkyYEO+8806MGzcutm/fHhERhx12WFx55ZUxceLEBi0QAKC50EMBAOy236HUzp0746mnnoorr7wyvv/978eyZcuioKAgunfvHtls9kDUCADQ5OmhAABq2u9QqkWLFnH66afHsmXLomvXrnHSSScdiLoAAJoVPRQAQE11un3v+OOPjzfffDO6du3a0PUAwEFn1apVUVlZme8ymqz27dvHUUcdle8y9okeqiY/+3W3bNmyfJcAAPVWp1Dq2muvjSuuuCL+4z/+Iz772c/G4YcfXmN5UVFRgxQHAM3dqlWromfP42Lbtq35LqXJKihoHa++uqxJBFN6qN387DeMd6u357sEAKizOoVSZ5xxRkREfPnLX45MJpMbT5IkMplM7Ny5s2GqA4BmrrKyMrZt2xr9/+XqKCo9Ot/lNDlVa1bGc3deE5WVlU0ilNJD7eZnv37WLH0m/vDQbbFjx458lwIAdVanUOqJJ55o6DoA4KBWVHp0tDvq2HyXwQGmh6rNz37dVK1Zme8SAKDe6hRKDRo0qKHrAABo9vRQAAC7HVLXFz755JNx3nnnxcCBA+PPf/5zRET893//dzz11FMNVhwAQHOjhwIAeE+dQqn7778/Tj/99CgoKIgXXnghqqurIyJi06ZNMXny5AYtEACgudBDAQDsVqdQ6oc//GHceuutcfvtt8ehhx6aGx84cGC88MILDVYcAEBzoocCANitTqHUa6+9Fqeeemqt8aKiotiwYUN9awIAaJb0UAAAu9UplCotLY0//vGPtcafeuqpOOaYY+pdFABAc6SHAgDYrU6h1IUXXhiXXnppPPfcc5HJZOLtt9+Oe++9N6644ooYN25cQ9cIANAs6KEAAHZrWZcXTZgwIaqqqmLIkCHxt7/9LU499dTIZrNxxRVXxMUXX9zQNQIANAt6KACA3fYrlNq6dWt897vfjQcffDDefffdGDFiRFx++eUREdGrV69o06bNASkSAKAp00MBANS2X6HU1VdfHdOnT49zzz03CgoKYsaMGbFr16749a9/faDqAwBo8vRQAAC17VcoNWvWrLjjjjvin/7pnyIi4txzz43Pf/7zsXPnzmjRosUBKRAAoKnTQwEA1LZfDzpfvXp1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0pqlz8QfHrotPj3qyjiya898l9PkvH/8duzYke9SAACAfeD3yPrze2T9VK1ZGc/deU1UVlYKpZqDotKjo91Rx+a7jCapas3KiIho0+Eox7AO3j9+AABA0+L3yLrze2Tz4EHnAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6hp1KFVWVhaZTKbGVFJSku+yAAAaNT0UANAUtMx3AR+nd+/e8bvf/S4336JFizxWAwDQNOihAIDGrtGHUi1bttyvb/aqq6ujuro6N19VVXUgygIAaNT0UABAY9eob9+LiFi+fHl07NgxunbtGv/0T/8Ub7755keuX15eHm3bts1NnTt3TqlSAIDGQw8FADR2jTqU6t+/f9x9993x6KOPxu233x4VFRUxcODAWLdu3V5fM3HixNi4cWNuWr16dYoVAwDknx4KAGgKGvXte8OHD8/99/HHHx8DBgyIv/u7v4u77rorxo8fv8fXZLPZyGazaZUIANDo6KEAgKagUV8p9WGHH354HH/88bF8+fJ8lwIA0GTooQCAxqhJhVLV1dWxbNmyKC0tzXcpAABNhh4KAGiMGnUodcUVV8T8+fNjxYoV8dxzz8U//uM/RlVVVYwePTrfpQEANFp6KACgKWjUz5T605/+FP/8z/8clZWVceSRR8bJJ58czz77bHTp0iXfpQEANFp6KACgKWjUodTMmTPzXQIAQJOjhwIAmoJGffseAAAAAM2TUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA1AmlAAAAAEidUAoAAACA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1y4OP/zw6NevXzz33HMxffr0uOaaa+J///d/cz3B+33Gh/uQpUuXxmmnnZbb/7/+67/G5s2bc8vHjBkTX/nKV+I///M/o7S0NI444oi46KKL4t13392n97d27doYMWJEFBQURNeuXePee++tsfzDt+JHRGzYsCEymUzMmzcvInaf3x999NHo169fZLPZePLJJ+ONN96Is846K4qLi6NNmzZx0kknxe9+97vcdgYPHhxvvfVWfOc738kdh4g93743derU+Lu/+7to1apVHHvssfHf//3fNZZnMpn4xS9+EWeffXa0bt06unfvHg899NA+HYOdO3fGN77xjejatWsUFBTEscceG7fcckuNdd4/zuXl5dGxY8fo0aNHREQsXLgwPv3pT+d6nwcffHCPjy549NFH48QTT4yCgoI47bTTYu3atfHII4/EcccdF0VFRfHP//zPsXXr1tz+Zs+eHV/4whfiE5/4RBxxxBHxD//wD/HGG2/klt99993Rpk2bWL58eW7skksuiR49euR+Pj/K0UcfHT/84Q9zPXGXLl3i//7f/xt//etf46yzzoo2bdrE8ccfH4sXL67xuoULF8app54aBQUF0blz5/j2t79dY3/33HNP9OvXLwoLC6OkpCRGjRoVa9euzS1//3g89thj0a9fv2jdunUMHDgwXnvttX34pN7z0EMPRb9+/eKwww6L9u3bx8iRI/d7/x/+WYUGlQB8hG9961tJp06dkjlz5iQvvfRS8g//8A9JmzZtkksvvTRJkiSJiOSBBx6o8Zq2bdsm06ZNS5IkSVasWJFERHL00Ucn999/f/Lmm28mf/7zn5M//elPyY9//OPkxRdfTN54443kJz/5SdKiRYvk2WefTZIkSTZs2JAMGDAgueCCC5I1a9Yka9asSXbs2JE88cQTSUQk69evT5IkSRYvXpwccsghyb//+78nr732WjJt2rSkoKAgt/8kSZIuXbok7dq1S376058my5cvT8rLy5NDDjkkWbZs2ce+//fr79mzZzJ79uzklVdeSU4++eTkM5/5TDJ48ODkqaeeSl544YWkW7duydixY3Ovu+2225LS0tLce77//vuTdu3aJdOnT0+SJEk2b96cHHnkkck555yT/OEPf0h+85vfJMccc0wSEcmLL76YJElS671+3DFLkiQZNGhQUlRUlJSVlSWvv/56ctdddyWZTCaZM2fOPn7iAFA3b7/9dtKyZcvkxhtvTFasWJG89NJLyU9/+tNk06ZNH3te3LRpU3LMMcckp5xySvLkk08my5cvT+67775k4cKFydatW5PLL7886d27d64n2Lp1a5IkNfuQLVu2JB07dkxGjhyZLF26NHnssceSrl27JqNHj87VOHr06KSoqCgZO3ZssmzZsuQ3v/lN0rp16+S2227bp/c4fPjwpE+fPsnChQuTxYsXJwMHDkwKCgqSm266KUmS3X3D++fyJEmS9evXJxGRPPHEE0mS7D6/9+3bN5kzZ07yxz/+MamsrEyWLFmS3HrrrclLL72UvP7668mkSZOSww47LHnrrbeSJEmSdevWJZ06dUr+/d//PXcckiRJpk2blrRt2za3v1mzZiWHHnpo8tOf/jR57bXXkhtuuCFp0aJF8vjjj+fWiYikU6dOyYwZM5Lly5cn3/72t5M2bdok69at+9hjsH379uQHP/hB8vvf/z558803k3vuuSdp3bp1ct9999U4zm3atEnOP//85A9/+EOydOnSpKqqKmnXrl1y3nnnJS+//HLy8MMPJz169Nhj73PyySfX6LEGDRqUDBs2LHnhhReSBQsWJEcccURy3XXX5fb3P//zP8n999+fvP7668mLL76YjBgxIjn++OOTnTt35tb52te+lpx00knJu+++mzzyyCPJoYcemvz+97/fp8/9/V7y1ltvTV5//fXkW9/6VlJYWJicccYZya9+9avktddeS77yla8kxx13XLJr164kSZLkpZdeStq0aZPcdNNNyeuvv548/fTTyYknnpiMGTMmt9077rgjefjhh5M33ngjeeaZZ5KTTz45GT58eG75+8ejf//+ybx585KXX345OeWUU5KBAwfuU93/7//9v6RFixbJD37wg+SVV15JlixZklx77bX7vf8P/6xCQxJKAXu1adOmpFWrVsnMmTNzY+vWrUsKCgr2O5S6+eabP3Z/Z555ZnL55Zfn5gcNGpTbz/s+HNSMGjUqGTp0aI11vvvd7ya9evXKzXfp0iU577zzcvO7du1KOnTokEydOvVja3q//l/84he5sV/+8pdJRCSPPfZYbqy8vDw59thjc/OdO3dOZsyYUWNb//Ef/5EMGDAgSZIk+fnPf560a9cu2bJlS2751KlTPzKU2pM9HbMvfOELNdY56aSTkiuvvPJj3ysA1Mfzzz+fRESycuXKWsv25bxYWFi411Dk6quvTk444YRa4x/sQ2677bbkk5/8ZLJ58+bc8t/+9rfJIYccklRUVCRJ8l5Y0qVLl2THjh25db72ta8l55xzzse+v9deey2JiBpfBi1btiyJiDqFUg8++ODH7rNXr17Jf/3Xf+Xmu3TpktvX+z4cSg0cODC54IILaqzzta99LTnzzDNz8xGRfO9738vNb968OclkMskjjzzysTXtybhx45KvfvWrufnRo0cnxcXFSXV1dW5s6tSpyRFHHJFs27YtN3b77bfvsff53e9+l1unvLw8iYjkjTfeyI1deOGFyemnn77XetauXZtERLJ06dLc2DvvvJN06tQp+da3vpUUFxcnP/zhD/f5/X24l1yzZk0SEcn3v//93NgzzzyTREQuLDz//POTf/3Xf62xnSeffDI55JBDahyDD/r973+fRESyadOmJEn2fDx++9vfJhGx12180IABA5Jzzz13n9/n3va/Lz+rUFdu3wP26o033ojt27fHgAEDcmPt2rWLY489dr+31a9fvxrzO3fujGuvvTb69u0bRxxxRLRp0ybmzJkTq1at2q/tLlu2LD7/+c/XGPv85z8fy5cvj507d+bG+vbtm/vvTCYTJSUlNS5P/jgffH1xcXFERBx//PE1xt7f3l//+tdYvXp1fOMb34g2bdrkph/+8Ie5S8mXLVsWJ5xwQrRu3Tq3jQ8e5z3Z12P2wVojIkpLS/frvQJAXZxwwgnxxS9+MY4//vj42te+FrfffnusX79+n86LS5YsiRNPPDHatWtX5/2/f249/PDDc2Of//znY9euXTVud+rdu3e0aNEiN7+v58lly5ZFy5Yta/Q0PXv2rPNfvvtwb7Rly5aYMGFC9OrVKz7xiU9EmzZt4tVXX22w3mjZsmU1xj7YLxx++OFRWFi4z/3CrbfeGv369Ysjjzwy2rRpE7fffnutOo8//vgaz5F67bXXom/fvnHYYYflxj73uc/tcfsf7rtat24dxxxzTI2xD9b6xhtvxKhRo+KYY46JoqKi6Nq1a0REjZo++clPxh133JG7tfHf/u3f9um97q2m99/jh8fer+v555+P6dOn1/iZP/3002PXrl2xYsWKiIh48cUX46yzzoouXbpEYWFhDB48uFbdH953aWlpjf18lCVLlsQXv/jFvS7f1/1/+GcVGpInlAF7lSTJx66TyWRqrben5zJ8sEGMiLjhhhvipptuiptvvjmOP/74OPzww+Oyyy6L7du373eN7z9T4aPq/vCD1TOZTOzatWuf9/PB17+/vw+Pvb+99//39ttvj/79+9fYzvtN8L4c2w/b12NW3/cKAHXRokWLmDt3bixcuDDmzJkT//Vf/xWTJk2K3/zmNxHx0efFhnhQ9556gvd9cLyu58n3z91720dExCGHHFJj3Yg990URtXuj7373u/Hoo4/Gf/7nf0a3bt2ioKAg/vEf/3G/e6M91binY1PX4/CrX/0qvvOd78QNN9wQAwYMiMLCwvjxj38czz33XI31Pvz+9rVn+3BtmUzmY2sdMWJEdO7cOW6//fbo2LFj7Nq1K/r06VPr2C1YsCBatGgRb7/9dmzZsiWKioo+9v3uraa9jX2wH7zwwgvj29/+dq1tHXXUUbFly5YYNmxYDBs2LO6555448sgjY9WqVXH66ad/ZG/34f18lI/6d7U/+//wZwkNyZVSwF5169YtDj300Hj22WdzY+vXr6/xZ4ePPPLIWLNmTW5++fLlNR48uTdPPvlknHXWWXHeeefFCSecEMccc0yNh09GvPfX5z54tdOe9OrVK5566qkaYwsXLowePXrU+BY0TcXFxfGpT30q3nzzzejWrVuN6f1v7nr16hX/+7//G9u2bcu97oPHeU/25ZgBQD5lMpn4/Oc/H9dcc028+OKL0apVq3j66ac/9rzYt2/fWLJkSbzzzjt73O6+9gRLliyp8SDpp59+Og455JDcg7br47jjjosdO3bUeJj1a6+9VuOPrxx55JERETV6ow8+9PyjPPnkkzFmzJg4++yz4/jjj4+SkpJYuXJljXX25Tgcd9xxe+yNjjvuuH2qY1/qHDhwYIwbNy5OPPHE6NatW42Hiu9Nz54946WXXorq6urc2IcfDF4X69ati2XLlsX3vve9+OIXvxjHHXdcrF+/vtZ6CxcujOuvvz5+85vfRFFRUVxyySX13vdH+cxnPhMvv/xyrZ/5bt26RatWreLVV1+NysrKuO666+KUU06Jnj17NviV7X379o3HHntsj8vS2D/sC6EUsFdt2rSJb3zjG/Hd7343HnvssfjDH/4QY8aMyX0LGBFx2mmnxZQpU+KFF16IxYsXx9ixY2t9m7Un3bp1y32bumzZsrjwwgujoqKixjpHH310PPfcc7Fy5cqorKzc4zdCl19+eTz22GPxH//xH/H666/HXXfdFVOmTIkrrrii/gegHsrKyqK8vDxuueWWeP3112Pp0qUxbdq0uPHGGyMiYtSoUXHIIYfEN77xjXjllVfi4Ycfjv/8z//8yG3uyzEDgHx57rnnYvLkybF48eJYtWpVzJo1K/7617/Gcccd97HnxX/+53+OkpKS+MpXvhJPP/10vPnmm3H//ffHM888ExHv9QQrVqyIJUuWRGVlZY1g433nnntuHHbYYTF69Oj4wx/+EE888URccsklcf755+duraqPY489Ns4444y44IIL4rnnnovnn38+vvnNb9a4GqWgoCBOPvnkuO666+KVV16JBQsWxPe+97192n63bt1i1qxZsWTJkvjf//3fGDVqVK3e5+ijj44FCxbEn//856isrNzjdr773e/G9OnT49Zbb43ly5fHjTfeGLNmzWqw3qhbt26xePHiePTRR+P111+P73//+7Fo0aKPfd377+df//VfY9myZbmrwiI++uqzj/PJT34yjjjiiLjtttvij3/8Yzz++OMxfvz4Guts2rQpzj///Ljkkkti+PDhMWPGjPjVr34Vv/71r+u8349z5ZVXxjPPPBMXXXRRLFmyJJYvXx4PPfRQLgw76qijolWrVvFf//Vf8eabb8ZDDz0U//Ef/9GgNVx99dXxy1/+Mq6++upYtmxZLF26NK6//vrU9g/7QigFfKQf//jHceqpp8aXv/zl+NKXvhRf+MIX4rOf/Wxu+Q033BCdO3eOU089NUaNGhVXXHFFjeck7c33v//9+MxnPhOnn356DB48ONeIftAVV1wRLVq0iF69euUuKf6wz3zmM/GrX/0qZs6cGX369Ikf/OAH8e///u8xZsyY+r71evnmN78Zv/jFL2L69Olx/PHHx6BBg2L69Om5b4TbtGkTv/nNb+KVV16JE088MSZNmhQ/+tGPPnKb+3LMACBfioqKYsGCBXHmmWdGjx494nvf+17ccMMNMXz48I89L7Zq1SrmzJkTHTp0iDPPPDOOP/74uO6663JXPX/1q1+NM844I4YMGRJHHnlk/PKXv6y1/9atW8ejjz4a77zzTpx00knxj//4j/HFL34xpkyZ0mDvcdq0adG5c+cYNGhQjBw5Mv71X/81OnToUGOdO++8M959993o169fXHrppfHDH/5wn7Z90003xSc/+ckYOHBgjBgxIk4//fT4zGc+U2Odf//3f4+VK1fG3/3d3+Wuyvqwr3zlK3HLLbfEj3/84+jdu3f8/Oc/j2nTpuWeF1RfY8eOjZEjR8Y555wT/fv3j3Xr1sW4ceM+9nVFRUXxm9/8JpYsWRKf/vSnY9KkSfGDH/wgIqLGc6b21yGHHBIzZ86M559/Pvr06RPf+c534sc//nGNdS699NI4/PDDY/LkyRHx3nPFfvSjH8XYsWPjz3/+c533/VH69u0b8+fPj+XLl8cpp5wSJ554Ynz/+9/PPRPqyCOPjOnTp8evf/3r6NWrV1x33XUf+wXl/ho8eHD8+te/joceeig+/elPx2mnnZa7zTKN/cO+yCR1ebAJAAAA1MO9994bX//612Pjxo0N8lwxoOnxoHMAAAAOuLvvvjuOOeaY+NSnPhX/+7//G1deeWX8n//zfwRScBBz+x5wUJs8eXKNP9X7wWn48OH5Lg8ASMmTTz65156gTZs2+S4vNWPHjt3rMRg7dmy9tl1RURHnnXdeHHfccfGd73wnvva1r8Vtt93WQJXXTVP+3Hv37r3Xuu+99958lwf7xO17wEHtnXfe2etf+ikoKIhPfepTKVcEAOTDtm3bPvL5Qt26dUuxmvxZu3ZtVFVV7XFZUVFRrWdoNXVN+XN/66234t13393jsuLi4igsLEy5Ith/QikAAAAAUuf2PQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABSJ5QCAAAAIHVCKQAAAABS1zLfBRxou3btirfffjsKCwsjk8nkuxwAoIlJkiQ2bdoUHTt2jEMOOXi+z3v/fQMA1NXHZTHNPpR6++23o3PnzvkuAwBo4lavXh2dOnXKdxmpqaqqik984hP5LgMAaMI2bNgQbdu23evyZh9KFRYWRsR7jWRRUVGeqwEAmpqqqqro3Llzrqc42OihAID99X7/9HGafSj1/mViRUVFGioAoM4OtscA6KEAgPr6uP7p4HkwAgAAAACNhlAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABInVAKAAAAgNQJpQAAAABIXct8FwANYdWqVVFZWZnvMg5a7du3j6OOOirfZQAAAE2E3+HyrzH8HieUoslbtWpV9Ox5XGzbtjXfpRy0Cgpax6uvLsv7/6EBAACNn9/hGofG8HucUIomr7KyMrZt2xr9/+XqKCo9Ot/lHHSq1qyM5+68JiorK4VSAADAx/I7XP41lt/jhFI0G0WlR0e7o47NdxkAAADsA7/D4UHnAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKROKAUAAABA6oRSAAAAAKQur6HU1KlTo2/fvlFUVBRFRUUxYMCAeOSRR3LLx4wZE5lMpsZ08skn57FiAAAAABpCy3zuvFOnTnHddddFt27dIiLirrvuirPOOitefPHF6N27d0REnHHGGTFt2rTca1q1apWXWgEAAABoOHkNpUaMGFFj/tprr42pU6fGs88+mwulstlslJSU5KM8AAAAAA6QRvNMqZ07d8bMmTNjy5YtMWDAgNz4vHnzokOHDtGjR4+44IILYu3atR+5nerq6qiqqqoxAQAAANC45D2UWrp0abRp0yay2WyMHTs2HnjggejVq1dERAwfPjzuvffeePzxx+OGG26IRYsWxWmnnRbV1dV73V55eXm0bds2N3Xu3DmttwIAAADAPsrr7XsREccee2wsWbIkNmzYEPfff3+MHj065s+fH7169Ypzzjknt16fPn2iX79+0aVLl/jtb38bI0eO3OP2Jk6cGOPHj8/NV1VVCaYAAAAAGpm8h1KtWrXKPei8X79+sWjRorjlllvi5z//ea11S0tLo0uXLrF8+fK9bi+bzUY2mz1g9QIAAABQf3m/fe/DkiTZ6+1569ati9WrV0dpaWnKVQEAAADQkPJ6pdRVV10Vw4cPj86dO8emTZti5syZMW/evJg9e3Zs3rw5ysrK4qtf/WqUlpbGypUr46qrror27dvH2Wefnc+yAQAAAKinvIZSf/nLX+L888+PNWvWRNu2baNv374xe/bsGDp0aGzbti2WLl0ad999d2zYsCFKS0tjyJAhcd9990VhYWE+ywYAAACgnvIaSt1xxx17XVZQUBCPPvpoitUAAAAAkJZG90wpAAAAAJo/oRQAAAAAqRNKAQAAAJA6oRQAAAAA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Gz/77LPjscce2+ftXHTRRXHPPffEjBkzorCwMCoqKqKioiK2bdsWEe/dtnfZZZfF5MmT44EHHog//OEPMWbMmGjdunWMGjWqLqUDAORNQ/VQAADNQZ3/+t7TTz8drVq1qjHepUuX+POf/7zP25k6dWpERAwePLjG+LRp02LMmDERETFhwoTYtm1bjBs3LtavXx/9+/ePOXPmRGFhYV1KBwDIm4bqoQAAmoM6hVK7du2KnTt31hr/05/+tF9hUZIkH7tOJpOJsrKyKCsr258SAQAanYbqoQAAmoM63b43dOjQuPnmm3PzmUwmNm/eHFdffXWceeaZDVUbAECzoocCANitTldK3XTTTTFkyJDo1atX/O1vf4tRo0bF8uXLo3379vHLX/6yoWsEAGgW9FAAALvVKZTq2LFjLFmyJGbOnBnPP/987Nq1K77xjW/EueeeW+OhnQAA7KaHAgDYrU6hVEREQUFBfP3rX4+vf/3rDVkPAECzpocCAHhPnZ4pVV5eHnfeeWet8TvvvDN+9KMf1bsoAIDmSA8FALBbnUKpn//859GzZ89a4717945bb7213kUBADRHeigAgN3qFEpVVFREaWlprfEjjzwy1qxZU++iAACaIz0UAMBudQqlOnfuHE8//XSt8aeffjo6duxY76IAAJojPRQAwG51etD5N7/5zbjsssvi3XffjdNOOy0iIh577LGYMGFCXH755Q1aIABAc6GHAgDYrU6h1IQJE+Kdd96JcePGxfbt2yMi4rDDDosrr7wyJk6c2KAFAgA0F3ooAIDd9juU2rlzZzz11FNx5ZVXxve///1YtmxZFBQURPfu3SObzR6IGgEAmjw9FABATfsdSrVo0SJOP/30WLZsWXTt2jVOOumkA1EXAECzoocCAKipTg86P/744+PNN99s6FoAAJo1PRQAwG51CqWuvfbauOKKK+L//b//F2vWrImqqqoaEwAAtemhAAB2q9ODzs8444yIiPjyl78cmUwmN54kSWQymdi5c2fDVAcA0IzooQAAdqtTKPXEE080dB0AAM2eHgoAYLc6hVKDBg1q6DoAAJo9PRQAwG51eqZURMSTTz4Z5513XgwcODD+/Oc/R0TEf//3f8dTTz3VYMUBADQ3eigAgPfUKZS6//774/TTT4+CgoJ44YUXorq6OiIiNm3aFJMnT27QAgEAmgs9FADA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XlkfHwCAG/XZZ5+pUaNGkqRTp05pz549atGihWPxlIf5Xbp84/gNGzZo27Zteu6551SzZk21bNlS06ZNU926dRUVFSXp8pe9ZGZm6vnnn1d4eLiky7Vccby8vLRo0SINHjxY3bp108aNG0v1Yd6VgoKCFBoaqs8//1yxsbGSLn8zc3Jystq2bXtdrwmAb98DrrFt2zZNnz5d27dv15EjR7R8+XJ99913ioqK0uTJkzVjxgz96U9/0p49e7Rz504tXLhQs2bNkiQ9/PDDqlevnvr166fNmzfrwIEDev/997V161ZJl79t7uDBg0pJSVFmZqbOnz9/zfGHDBkiHx8fDRs2TP/617+0YcMGjRo1SkOHDnWfDn4jmjdvrl69eumxxx7Ttm3blJSUpEcffbTIpsbLL7+sd955R7t379aePXv07rvvql69eu5L/iIjI7V+/XplZGTo1KlTki5f0rZ8+XKlpKToq6++0uDBg0v0qdmVisvns88+q7fffluTJ0/W119/rdTUVC1btkwTJ04s9rVvueUW5eTk6LXXXtOBAwe0aNEivfHGG8Xu16JFC3Xv3l0jR47U559/ruTkZI0cOfKaM6quR0lyFh8fr/DwcE2cOFGzZs2SmenJJ5+8oeMWZciQIapdu7b69u2rxMREHTx4UJs2bdKYMWN07Ngxd9yLFi1Samqqtm3bpiFDhvykTbInnnhCp0+f1kMPPaTt27dr7969WrRokfty1rI+PgAAN+q5557T+vXr9a9//UvDhw9X7dq1Hf3GtvIwv0uXm1Iff/yxXC6XWrZs6V63ePHifJfuNWrUSNWqVXPXbStWrNDUqVNLdIwqVapo8eLFatOmjbp166aMjIzrjnfUqFGaMWOG/u///k9paWkaM2aMTp06dcM1IHAzoykFXCUwMFCffPKJ+vTpo2bNmmnixImaOXOmevfurUcffVRvvvmmEhIS1Lp1a8XFxSkhIUGNGzeWdPlMqDVr1qhu3brq06ePWrdureeff959ed8vfvEL9erVS3fddZfq1KmjpUuXXnN8Pz8/rV69WidPnlSHDh00cOBA3X333frzn//8k73HhQsXKjw8XHFxcRowYIBGjhypunXrFrp9jRo19MILL6h9+/bq0KGDDh06pFWrVrnPMJo5c6bWrl2r8PBw3XHHHZIuN7Jq1aqlmJgY3X///erZs2e++zCVRHH57Nmzp/7xj39o7dq16tChgzp37qxZs2YpIiKi2Ndu27atZs2apRdeeEG33XabFi9erBkzZpQorrfffluhoaH6+c9/rv79++uxxx5TQEBAsZcMFqe4nL399ttatWqVFi1aJG9vb/n5+Wnx4sV68803tWrVqhs6dmH8/Pz0ySefqFGjRhowYICioqL0yCOP6Ny5c+5PVhcsWKBTp07pjjvu0NChQzV69Ogif55KKyQkRP/85z+VnZ2tuLg4RUdHa968ee6zpsr6+AAA3Kjnn39eY8aMUXR0tNLT07VixQpVq1bNsXjKw/wuXb6vlCTFxcW5GztxcXG6dOlSvqZUnTp1lJCQoHfffVctW7bU888/r5deeqnEx/H29tbSpUvVqlUrdevWrVT367rS73//ez388MP61a9+pS5duqhGjRrq2bPnDdeAwM3MZVwECwA35NixYwoPD9e6det09913Ox0OAAAoJzZu3Ki77rpLp06dKvJLZVAx5ebmKioqSg8++GCJz9wCkB/3lAKAUso7a6d169ZKT0/XU089pcjISPenfQAAAKh8Dh8+rDVr1iguLk7nz5/Xn//8Zx08eFCDBw92OjSgwuLyPaCSSUxMdH+1b0HLzWLx4sWF5qBVq1Y39NoXL17U//7v/6pVq1bq37+/6tSpo40bNxZ4E25PKmrcExMTHY2tKPHx8YXGHR8f73R4AAA4ivm9/PDy8lJCQoI6dOigrl27aufOnVq3bp37huwASo/L94BK5ty5c/rmm28Kff56vqmuIsrKytK3335b4HNVq1Yt0X2nKpp9+/YV+lyDBg3K7c2/jx8/rtOnTxf4XGBgIPeHAgDc1JjfAVRmNKUAAAAAAADgcVy+BwAAAAAAAI+jKQUAAAAAAACPoykFAAAAAAAAj6MpBQAAAAAAAI+jKQUAAAAAAACPoykFAAAAAAAAj6MpBQAAAAAAAI/7f0pcqttxI7oWAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "==================================================\n" - ] - } - ], + "outputs": [], "source": [ "## TRIP SUMMARIES\n", "\n", @@ -1679,63 +807,12 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "id": "a8723e3d", "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "For cluster -1:\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/4x/l9lw50rn7qvf79m01f21x70mlpd6gh/T/ipykernel_35596/2042025115.py:34: RuntimeWarning: Mean of empty slice\n", - " oc[cix][feature] = np.nanmean([ic[x].get(feature, np.nan) for x in oix])\n" - ] - }, - { - "data": { - "image/png": "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XrfmzMxMDRkyRHfccYc6dOigTZs2OdZde8Zv6dKlat++vaTLZ2GaNWum4cOHq02bNlq8eLEWLFig1q1bq3nz5mrWrJm++OILSdLLL7+s48ePq1evXmrWrJl27typhIQEjRo1SpKUk5OjUaNGKTIyUpGRkfrLX/6izMxMSdKAAQMUFxenTp066Y477lDPnj0d6wrTt29ftWzZUk2aNFG3bt0cQa6gmtetW6fGjRurSZMm+stf/qK6des65jksLEwTJkxQ27ZtFRoaqvfff1+vv/66WrVqpfr16+ubb76RdDmYxcbGqmXLlmrUqJH69OmjixcvSpJeeeUV9ejRQ8YYZWRkKCoqSgsXLiy09rwan376aTVu3FgtWrTQDz/84Pi9iomJ0fnz5yVJWVlZGjNmjFq1aqVmzZrp8ccf15kzZySp0J9F3uuaNGmS2rZtq/DwcP31r3+97nzmPdfAgQMVFRWlli1b6vvvv3fUe/UZwH//+9+6++671bRpUzVr1kybNm3Sq6++qiFDhji2OXPmjKpVq6ZTp05JKvi/gasdOnRI1apVczy+3u/49X6eAICSiwxFhiJDkaFwCzMAXGLRokUmJibG8fi3334z69evN127djWXLl0yxhizdu1a06RJE2OMMfPmzTP33HOPOXv2rDHGmFOnTpns7GyzevVqExUV5XTsunXrmt27dxtjjGnVqpV56623jDHG7N+/31SpUsUcOXLEGGOMJDN9+nRjjDF79+41FStWNFlZWYXW/MYbb5iYmBiTmZlpLly4YKKioswjjzxijDFm7ty5jn8bY8y//vUvEx0dbYwxZvXq1cZms5l169Y51qempprc3FxjjDHJycmmZs2aJjMzM1/9xhgzceJEM3LkSGOMMTNnzjTt27c3ly5dMllZWaZLly4mKSnJGGNM//79TZs2bczFixdNdna2adu2rVmwYMH1fgzm119/dfx78uTJZujQoQXWfOnSJVOrVi2zdu1aY8zln58kR51169Y1o0aNMsYYs3nzZuPr62v+8Y9/GGOMWbhwoWnTpo0xxpjc3FyTmprq+PfTTz9tXn31VcfjBx54wLz66qsmLi7ODBky5Lq1r1692nh5eZkdO3YYY4yJi4sztWrVMkePHjXGGNOlSxfHz/6VV14x/+///T/Hvi+//LIZPnz4Tf0s4uPjjTHGnDx50gQEBJhjx45dtyZJZvXq1Y7X3rBhQ8e6vN/Vffv2maCgILNv3z5jjDGZmZnmzJkz5vTp06ZGjRrmzJkzxhhjXnvtNTNo0CBjzM39N5CcnGyqVq3qqKew3/Eb/TwBACUXGYoMRYYiQ+HW5eWpZhhQ1jRt2lQ//fST4uLiFB0dra5du+qf//ynvv/+e7Vu3dqx3a+//qrMzEwtXbpUzzzzjAICAiRJlStXvuFznDt3Tjt37tTgwYMlSREREfrDH/6g9evX689//rMkOT6fftddd8nLy0spKSmqXbt2gcdbvXq1+vfvr/Lly6t8+fLq27ev1q9ff1Ov94477tAf/vAHx+Pk5GT16dNHx44dk5eXl1JTU3X48GHdfvvt1z3OypUrNXjwYNntdknSU089pdmzZ+v555+XJPXs2VO+vr6SpFatWt3wvhAffPCB3nvvPWVkZCg9PV3BwcEF1rxv3z75+vrqvvvukyQ9/PDDqlSpktOxHnvsMUlSixYtlJ6erkcffVSSFBUVpYMHD0qSjDGaNm2a/v3vfys7O1tnz55Vu3btJF0+I/X++++refPmqly5stNZ1MLceeedatasmeN5Dx8+7Pj5Xf28S5YsUVpamj799FNJl8/Y5n084UY/i7zfkerVq6tevXpKTk5WrVq1Cq3p9ttvd5zhffTRR/U///M/On78uNM2K1asUNeuXXXHHXdIksqXL6/AwEBJ0iOPPKJ58+Zp+PDhmjVrlj755BNJKtZ/A1fXf/Xv+KlTp2748wQAlExkKDIUGYoMhVsXTSnARerVq6e9e/dq1apVWrlypUaPHq3OnTtr0KBBevnll13yHMYYSZf/UF/t6sc+Pj6Of5crV+66n/vPO15BvLy8lJOT43h86dIlp/UVK1Z0evz444/rtdde00MPPSRJqlKlSr59CqvBVa9n/fr1mjFjhjZs2KDq1avr888/d5r7q2su6Hmvlffc5cqVy/c4r44FCxZozZo1Wrt2rfz9/fXGG29o7dq1jmMcPnxYubm5SktL04ULF5xez/WeM+95rn2cnp7uqH/mzJm6//778x3jRj+LosxpYW40d1cbPny4HnroIdWvX19BQUFq3rx5kZ/vagXVfzM/TwBAyUSGIkORoQpGhsKtgHtKAS5y7Ngx2Ww29ejRQ6+99pqMMerXr5/+7//+T0ePHpUk5ebmauvWrZKkHj16aNasWUpLS5N0+XPiOTk5CggI0NmzZwt8joCAADVr1kzz58+XJB04cEDffvut7r333mLV3LFjR7333nvKzs5Wenq6FixY4FhXv359ff/997p06ZKys7Od1hXk9OnTCgsLkyS9//77On36tFPdhb2mmJgYzZs3T5mZmcrOztY777yjTp06Fev1nD59WgEBAapSpYoyMzP11ltvFbptgwYNdOHCBX377beSpH/+85+O+wkU9TmrVq0qf39/nTt3TvPmzXOsS0tL05///Gf93//9n4YMGaInnnjiuiG2KHr06KGpU6c67h9w8eJF7dmzx1FTYT+L4vj5558dIfHTTz9VrVq1VLNmTadtYmNj9eWXX2r//v2SLt9DIe9n3qBBA4WFhemZZ57RsGHDnF5DQf8NFIerfp4AAOuRochQZCgyFG5dNKUAF9m9e7fatm2rJk2aqEWLFurXr5/atWunxMRE/fGPf1TTpk0VGRnpuEljv3799NBDD6lNmzZq1qyZunbtqoyMDDVp0kR33nmnIiMjHTfpvNoHH3yg999/X02bNtUjjzyi//3f/1WdOnWKVfP//M//KDQ0VA0bNtSDDz7ouGxXktq0aaPY2FhFRkbqgQceuOE317z++ut6+OGH9Yc//EHff/+9QkNDHeuGDx+ugQMHOm7SeW0NTZs2VYsWLdSsWTOFhYVp+PDhxXo9Xbp00e23364GDRooNjbWcQl3Qex2uxYsWKCnn35arVq10oYNGxQUFOS4XPpmPfHEEzp//rwaNmyonj17Os3h4MGD1bt3b91///164YUXZIxRUlJSsV7btcaMGaNmzZqpdevWatKkie655x7H3F7vZ1EczZo100cffaSWLVtq8uTJBYbr22+/Xe+8847+/Oc/q0mTJmrVqpX27dvnWP/UU08pOzvb6cavhf03UByu+nkCAKxHhiJDkaHIULh12YyrWs4AUMqcO3dO/v7+kq7cG+LQoUO67Tb69a4WFxenmjVr6qWXXnLbc/DzBADAGvzNtQ4ZCmUd95QCcMv67LPPNG3aNOXm5sput+vDDz/kj6+LHT9+XPfff7+qVKmiKVOmuPW5+HkCAGAN/ua6HxkKtwqulAJuAS1btsx3I8ZGjRrpgw8+8FBFv8/LL7+sRYsW5Rv/7LPPbniJfEnQo0cPHTlyxGmscuXKWr16tYcqKpk1AQDgaWSokqUk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6rXXXtN3332nLl26qGrVqurYsaO2bt16w31/+eUXSdLdd9+db44WLlyYb378/Pyc7r8AAABKDytyWh6bzaavv/5asbGxSkpKUosWLVS9enUNHz5c586du+H+Rc1wN3tlU17Wy7ti6mqnTp2SzWZTpUqVbupYADyDj+8BKFS5cuXUsWNHffnllzp27NhNNWPsdrsyMjLyjRcUFqTCz14VNF6tWjX5+vrq3XffLXCfatWq3bC+36N69eqSpGPHjhV5Xx8fnwLnJTU11aluLy8vjRgxQiNGjNCZM2e0cuVKvfjii4qNjdXRo0ev++14ecf59NNPVbdu3RvWxJlDAABKr+LktGvlXfl9bUa5tkkkXb55+DvvvCPp8tXjH3/8sRISEpSZmanZs2df93mKmuFuNqPUr19fvr6+2r17d751u3fv1u233879pIASjiulAFzX2LFjZYzRU089pczMzHzrs7Ky9K9//cvxOCwsTLt27XLaZtWqVTp//vzvrqVbt246cOCAqlatqpYtW+ZbbuaeUNfKuwHnzVw9dccdd6h+/fp69913C2wwXU9B87J//37t27ev0H0qVaqkXr16aejQoTp16pQOHTp03ZpjY2Pl5eWlAwcOFDg/efdwAAAAZUNRc9q18rLTtRnl888/v+7z3nHHHRo/frwaN26s7du3O8YLuyLdHRlOunwyr3v37lq0aJHTFVtHjhzR6tWrne55BaBk4kopANfVpk0bzZo1S3FxcYqKitIzzzyjRo0aKSsrSzt27NCcOXMUGRmp7t27S5L69eunl156SRMmTFB0dLT27t2rGTNmKDAw8HfXEh8fr88++0zt2rXTc889pyZNmig3N1dHjhzR8uXLNXLkSLVu3bpIx2zcuLEk6fXXX1f//v1Vvnx53XnnnU73orraP/7xD3Xv3l333HOPnnvuOYWGhurIkSNatmyZPvjgg0Kfp1+/furbt6/i4uL0yCOP6PDhw0pKSnJcfZWne/fuioyMVMuWLVW9enUdPnxY06dPV926dRUREXHdmsPCwvTyyy9r3LhxOnjwoB544AFVrlxZv/zyizZv3qwKFSpo0qRJRZofAABQchU1p10rODhYnTp10uTJk1W5cmXVrVtXX3/9tRYtWuS03a5duzRs2DD96U9/UkREhLy9vbVq1Srt2rVLY8aMcWzXuHFjffTRR1q4cKHq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vnx58+mnn3rqJZRKRZ33BQsWGC8vL/OPf/zD6ff7zJkznnoJpVZR5/5afHMMcGPkJ88hQ1mD/OQ5ZCjPIUO5H00p5PPbb7+ZPn36GH9/f+Pv72/69OljTp8+7bSNJDN37txCj0GoKrqizntycrKRVOCyevVqy+svbf7xj3+YunXrGm9vb9OiRQuzZs0ax7r+/fub6Ohop+2/+eYb07x5c+Pt7W3CwsLMrFmzLK64bCjKvEdHRxf4+92/f3/rCy8Divo7fzUCFXBj5CfPIUNZh/zkOWQozyFDuZfNmP//bnMAAAAAAACARfj2PQAAAAAAAFiOphQAAAAAAAAsR1MKAAAAAAAAlqMpBQAAAAAAAMvRlAIAAAAAAIDlaEoBAAAAAADAcjSlAAAAAAAAYDmaUgAAAAAAALAcTSkAZUqzZs2Unp5u2fN17dpVBw4cKHBd+/bttXTpUstqAQAAKA7yEwBP8fJ0AQDgSjt37rT0+b744gtLnw8AAMDVyE8APIUrpQCUKTabTefPn1dubq6GDRumBg0aqGnTpoqKitKlS5cK3W/AgAF66qmn1LFjRzVo0EADBgxQRkaGJGnBggVq3bq1mjdvrmbNmjkFqbCwMP3www+SpL1796p169Zq0aKF+vTpc93nAwAAKCnITwA8hSulAJRJ33//vb7++mvt3btXt912m86ePStvb+/r7rNp0yZt2LBBvr6+evjhh/X6669r9OjRio2N1Z///GfZbDYdOnRIbdu21eHDh1W+fHmn/fv166fhw4erf//++u6773Tvvfe68yUCAAC4FPkJgNW4UgpAmVSvXj1lZWVp0KBBmj9/vrKysnTbbdd/y3vsscdUsWJFlStXToMGDdLKlSslScnJyerSpYsiIyP10EMPKTU1VYcPH3baNy0tTT/88IP69esnSbrnnnvUuHFj97w4AAAANyA/AbAaTSkAZVJgYKD27Nmj3r1766efflKTJk30888/F+kYNptNkvT444/r6aef1g8//KCdO3eqYsWKBV5anrc9AABAaUR+AmA1mlIAyqRff/1VFy5cUOfOnZWYmKiwsDDt3bv3uvt88sknunDhgnJycjR37lx16tRJknT69GmFhYVJkt5//32dPn06374BAQGKjIzUBx98IEnavHmzdu/e7doXBQAA4EbkJwBW455SAMqko0eP6qmnnlJWVpZy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fv00adIkdevWTTU1Ndq3b5/WrVunKVOmqE+fPvU6Z3x8vCTpn//8p1JTU9W8eXNdfvnlbvei+q1nnnlGgwcP1lVXXaVJkyapY8eO2rdvn/79739r2bJlZ/x1Ro0apZEjRyotLU3/+Z//qb1792revHmuq69OGTx4sOLi4pSQkKCLL75Ye/fuVW5urqKiohQbG3vWmTt16qQ5c+ZoxowZ+vbbb3XjjTeqTZs2+vHHH7Vt2za1bNlSs2fPrtf+AACAxqu+Oe33wsLCdMMNNyg7O1tt2rRRVFSUNmzYoNWrV7sd9+mnn2rChAm64447FBsbq4CAAG3cuFGffvqppk2b5jouPj5eK1eu1KpVqxQTE6PAwEDFx8d7JcOdMnv2bF155ZW65ZZbNG3aNB07dkwzZ85U+/btNWXKlAadE4CFDACcg8LCQpOammo6duxoAgICTMuWLU3Pnj3NzJkzTUlJieu4yspKk5GRYSIjI01QUJBJSkoyhYWFJioqyqSmprqOW7x4sZFktm/fXufXSkpKMl27dj3tHEeOHDEPP/ywufzyy01AQIAJCQkx8fHxZtKkSaa4uNh1nCRz33331Xn97+cwxpjp06ebiIgI06xZMyPJbNq06ax78cEHH5ibbrrJhISEGKfTaS677DIzadKkOu+tqKjItVZTU2PmzZtnYmJiTGBgoElISDAbN240SUlJJikpyXXck08+aRITE0379u1NQECA6dixoxk7dqz57rvvznnmNWvWmP79+5vWrVsbp9NpoqKizO23327eeecd1zGpqammZcuWZ32fAACgaTjXnPb73GGMMQcPHjS33367adu2rQkJCTEjR440O3bsMJLM4sWLjTHG/Pjjj2b06NGmc+fOpmXLlqZVq1amW7du5qmnnjJVVVWuc3333XcmJSXFBAcHG0kmKirK9dz5Zriz2bFjh7n++utNixYtTOvWrc2tt95qvv7663qdA4A9HMYYY18lBgAAAAAAgAsR95QCAAAAAACA5SilAAAAAAAAYDlKKQAAAAAAAFjO1lJq8+bNGjx4sCIiIuRwOLRmzRq3540xyszMVEREhIKCgpScnKxdu3a5HVNZWam///3vat++vVq2bKkhQ4bowIEDFr4LAAAAa5GhAACAL7C1lPr111/VvXt35eXlnfb5efPmKScnR3l5edq+fbvCwsI0YMAAlZeX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fNrXZGdna/bs2XXWIyMjvTLjKTtf/odXzw8AwIUsKSnJq+cvLy9XSEiIV38NK9U3Q5GfAADwPXbnpyZfSp3icDjcHhtj6qydMn36dE2ePNn1uKamRocOHVK7du3O+JoLVVlZmSIjI7V//361bt3a7nEuKOy9fdh7+7D39mDfz84Yo/LyckVERNg9ileca4YiP9UPf67swb7bh723D3tvH/b+zM41PzX5Uqp9+/by8/Or84leSUlJnU/+TnE6nXI6nW5rF110kbdG9AmtW7fmD5lN2Hv7sPf2Ye/twb6fmS9dIXVKfTMU+alh+HNlD/bdPuy9fdh7+7D3p3cu+anJ3+g8ICBAvXr10vr1693W169fr8TERJumAgAAaNzIUAAAwG5N/kopSZo8ebJGjRqlhIQEXX311Xruuee0b98+jR8/3u7RAAAAGi0yFAAAsJNPlFLDhg3Tzz//rDlz5ujgwYOKi4vT2rVrFRUVZfdoTZ7T6dSsWbPqXK4P72Pv7cPe24e9twf7fuEiQ3kPf67swb7bh723D3tvH/b+/DmMr/18YwAAAAAAADR6Tf6eUgAAAAAAAGh6KKUAAAAAAABgOUopAAAAAAAAWI5SCgAAAAAAAJajlAIAAAAAAIDlKKWgBQsWKDo6WoGBgerVq5fee++9sx5fWVmpGTNmKCoqSk6nU5dddplefPFFi6b1LfXd+2XLlql79+5q0aKFwsPDNWbMGP38888WTesbNm/erMGDBysiIkIOh0Nr1qz5w9fk5+erV69eCgwMVExMjBYtWuT9QX1Qffd+9erVGjBggC6++GK1bt1aV199tf79739bM6yPaci/96e8//778vf3V48ePbw2H9AUkZ/sQ36yBxnKPmQoe5CfrEEpdYFbtWqV0tPTNWPGDBUUFKhv37666aabtG/fvjO+ZujQodqwYYNeeOEF7dmzRytWrFDnzp0tnNo31Hfvt2zZorvuuktjx47Vrl279Morr2j79u265557LJ68afv111/VvXt35eXlndPxRUVFGjRokPr27auCggI99NBDmjhxol577TUvT+p76rv3mzdv1oABA7R27Vrt3LlT/fv31+DBg1VQUODlSX1Pfff+lNLSUt111126/vrrvTQZ0DSRn+xDfrIPGco+ZCh7kJ8sYnBB6927txk/frzbWufOnc20adNOe/xbb71lQkJC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7q1u3bpp/PjxOnHixDnPDAAAvI/8dGbkJ+DCQCkFwCMCAwP10Ucfae3atZo4caKqqqokSVOnTtX27dtVWFio//7v/9akSZMkSS+//LI6deqkzz77TJ9++qlb8Pm9yspK3XnnnZo/f762bdumfv36ad++fW7H7Nu3Txs3bqzzCd/dd9+tJUuWuB4vWbJEI0aMUPPmzfX444+rVatW2rZtmwoLC9W1a1fNmjXLdeyWLVv06quvateuXXr77bd1+PBh7d69W5988olWrlzZoH3Kzs7WN998ox07duiTTz7RSy+9JElavny5vvzyS33wwQf6+OOP9be//U0TJkxwve6jjz7S0qVLtXv3bl1yySV69tlnXeebMmWKCgsL9fnnn+vOO++UJE2ZMkX9+vXTtm3b9Mknn6iqqsoV7AAAQONAfjo35CfAd/HtewA84tQ9CK644gr5+/uruLhYHTp00Lp16zR//nyVl5erpqZGZWVlkqSrrrpKTz31lKZMmaKkpCQNHDjwjOfes2ePWrRooeTkZEnS0KFD9V//9V9ux4wZM0YOh6POaxMTE3XixAnt2LFDvXr10tKlS133KlizZo3Kysr06quvSjr5Kdxll13meu3QoUPVqlUrSVL37t31f//3f0pLS1NSUpIGDRrUoH1688039eSTT8rpdEqSLr74Ytcsp2aUpOrqavn5+bled9NNN6lt27aSpKuvvlqfffaZJKl///569NFH9fXXX+u6667Ttdde6zrfhx9+6AqrFRUVCggIaNDMAADAO8hP54b8BPguSikAHhEYGOj6Zz8/P1VVVWnfvn2aOHGitm3bppiYGH366ae67rrrJJ0MBoWFhXrnnXf02muv6eGHH1ZBQYFbkDjlt5ean8mp8HM6o0eP1pIlS1RaWqpLLrlEcXFxrvMuWLDANdPZzhkTE6Pdu3dr48aNeuedd5SRkaHCwkK1adPmD2c7F8YYPfzww7r77rtP+/zp9leS0tPTNWTIEG3YsEEPPfSQ4uLitGDBAhljtGbNGsXExHhkPgAA4Hnkp/NDfgKaPr59D4DXlJaWKiAgQGFhYTLGuF3+XFRUpFatWmno0KGaP3++vvzyyzP+BJrOnTuroqJCmzdvliS9+uqrKi0tPec5UlNT9corr2jRokVu914YMmSIcnJydPToUUnS0aNHtWvXrtOe48CBA3I4HBoyZIieeOIJGWNc9yyojyFDhig3N1eVlZWSTt4b4tT6ggULXPc6OHHihAoKCv7wfHv27FFMTIzuvfdePfTQQ/rwww9d5/vHP/7hCl+HDx/W119/Xe95AQCAtchPdZGfAN/FlVIAvCY+Pl533HGHunbtqo4dO2rAgAGu5959913l5OTIz89P1dXVevzxxxUSEnLa8zidTq1YsUJpaWkKCgpScnKyOnbseM5zhIeHKyEhQW+++aaef/551/q0adM0e/Zs9enTx3Xp+tSpU9W1a9c65/jss880bdo0GWNUU1OjUaNGqVu3buc8wylTp07VjBkz1LNnTwUEBCgiIkJr167VqFGj9PPPPys5OVkOh0NVVVUaO3asevbsedbzzZ8/X5s2bVJAQID8/Pxcl5vn5uZq6tSp6tGjh5o1a6bmzZtr7ty5+tOf/lTvmQEAgHXIT3WRnwDf5TDncl0nAAAAAAAA4EF8+x4AAAAAAAAsx7fvAWg0/vWvf532x+7Onz9fffv2tWGis1u7dq0eeuihOuvTp0/XsGHDbJgIAABcaMhPAJoyvn0PAAAAAAAAluPb9wAAAAAAAGA5SikAAAAAAABYjlIKAAAAAAAAlqOUAgAAAAAAgOUopQAAAAAAAGA5SikAAAAAAABYjlIKAAAAAAAAlvv/u6/mEuFJIU0AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n", - "For cluster 0:\n" - ] - }, - { - "data": { - "image/png": "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t5KzJCcn6y9/+Yu+/vprDRo0SAEBARowYIC2b99+xX2PHTsmSbr99turrNGyZcuqrI+3t7f8/Pycch4AAMDxzMhmF1gsFq1fv15xcXFKT0/XbbfdplatWumZZ55RUVHRFfevbW6rKRNeatasWXbH69ChQ53OD0D9wNf3ANTIzc1NAwYM0Oeff64jR45cVTPGarWqtLS0yvgvv/xS7fzqfmmvpvGWLVvKy8tL7733XrX7tGzZ8or1XYtWrVpJko4cOVLrfT09Patdl+PHj9vV7e7urgkTJmjChAn69ddftW7dOr3wwguKi4vT4cOHL/vreBeO8/HHHys0NPSKNdW09gAAoH6qSza71IW7vS/NJZc2iSQpNDRU7777rqTzd4x/+OGHSklJUVlZmebNm3fZz6ltbrvaXPI///M/GjJkiO11dQ97B9Bw0JQCcFnJycn67LPP9Ic//EF/+9vf5OHhYff+uXPntHr1asXHx0s6/yssu3btspuzYcMGFRcXX3MtQ4YMUWpqqgICAhz2LIULQeZq7p66+eab1aFDB7333nuaMGFCrUJQdeuyb98+7d27t8Zm2g033KChQ4fqp59+UlJSkg4cOKDOnTvXWHNcXJzc3d31448/8rU8AAAaqdpms0tdeB7lrl277J5b+cknn1z2c2+++WZNmzZNy5cv13fffWcbr+kudGfkNkkKDg5WcHCww44HwLVoSgG4rDvvvFNvvfWWEhMT1bNnT/3xj39Uly5ddO7cOeXm5mr+/PmKiIiwBZ8RI0boxRdf1PTp0xUVFaXvv/9eWVlZ8vf3v+ZakpKStHz5cvXr10/jx49Xt27dVFlZqUOHDik7O1sTJ05Unz59anXMrl27SpJef/11JSQkqGnTpurYsaPds6h+680331R8fLzuuOMOjR8/XiEhITp06JDWrFmj999/v8bPGTFihIYPH67ExEQ99NBDOnjwoNLT0213X10QHx+viIgI9erVS61atdLBgweVmZmp0NBQhYeHX7bmdu3aadasWZo6dar279+ve++9V82bN9exY8f07bffysfHRzNnzqzV+gAAgPqlttnsUkFBQRo4cKDS0tLUvHlzhYaGav369VqxYoXdvF27dmncuHF6+OGHFR4eLg8PD23YsEG7du3SlClTbPO6du2qpUuXatmyZWrfvr08PT3VtWtXp+S2Kzlz5ow+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gQOyWCx2dz3t379fjz32mIKDg2W1WhUYGKgBAwZo586dks7nmz179ignJ8eWSdq1a2fbv7a5bd68ebrllltktVq1aNGiWq9Nkyb87y3Q0HCnFIAaVVRUaMOGDerZs6fatm3rlM8YPXq07rvvPi1evFinT59W06ZNJUlHjx7V8OHDNXnyZKWmpqpJkyY6c+aMoqKidOTIEb3wwgvq1q2b9uzZo+nTp2v37t1at26d3V1W//d//6dt27Zp1qxZatasmdLT0/XAAw9o7969at++vZ588kmdOHFCc+bM0YoVK9S6dWtJUufOnWusd82aNYqPj9ctt9yijIwMhYSE6MCBA8rOznbIeqSnpyslJUXTpk1Tv379dO7cOf2///f/bF/Vu1LNqampmjZtmkaNGqVp06aprKxMr7zyivr27atvv/3W7tzKysp0//33a+zYsZoyZYrKy8sdcg4AAMA5zMhmvzV48GBVVFQoPT1dISEhOn78uLZs2WLLJStXrtTQoUPl7++vuXPnSpKtUVbb3LZq1Sp9+eWXmj59uoKCgnTjjTc6/fwAuB5NKQA1On78uM6cOaOwsDCnfcaAAQP09ttvVxk/ceKEPvroI91zzz22sT//+c/atWuXvvnmG/Xq1cu2/0033aShQ4dq9erVGjRokG1+SUmJ1q1bJ19fX0nSbbfdpuDgYH344YeaMmWK2rRpo5CQEElSjx497K7s1eTpp59WSEiIvvnmG3l6etrGR40aVafzv9RXX32lrl272t1tFhcXZ/vny9V8+PBhzZgxQ+PGjdMbb7xhG4+JiVF4eLhmzpypZcuW2cbPnTun6dOnO6x2AADgXGZkswt++eUX7d27V5mZmRo+fLht/MEHH7T9c48ePeTl5SU/Pz/dcccddvu/8cYbtcptxcXF2r17t5o3b+7kMwNQn3B/IwCXeuihh6odb968uV1DSpI+/fRTRURE6NZbb1V5eblti4uLq/Y29P79+9saUpIUGBioG2+8UQcPHqxTrfv27dOPP/6oMWPG2DWkHKl37976xz/+ocTERK1Zs0aFhYVXve+aNWtUXl6uJ554wm59PD09FRUVVe3XEmtafwAAcH1r0aKFOnTooFdeeUUZGRnKzc1VZWXlVe9f29x2zz33XFVDqrKy0u54FRUVtT01APUITSkANWrZsqW8vb2Vl5fntM+48PWzqxk/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BKAx4zOlAASEbdu2afHixdqxY4fatm2r9957T/Pnz1fTpk31hz/8QX/729/UqlUrDRo0SK1bt77ktZo2ber8dUhIiBwOhyTJMAzZbDa34+tbu5QWLVp4dLyn1wcAALgc5CcAjR13SgEICOXl5YqMjNQ111yjs2fP6uWXX3a+Nn78eOXn5ysvL+83bz2/lD59+ujgwYP67LPPJElr1qzRddddp5iYmAbPiYyMVEVFhUdf56233tJPP/0kh8OhvLw8DRo0yOuZAQAAGkJ+AtDYUUoBCAh33323brjhBnXq1ElDhgxRjx49nK/16tVLklRSUqKUlBSvv0bbtm31+uuvKy0tTTfffLOWLl2qN99885LnPPbYY5o/f77zgzovR//+/fXAAw+oS5cuatWqlZ544gmvZwYAAGgI+QlAY2czDMOweggAuFqMHTtWSUlJmjJlitWjAAAABATyExC8uFMKAAAAAAAApuNOKQBBadKkSdq1a5fb+s6dOxUeHu7RtdavX69nnnnGbX327NkaNWqU1zMCAAA0JuQnAGajlAIAAAAAAIDp+Od7AAAAAAAAMB2lFAAAAAAAAExHKQUAAAAAAADTUUoBAAAAAADAdJRSAAAAAAAAMB2lFAAAAAAAAExHKQUAAAAAAADT/R9FkjIFMLShVwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================================\n" - ] - } - ], + "outputs": [], "source": [ "ic, oc = dict(), dict()\n", "\n", @@ -1835,7 +912,7 @@ " offset_col_ix += 1\n", " \n", " plt.tight_layout()\n", - " plt.savefig(f\"./outputs/{CURRENT_DB}_cluster{cix}_combined_features.png\", dpi=300)\n", + " plt.savefig(OUTPUT_DIR / f\"{CURRENT_DB}_cluster{cix}_combined_features.png\", dpi=300)\n", " plt.show()\n", " print(50 * '=')" ] @@ -1850,7 +927,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "id": "d0288db8", "metadata": {}, "outputs": [], @@ -1863,7 +940,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "id": "1b14ad0c", "metadata": {}, "outputs": [], @@ -1876,7 +953,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "id": "2562bbb6-66eb-4283-8c08-6e20a0b2ade5", "metadata": {}, "outputs": [], @@ -1887,7 +964,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "id": "c7aad38a", "metadata": {}, "outputs": [], @@ -1902,7 +979,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "id": "39ce0238-b3f2-4f46-a52f-13e3160cc52f", "metadata": {}, "outputs": [], @@ -1934,7 +1011,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": null, "id": "ec27cf29", "metadata": { "scrolled": false diff --git a/replacement_mode_modeling/05_biogeme_modeling.ipynb b/replacement_mode_modeling/05_biogeme_modeling.ipynb new file mode 100644 index 00000000..29e89b76 --- /dev/null +++ b/replacement_mode_modeling/05_biogeme_modeling.ipynb @@ -0,0 +1,929 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Install biogeme: `pip3 install biogeme==3.2.12`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from enum import Enum\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "import pandas as pd\n", + "import biogeme.biogeme as bio\n", + "import biogeme.database as db\n", + "from biogeme import models\n", + "from biogeme.expressions import Beta, DefineVariable\n", + "from biogeme.expressions import Variable\n", + "import numpy as np\n", + "import seaborn as sns\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor\n", + "from sklearn.metrics import f1_score, r2_score, ConfusionMatrixDisplay\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Global experiment flags and variables.\n", + "SEED = 19348\n", + "TARGETS = ['p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown']\n", + "\n", + "# Set the Numpy seed too.\n", + "np.random.seed(SEED)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SPLIT_TYPE(Enum):\n", + " INTRA_USER = 0\n", + " TARGET = 1\n", + " MODE = 2\n", + " \n", + "\n", + "class SPLIT(Enum):\n", + " TRAIN = 0\n", + " TEST = 1\n", + "\n", + "\n", + "def get_train_test_splits(data: pd.DataFrame, how=SPLIT_TYPE, test_ratio=0.2, shuffle=True):\n", + "\n", + " if how == SPLIT_TYPE.INTRA_USER:\n", + " \n", + " # There are certain users with only one observation. What do we do with those?\n", + " # As per the mobilitynet modeling pipeline, we randomly assign them to either the\n", + " # training or test set.\n", + " \n", + " value_counts = data.user_id.value_counts()\n", + " single_count_ids = value_counts[value_counts == 1].index\n", + " \n", + " data_filtered = data.loc[~data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " data_single_counts = data.loc[data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data_filtered, test_size=test_ratio, shuffle=shuffle, stratify=data_filtered.user_id,\n", + " random_state=SEED\n", + " )\n", + " \n", + " data_single_counts['assigned'] = np.random.choice(['train', 'test'], len(data_single_counts))\n", + " X_tr_merged = pd.concat(\n", + " [X_tr, data_single_counts.loc[data_single_counts.assigned == 'train', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " X_te_merged = pd.concat(\n", + " [X_te, data_single_counts.loc[data_single_counts.assigned == 'test', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " return X_tr_merged, X_te_merged\n", + " \n", + " elif how == SPLIT_TYPE.TARGET:\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data, test_size=test_ratio, shuffle=shuffle, stratify=data.target,\n", + " random_state=SEED\n", + " )\n", + " \n", + " return X_tr, X_te\n", + " \n", + " elif how == SPLIT_TYPE.MODE:\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data, test_size=test_ratio, shuffle=shuffle, stratify=data.section_mode_argmax,\n", + " random_state=SEED\n", + " )\n", + " \n", + " return X_tr, X_te\n", + " \n", + " raise NotImplementedError(\"Unknown split type\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modeling" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following are common features across all datasets:\n", + "\n", + "```\n", + "{'age_21___25_years_old', 'cost_unknown', 'start_local_dt_hour', 'av_walk', 'distance', 'duration', 'av_unknown', 'ft_job', 'end_local_dt_hour', 'cost_no_trip', 'cost_s_micro', 'mph', 'n_residents_u18', 'is_paid', 'n_motor_vehicles', 'target', 'n_working_residents', 'section_distance_argmax', 'n_residence_members', 'has_medical_condition', 'primary_job_description_Other', 'cost_walk', 'cost_p_micro', 'av_transit', 'age_16___20_years_old', 'income_category', 'av_s_car', 'av_no_trip', 'cost_s_car', 'multiple_jobs', 'n_residents_with_license', 'section_duration_argmax', 'age_26___30_years_old', 'cost_car', 'av_p_micro', 'av_ridehail', 'av_car', 'cost_transit', 'available_modes', 'av_s_micro', 'has_drivers_license', 'cost_ridehail', 'user_id', 'section_mode_argmax', 'is_student'}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Read the data.\n", + "\n", + "DATA_SOURCES = [\n", + " ('../data/filtered_data/preprocessed_data_Stage_database.csv', 'allceo'),\n", + " ('../data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv', 'nicr'),\n", + " ('../data/filtered_data/preprocessed_data_openpath_prod_durham.csv', 'durham')\n", + "]\n", + "\n", + "DB_IX = 2\n", + "\n", + "PATH = DATA_SOURCES[DB_IX][0]\n", + "CURRENT_DB = DATA_SOURCES[DB_IX][1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = pd.read_csv(PATH)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data.drop_duplicates(inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(data.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def norm_data(df: pd.DataFrame, split: SPLIT, scaler=None):\n", + " \n", + " columns = df.columns.tolist()\n", + " \n", + " # Ignore dummy features (1/0).\n", + " ignore_cols = [\n", + " c for c in columns if 'age_' in c or 'av_' in c or 'gender_' in c \n", + " or 'primary_job_description' in c or 'is_' in c or 'highest_education' in c\n", + " or '_job' in c or 'has_' in c\n", + " ] + ['user_id', 'target', 'section_mode_argmax']\n", + " \n", + " data = df.loc[:, [c for c in df.columns if c not in ignore_cols]]\n", + " ignored = df.loc[:, ignore_cols]\n", + " \n", + " if split == SPLIT.TRAIN:\n", + " \n", + " scaler = StandardScaler()\n", + " \n", + " scaled = pd.DataFrame(\n", + " scaler.fit_transform(data), \n", + " columns=data.columns, \n", + " index=data.index\n", + " )\n", + " \n", + " elif split == SPLIT.TEST:\n", + " scaled = pd.DataFrame(\n", + " scaler.transform(data), \n", + " columns=data.columns, \n", + " index=data.index\n", + " )\n", + " \n", + " else:\n", + " raise NotImplementedError(\"Unknown split\")\n", + " \n", + " return pd.concat([scaled, ignored], axis=1), scaler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def drop_columns(df: pd.DataFrame):\n", + " \n", + " to_drop = [\n", + " 'available_modes'\n", + " ]\n", + " \n", + " for col in to_drop:\n", + " if col in df.columns:\n", + " df.drop(columns=[col], inplace=True)\n", + " \n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_duration_estimate(df: pd.DataFrame, dset: SPLIT, model_dict: dict):\n", + " \n", + " X_features = ['section_distance_argmax', 'mph']\n", + " \n", + " if dset == SPLIT.TRAIN and model_dict is None:\n", + " model_dict = dict()\n", + " \n", + " if dset == SPLIT.TEST and model_dict is None:\n", + " raise AttributeError(\"Expected model dict for testing.\")\n", + " \n", + " if dset == SPLIT.TRAIN:\n", + " for section_mode in df.section_mode_argmax.unique():\n", + " section_data = df.loc[df.section_mode_argmax == section_mode, :]\n", + " if section_mode not in model_dict:\n", + " model_dict[section_mode] = dict()\n", + "\n", + " model = LinearRegression(fit_intercept=True)\n", + "\n", + " X = section_data[\n", + " X_features\n", + " ]\n", + " Y = section_data[['section_duration_argmax']]\n", + "\n", + " model.fit(X, Y.values.ravel())\n", + "\n", + " r2 = r2_score(y_pred=model.predict(X), y_true=Y.values.ravel())\n", + " print(f\"Train R2 for {section_mode}: {r2}\")\n", + "\n", + " model_dict[section_mode]['model'] = model\n", + " \n", + " elif dset == SPLIT.TEST:\n", + " for section_mode in df.section_mode_argmax.unique():\n", + " \n", + " section_data = df.loc[df.section_mode_argmax == section_mode, :]\n", + " \n", + " X = section_data[\n", + " X_features\n", + " ]\n", + " Y = section_data[['section_duration_argmax']]\n", + " \n", + " if section_mode not in model_dict:\n", + " y_pred = [np.nan for _ in range(len(X))]\n", + " else:\n", + " y_pred = model_dict[section_mode]['model'].predict(X)\n", + " \n", + " r2 = r2_score(y_pred=y_pred, y_true=Y.values.ravel())\n", + " print(f\"Test R2 for {section_mode}: {r2}\")\n", + " \n", + " # Create the new columns for the duration.\n", + " new_columns = ['p_micro','no_trip','s_car','transit','car','s_micro','ridehail','walk','unknown']\n", + " df[new_columns] = 0\n", + " df['temp'] = 0\n", + " \n", + " for section in df.section_mode_argmax.unique():\n", + " X_section = df.loc[df.section_mode_argmax == section, X_features]\n", + " \n", + " # broadcast to all columns.\n", + " df.loc[df.section_mode_argmax == section, 'temp'] = model_dict[section]['model'].predict(X_section)\n", + " \n", + " for c in new_columns:\n", + " df[c] = df['av_' + c] * df['temp']\n", + " \n", + " df.drop(columns=['temp'], inplace=True)\n", + " \n", + " df.rename(columns=dict([(x, 'tt_'+x) for x in new_columns]), inplace=True)\n", + " \n", + " # return model_dict, result_df\n", + " return model_dict, df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now, we drop columns, split the data, and normalize\n", + "\n", + "data = drop_columns(data)\n", + "\n", + "train_data, test_data = get_train_test_splits(data=data, how=SPLIT_TYPE.INTRA_USER, shuffle=True)\n", + "\n", + "train_data, scaler = norm_data(train_data, split=SPLIT.TRAIN)\n", + "test_data, _ = norm_data(test_data, SPLIT.TEST, scaler)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "USERS = list(data.user_id.unique())\n", + "\n", + "USER_MAP = {\n", + " u: i+1 for (i, u) in enumerate(USERS)\n", + "}\n", + "\n", + "train_data['user_id'] = train_data['user_id'].apply(lambda x: USER_MAP[x])\n", + "test_data['user_id'] = test_data['user_id'].apply(lambda x: USER_MAP[x])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(7, 7))\n", + "train_data.target.hist(ax=ax[0])\n", + "test_data.target.hist(ax=ax[1])\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "params, train_data = get_duration_estimate(train_data, SPLIT.TRAIN, None)\n", + "print(10 * \"-\")\n", + "_, test_data = get_duration_estimate(test_data, SPLIT.TEST, params)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Drop section_mode\n", + "\n", + "train_data.drop(columns=['section_mode_argmax'], inplace=True)\n", + "# test_data.drop(columns=['section_mode_argmax'], inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_data.shape, test_data.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(train_data.columns.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Some helper functions that will help ease redundancy in the code.\n", + "\n", + "def get_database(df: pd.DataFrame, split: SPLIT):\n", + " return db.Database(split.name + '_db', df)\n", + "\n", + "\n", + "def get_variables(database: db.Database):\n", + " \n", + " columns = database.data\n", + " \n", + " # User-level features.\n", + " START_HOUR = Variable('start_local_dt_hour')\n", + " END_HOUR = Variable('end_local_dt_hour')\n", + " TRIP_DISTANCE = Variable('distance')\n", + " INCOME = Variable('income_category')\n", + " N_MEMBERS = Variable('n_residence_members')\n", + " N_U18 = Variable('n_residents_u18')\n", + " N_LICENSE = Variable('n_residents_with_license')\n", + " N_VEHICLES = Variable('n_motor_vehicles')\n", + " LICENSE = Variable('has_drivers_license')\n", + " CONDITION = Variable('has_medical_condition')\n", + " FT_JOB = Variable('ft_job')\n", + " MULTIPLE_JOBS = Variable('multiple_jobs')\n", + " \n", + " # Sections\n", + " DISTANCE_ARGMAX = Variable('section_distance_argmax')\n", + " TT_ARGMAX = Variable('section_duration_argmax')\n", + " MPH = Variable('mph')\n", + " \n", + " # Costs\n", + " COST_P_MICRO = Variable('cost_p_micro')\n", + " COST_NO_TRIP = Variable('cost_no_trip')\n", + " COST_S_CAR = Variable('cost_s_car')\n", + " COST_CAR = Variable('cost_car')\n", + " COST_S_MICRO = Variable('cost_s_micro')\n", + " COST_RIDEHAIL = Variable('cost_ridehail')\n", + " COST_WALK = Variable('cost_walk')\n", + " COST_UNKNOWN = Variable('cost_unknown')\n", + " COST_TRANSIT = Variable('cost_transit')\n", + "\n", + " # Availability.\n", + " AV_P_MICRO = Variable('av_p_micro')\n", + " AV_NO_TRIP = Variable('av_no_trip')\n", + " AV_S_CAR = Variable('av_s_car')\n", + " AV_TRANSIT = Variable('av_transit')\n", + " AV_CAR = Variable('av_car')\n", + " AV_S_MICRO = Variable('av_s_micro')\n", + " AV_RIDEHAIL = Variable('av_ridehail')\n", + " AV_WALK = Variable('av_walk')\n", + " AV_UNKNOWN = Variable('av_unknown')\n", + " \n", + " # OHE\n", + " G = [Variable(x) for x in columns if 'gender_' in x]\n", + " E = [Variable(x) for x in columns if 'highest_education' in x]\n", + " PJ = [Variable(x) for x in columns if 'primary_job_description' in x]\n", + " \n", + " # Times.\n", + " TT_P_MICRO = Variable('tt_p_micro')\n", + " TT_NO_TRIP = Variable('tt_no_trip')\n", + " TT_S_CAR = Variable('tt_s_car')\n", + " TT_TRANSIT = Variable('tt_transit')\n", + " TT_CAR = Variable('tt_car')\n", + " TT_S_MICRO = Variable('tt_s_micro')\n", + " TT_RIDEHAIL = Variable('tt_ridehail')\n", + " TT_WALK = Variable('tt_walk')\n", + " TT_UNKNOWN = Variable('tt_unknown')\n", + " \n", + " # Choice.\n", + " CHOICE = Variable('target')\n", + " \n", + " return_dict = locals().copy()\n", + " \n", + " # Remove the gender list and place them in the locals dict.\n", + " for i, val in enumerate(G):\n", + " return_dict.update({'G_' + str(i): val})\n", + " \n", + " del return_dict['G']\n", + " \n", + " \n", + " ## Education\n", + " for i, val in enumerate(E):\n", + " return_dict.update({'E_' + str(i): val})\n", + " \n", + " del return_dict['E']\n", + " \n", + " ## Job\n", + " for i, val in enumerate(PJ):\n", + " return_dict.update({'PJ_' + str(i): val})\n", + " \n", + " del return_dict['PJ']\n", + " \n", + " # return the filtered locals() dictionary.\n", + " return {k:v for k,v in return_dict.items() if not k.startswith('_') and k not in ['database', 'columns']}\n", + "\n", + "\n", + "# def exclude_from_db(v_dict: dict, db: db.Database):\n", + "# EXCLUDE = (v_dict['CHOICE'] == 2) + (v_dict['CHOICE'] == 9) > 0\n", + "# db.remove(EXCLUDE)\n", + "\n", + "def get_params(variables):\n", + " \n", + " param_dict = {'B_' + k: Beta('B_' + k, 0, None, None, 0) for k in variables.keys()}\n", + " \n", + " param_dict['ASC_P_MICRO'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_NO_TRIP'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_S_CAR'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_TRANSIT'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_CAR'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_S_MICRO'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_RIDEHAIL'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_WALK'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " param_dict['ASC_UNKNOWN'] = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " \n", + " # Return filtered locals dict.\n", + " return param_dict\n", + "\n", + "\n", + "def get_utility_functions(v: dict):\n", + " \n", + " ## User-level utility.\n", + " user = 1.\n", + " for var in [\n", + " 'INCOME', 'N_MEMBERS', \n", + " 'N_U18', 'N_LICENSE', 'N_VEHICLES', 'LICENSE', 'CONDITION', 'FT_JOB', 'MULTIPLE_JOBS'\n", + " ]:\n", + " user += v[var] * v['B_'+var]\n", + " \n", + " # OHE (One-hot encoded utility.)\n", + " ohe = 1.\n", + " ohe_vars = [var for var in v if ('G_' in var or 'E_' in var or 'PJ_' in var) and 'B_' not in var]\n", + " for var in ohe_vars:\n", + " ohe += v[var] * v['B_'+var]\n", + " \n", + " ## Trip utility.\n", + " trip = 1.\n", + " for var in ['MPH', 'DISTANCE_ARGMAX', 'TT_ARGMAX', 'START_HOUR', 'END_HOUR', 'TRIP_DISTANCE']:\n", + " trip += v[var] * v['B_' + var]\n", + " \n", + " \n", + " V_P_MICRO = v['ASC_P_MICRO'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_P_MICRO'] * v['B_TT_P_MICRO'] + \\\n", + " v['COST_P_MICRO'] * v['B_COST_P_MICRO']\n", + " \n", + " V_S_MICRO = v['ASC_S_MICRO'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_S_MICRO'] * v['B_TT_S_MICRO'] + \\\n", + " v['COST_S_MICRO'] * v['B_COST_S_MICRO']\n", + " \n", + " V_S_CAR = v['ASC_S_CAR'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_S_CAR'] * v['B_TT_S_CAR'] + \\\n", + " v['COST_S_CAR'] * v['B_COST_S_CAR']\n", + " \n", + " V_CAR = v['ASC_CAR'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_CAR'] * v['B_TT_CAR'] + \\\n", + " v['COST_CAR'] * v['B_COST_CAR']\n", + " \n", + " V_TRANSIT = v['ASC_TRANSIT'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_TRANSIT'] * v['B_TT_TRANSIT'] + \\\n", + " v['COST_TRANSIT'] * v['B_COST_TRANSIT']\n", + " \n", + " V_WALK = v['ASC_WALK'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_WALK'] * v['B_TT_WALK'] + \\\n", + " v['COST_WALK'] * v['B_COST_WALK']\n", + " \n", + " V_RIDEHAIL = v['ASC_RIDEHAIL'] + \\\n", + " ohe + user + trip + \\\n", + " v['TT_RIDEHAIL'] * v['B_TT_RIDEHAIL'] + \\\n", + " v['COST_RIDEHAIL'] * v['B_COST_RIDEHAIL']\n", + " \n", + " V_NO_TRIP = -100\n", + " V_UNKNOWN = -100\n", + " \n", + " # Remember to exclude the input argument.\n", + " return {k:v for k,v in locals().items() if not k.startswith('_') and k != 'v'}\n", + "\n", + "\n", + "def get_utility_mapping(var: dict):\n", + " # Map alterative to utility functions.\n", + " return {\n", + " 1: var['V_P_MICRO'], \n", + " 2: var['V_NO_TRIP'],\n", + " 3: var['V_S_CAR'], \n", + " 4: var['V_TRANSIT'],\n", + " 5: var['V_CAR'], \n", + " 6: var['V_S_MICRO'],\n", + " 7: var['V_RIDEHAIL'], \n", + " 8: var['V_WALK'], \n", + " 9: var['V_UNKNOWN']\n", + " }\n", + "\n", + "\n", + "def get_availability_mapping(var: dict):\n", + " return {\n", + " 1: var['AV_P_MICRO'],\n", + " 2: var['AV_NO_TRIP'],\n", + " 3: var['AV_S_CAR'],\n", + " 4: var['AV_TRANSIT'],\n", + " 5: var['AV_CAR'],\n", + " 6: var['AV_S_MICRO'],\n", + " 7: var['AV_RIDEHAIL'],\n", + " 8: var['AV_WALK'],\n", + " 9: var['AV_UNKNOWN']\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # First, drop columns.\n", + "\n", + "# train_data = drop_columns(train_data)\n", + "\n", + "# train_data, scaler = norm_data(train_data, split=SPLIT.TRAIN)\n", + "\n", + "# get dbs.\n", + "train_db = get_database(train_data, SPLIT.TRAIN)\n", + "\n", + "# get vars.\n", + "train_vars = get_variables(train_db)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_vars" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_params = get_params(train_vars)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_params" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_vars.update(train_params)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_V = get_utility_functions(train_vars)\n", + "train_vars.update(train_V)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "V = get_utility_mapping(train_vars)\n", + "av = get_availability_mapping(train_vars)\n", + "logprob = models.loglogit(V, av, train_vars['CHOICE'])\n", + "\n", + "# logit1 = models.logit(V, av, 1)\n", + "# logit2 = models.logit(V, av, 2)\n", + "# logit3 = models.logit(V, av, 3)\n", + "# logit4 = models.logit(V, av, 4)\n", + "# logit5 = models.logit(V, av, 5)\n", + "# logit6 = models.logit(V, av, 6)\n", + "# logit7 = models.logit(V, av, 7)\n", + "# logit8 = models.logit(V, av, 8)\n", + "# logit9 = models.logit(V, av, 9)\n", + "\n", + "# models = {f'logit_{ix}': logit for ix, logit in enumerate(\n", + "# [logit1, logit2, logit3, logit4, logit5, logit6, logit7, logit8, logit9]\n", + "# )}\n", + "\n", + "model = bio.BIOGEME(train_db, logprob)\n", + "model.modelName = 'customUtility-new'\n", + "model.generate_html = False\n", + "model.generate_pickle = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_results = model.estimate()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(train_results.short_summary())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(train_results.getEstimatedParameters())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from biogeme.expressions import Derive\n", + "\n", + "\n", + "def simulate_results(V, av, db, beta_dict):\n", + " \n", + " wtp = {\n", + " 'WTP s_car': Derive(V[3], 'tt_s_car')/Derive(V[3], 'scaled_cost_s_car'),\n", + " 'WTP transit': Derive(V[4], 'tt_transit')/Derive(V[4], 'scaled_cost_transit'),\n", + " 'WTP car': Derive(V[5], 'tt_car')/Derive(V[5], 'scaled_cost_car'),\n", + " 'WTP s_micro': Derive(V[6], 'tt_s_micro')/Derive(V[6], 'scaled_cost_s_micro'),\n", + " 'WTP ridehail': Derive(V[7], 'tt_ridehail')/Derive(V[7], 'scaled_cost_ridehail')\n", + " }\n", + " \n", + " prob_labels = ['Prob. ' + x for x in TARGETS]\n", + " probs = [models.logit(V, av, i+1) for i in range(len(prob_labels))]\n", + " \n", + " simulate = dict(zip(prob_labels, probs))\n", + " \n", + " # simulate.update(wtp)\n", + " \n", + " biosim = bio.BIOGEME(db, simulate)\n", + " biosim.modelName = 'test-3'\n", + " \n", + " return biosim.simulate(theBetaValues=beta_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "test_data = drop_columns(test_data)\n", + "\n", + "# Scale cost.\n", + "test_data, _ = norm_data(test_data, SPLIT.TEST, scaler)\n", + "\n", + "test_data.drop(columns=['section_mode_argmax'], inplace=True)\n", + "\n", + "# get dbs.\n", + "test_db = get_database(test_data, SPLIT.TEST)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "test_probs = simulate_results(V, av, test_db, train_results.getBetaValues())\n", + "# test_utilities = get_utility_df(train_results, test_data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display(test_probs.head())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# argmax starts from 0. Offset all predicted indices by 1.\n", + "choices = np.argmax(test_probs.values, axis=1) + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "y_true = test_data.chosen\n", + "score = f1_score(y_true, choices, average='weighted')\n", + "\n", + "print(score)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "counts = pd.Series(choices).value_counts()\n", + "ix = counts.index.tolist()\n", + "_x = [i+1 for i in range(len(TARGETS))]\n", + "height = [0 if i not in ix else counts[i] for i in _x]\n", + "ax.bar(x=_x, height=height)\n", + "ax.set_xticks(range(1, 10, 1))\n", + "ax.set_xticklabels(TARGETS, rotation=45)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.metrics import ConfusionMatrixDisplay\n", + "\n", + "fig, ax = plt.subplots()\n", + "cm = ConfusionMatrixDisplay.from_predictions(y_true=y_true, y_pred=choices, ax=ax)\n", + "\n", + "y_unique = np.unique(y_true)\n", + "labelset = [t for i, t in enumerate(TARGETS) if (i+1) in y_unique]\n", + "\n", + "ax.set_xticklabels(labelset, rotation=45)\n", + "ax.set_yticklabels(labelset)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# np.diag(cm.confusion_matrix)/np.sum(cm.confusion_matrix, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# u_np = test_utilities.values\n", + "# choice_df = np.exp(u_np)/np.sum(np.exp(u_np), axis=1, keepdims=True)\n", + "\n", + "# choice_df = pd.DataFrame(choice_df, columns=test_utilities.columns)\n", + "# display(choice_df.head())" + ] + } + ], + "metadata": { + "interpreter": { + "hash": "ab0c6e94c9422d07d42069ec9e3bb23090f5e156fc0e23cc25ca45a62375bf53" + }, + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 9ee6fd40f45ec0b33ba96bccbb65b82a483b3ee2 Mon Sep 17 00:00:00 2001 From: Rahul Kulhalli Date: Wed, 1 May 2024 16:08:10 -0400 Subject: [PATCH 6/6] Adding all other experimental notebooks --- .../experimental_notebooks/LSTM.ipynb | 1398 +++++++++++++++++ .../experimental_notebooks/README.md | 3 + .../baseline_modeling0.ipynb | 1011 ++++++++++++ ...biogeme_modeling train_test_w_splits.ipynb | 1107 +++++++++++++ .../optimal_interuser_splits.ipynb | 617 ++++++++ .../rf_bayesian_optim.py | 280 ++++ 6 files changed, 4416 insertions(+) create mode 100644 replacement_mode_modeling/experimental_notebooks/LSTM.ipynb create mode 100644 replacement_mode_modeling/experimental_notebooks/README.md create mode 100644 replacement_mode_modeling/experimental_notebooks/baseline_modeling0.ipynb create mode 100644 replacement_mode_modeling/experimental_notebooks/biogeme_modeling train_test_w_splits.ipynb create mode 100644 replacement_mode_modeling/experimental_notebooks/optimal_interuser_splits.ipynb create mode 100644 replacement_mode_modeling/experimental_notebooks/rf_bayesian_optim.py diff --git a/replacement_mode_modeling/experimental_notebooks/LSTM.ipynb b/replacement_mode_modeling/experimental_notebooks/LSTM.ipynb new file mode 100644 index 00000000..80260d7e --- /dev/null +++ b/replacement_mode_modeling/experimental_notebooks/LSTM.ipynb @@ -0,0 +1,1398 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "5f2cdb77", + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns\n", + "from abc import ABC, abstractmethod\n", + "from typing import List\n", + "import ast" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ebc3879", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import random\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "import torch.optim as optim\n", + "import numpy as np\n", + "import pandas as pd\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from enum import Enum\n", + "import matplotlib.pyplot as plt\n", + "from torch.nn.utils.rnn import pad_sequence\n", + "from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.metrics import r2_score\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2ace37f", + "metadata": {}, + "outputs": [], + "source": [ + "# Global experiment flags and variables.\n", + "SEED = 13210\n", + "\n", + "'''\n", + "'No Travel', 'Free Shuttle', 'Other', 'Gas Car, drove alone',\n", + " 'Regular Bike', 'Walk', 'Gas Car, with others', 'Bus', 'E-bike',\n", + " 'Scooter share', 'Taxi/Uber/Lyft', 'Train', 'Bikeshare',\n", + " 'Skate board', 'Not a Trip'\n", + "'''\n", + "\n", + "TARGET_MAPPING = {\n", + " 'No Travel': 'no_trip',\n", + " 'Free Shuttle': 'transit',\n", + " 'Other': 'unknown',\n", + " 'Gas Car, drove alone': 'car',\n", + " 'Regular Bike': 'p_micro',\n", + " 'Walk': 'walk',\n", + " 'Gas Car, with others': 's_micro',\n", + " 'Bus': 'transit',\n", + " 'E-bike': 'p_micro',\n", + " 'Scooter share': 's_micro',\n", + " 'Taxi/Uber/Lyft': 'ridehail',\n", + " 'Train': 'transit',\n", + " 'Bikeshare': 's_micro',\n", + " 'Skate board': 'p_micro',\n", + " 'Not a Trip': 'no_trip'\n", + "}\n", + "\n", + "\n", + "TARGETS = {\n", + " x: ix for (ix, x) in enumerate([\n", + " 'p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown'\n", + " ])\n", + "}\n", + "\n", + "av_modes = {\n", + " 'Skateboard': 'p_micro', \n", + " 'Walk/roll': 'walk', \n", + " 'Shared bicycle or scooter': 's_micro', \n", + " 'Taxi (regular taxi, Uber, Lyft, etc)': 'ridehail', \n", + " 'Rental car (including Zipcar/ Car2Go)': 'car',\n", + " 'Bicycle': 'p_micro', \n", + " 'Public transportation (bus, subway, light rail, etc.)': 'transit',\n", + " 'Get a ride from a friend or family member': 's_car',\n", + " 'None': 'no_trip', \n", + " 'Prefer not to say': 'unknown'\n", + "}\n", + "\n", + "# Set the Numpy seed too.\n", + "random.seed(SEED)\n", + "np.random.seed(SEED)\n", + "torch.manual_seed(SEED)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9addd580", + "metadata": {}, + "outputs": [], + "source": [ + "TARGETS" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "481cc1bf", + "metadata": {}, + "outputs": [], + "source": [ + "data = pd.read_csv('../data/final_modeling_data_02142024.csv')\n", + "weather_df = pd.read_csv('../data/denver_weather_data.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8263d9ef", + "metadata": {}, + "outputs": [], + "source": [ + "data.Replaced_mode = data.Replaced_mode.replace(TARGET_MAPPING)\n", + "data.Replaced_mode = data.Replaced_mode.replace(TARGETS)\n", + "data.rename(columns={'Replaced_mode': 'target'}, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8954515f", + "metadata": {}, + "outputs": [], + "source": [ + "data[list(av_modes.values())] = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf9b787b", + "metadata": {}, + "outputs": [], + "source": [ + "def encode_availability(x):\n", + " modes = [y.strip() for y in x.available_modes.split(';')]\n", + " mapped = set([av_modes[x] for x in modes])\n", + " \n", + " for mode in mapped:\n", + " x[mode] = 1\n", + " \n", + " return x\n", + "\n", + "\n", + "data = data.apply(lambda x: encode_availability(x), axis=1)\n", + "data.drop(columns=['available_modes'], inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b010c95f", + "metadata": {}, + "outputs": [], + "source": [ + "data['mark'] = 0\n", + "\n", + "data.section_distances = data.section_distances.apply(lambda x: ast.literal_eval(x))\n", + "data.section_modes = data.section_modes.apply(lambda x: ast.literal_eval(x))\n", + "data.section_durations = data.section_durations.apply(lambda x: ast.literal_eval(x))\n", + "\n", + "data.mark = data.apply(\n", + " lambda x: 1 if (len(x.section_distances) == len(x.section_modes) == len(x.section_durations))\n", + " and len(x.section_distances) > 0 and len(x.section_modes) > 0 and len(x.section_durations) > 0 else 0,\n", + " axis=1\n", + ")\n", + "\n", + "data.section_distances = data.section_distances.apply(lambda x: np.array(x).astype(np.float64))\n", + "data.section_modes = data.section_modes.apply(lambda x: np.array(x))\n", + "data.section_durations = data.section_durations.apply(lambda x: np.array(x).astype(np.float64))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c79cdb8", + "metadata": {}, + "outputs": [], + "source": [ + "data = data.loc[data.mark == 1, :].drop(columns=['mark'], inplace=False).reset_index(drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c420ee08", + "metadata": {}, + "outputs": [], + "source": [ + "class SectionScaler:\n", + " def __init__(self):\n", + " self.dur = dict()\n", + " self.dist = dict()\n", + " \n", + " def compute_stats(self, df):\n", + " \n", + " for _, row in df[['section_modes', 'section_distances', 'section_durations']].iterrows():\n", + " for (mode, distance, duration) in zip(\n", + " row['section_modes'], row['section_distances'], row['section_durations']\n", + " ):\n", + " if mode not in self.dur.keys():\n", + " self.dur[mode] = [duration]\n", + " else:\n", + " self.dur[mode].append(duration)\n", + " \n", + " if mode not in self.dist.keys():\n", + " self.dist[mode] = [distance]\n", + " else:\n", + " self.dist[mode].append(distance)\n", + "\n", + " for mode in self.dur.keys():\n", + " self.dur[mode] = [np.nanmean(self.dur[mode]), np.std(self.dur[mode])]\n", + " \n", + " for mode in self.dist.keys():\n", + " self.dist[mode] = [np.nanmean(self.dist[mode]), np.std(self.dist[mode])]\n", + " \n", + " def apply(self, df):\n", + "\n", + " rows = list()\n", + " \n", + " for ix, x in df.iterrows():\n", + " row = x.to_dict()\n", + " modes = row['section_modes']\n", + " distances = row['section_distances']\n", + " durations = row['section_durations']\n", + " \n", + " norm_distances = [\n", + " (distances[i] - self.dist[mode][0])/self.dist[mode][1] for i, mode in enumerate(modes)\n", + " ]\n", + " \n", + " norm_durations = [\n", + " (durations[i] - self.dur[mode][0])/self.dur[mode][1] for i, mode in enumerate(modes)\n", + " ]\n", + "\n", + " if ix == 0:\n", + " print(norm_distances, norm_durations)\n", + " \n", + " row['section_distances'] = norm_distances\n", + " row['section_durations'] = norm_durations\n", + "\n", + " rows.append(row)\n", + "\n", + " return pd.DataFrame(data=rows)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "889bd770", + "metadata": {}, + "outputs": [], + "source": [ + "class SPLIT_TYPE(Enum):\n", + " INTRA_USER = 0\n", + " INTER_USER = 1\n", + " TARGET = 2\n", + " MODE = 3\n", + " INTER_USER_STATIC = 4\n", + " \n", + "\n", + "class SPLIT(Enum):\n", + " TRAIN = 0\n", + " TEST = 1\n", + "\n", + "def get_splits(count_df: pd.DataFrame, n:int, test_size=0.2):\n", + " maxsize = int(n * test_size)\n", + "\n", + " max_threshold = int(maxsize * 1.05)\n", + " min_threshold = int(maxsize * 0.95)\n", + "\n", + " print(f\"{min_threshold}, {max_threshold}\")\n", + " \n", + " # Allow a 10% tolerance\n", + " def _dp(ix, curr_size, ids, cache):\n", + " \n", + " if ix >= count_df.shape[0]:\n", + " return []\n", + "\n", + " key = ix\n", + "\n", + " if key in cache:\n", + " return cache[key]\n", + "\n", + " if curr_size > max_threshold:\n", + " return []\n", + "\n", + " if min_threshold <= curr_size <= max_threshold:\n", + " return ids\n", + "\n", + " # two options - either pick the current id or skip it.\n", + " branch_a = _dp(ix, curr_size+count_df.loc[ix, 'count'], ids+[count_df.loc[ix, 'index']], cache)\n", + " branch_b = _dp(ix+1, curr_size, ids, cache)\n", + " \n", + " curr_max = []\n", + " if branch_a and len(branch_a) > 0:\n", + " curr_max = branch_a\n", + " \n", + " if branch_b and len(branch_b) > len(branch_a):\n", + " curr_max = branch_b\n", + " \n", + " cache[key] = curr_max\n", + " return cache[key]\n", + " \n", + " return _dp(0, 0, ids=list(), cache=dict())\n", + "\n", + "\n", + "def get_train_test_splits(data: pd.DataFrame, how=SPLIT_TYPE, test_ratio=0.2, shuffle=True):\n", + "\n", + " n_users = list(data.user_id.unique())\n", + " n = data.shape[0]\n", + " \n", + " if shuffle:\n", + " data = data.sample(data.shape[0], random_state=SEED).reset_index(drop=True, inplace=False)\n", + "\n", + " if how == SPLIT_TYPE.INTER_USER:\n", + " # Make the split, ensuring that a user in one fold is not leaked into the other fold.\n", + " # Basic idea: we want to start with the users with the highest instances and place \n", + " # alternating users in each set.\n", + " counts = data.user_id.value_counts().reset_index(drop=False, inplace=False, name='count')\n", + "\n", + " # Now, start with the user_id at the top, and keep adding to either split.\n", + " # This can be achieved using a simple DP program.\n", + " test_ids = get_splits(counts, data.shape[0])\n", + " test_data = data.loc[data.user_id.isin(test_ids), :]\n", + " train_index = data.index.difference(test_data.index)\n", + " train_data = data.loc[data.user_id.isin(train_index), :]\n", + " \n", + " return train_data, test_data\n", + " \n", + " elif how == SPLIT_TYPE.INTRA_USER:\n", + " \n", + " # There are certain users with only one observation. What do we do with those?\n", + " # As per the mobilitynet modeling pipeline, we randomly assign them to either the\n", + " # training or test set.\n", + " \n", + " value_counts = data.user_id.value_counts()\n", + " single_count_ids = value_counts[value_counts == 1].index\n", + " \n", + " data_filtered = data.loc[~data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " data_single_counts = data.loc[data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data_filtered, test_size=test_ratio, shuffle=shuffle, stratify=data_filtered.user_id,\n", + " random_state=SEED\n", + " )\n", + " \n", + " data_single_counts['assigned'] = np.random.choice(['train', 'test'], len(data_single_counts))\n", + " X_tr_merged = pd.concat(\n", + " [X_tr, data_single_counts.loc[data_single_counts.assigned == 'train', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " X_te_merged = pd.concat(\n", + " [X_te, data_single_counts.loc[data_single_counts.assigned == 'test', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " return X_tr_merged, X_te_merged\n", + " \n", + " elif how == SPLIT_TYPE.TARGET:\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data, test_size=test_ratio, shuffle=shuffle, stratify=data.target,\n", + " random_state=SEED\n", + " )\n", + " \n", + " return X_tr, X_te\n", + " \n", + " elif how == SPLIT_TYPE.MODE:\n", + " X_tr, X_te = train_test_split(\n", + " data, test_size=test_ratio, shuffle=shuffle, stratify=data.section_mode_argmax,\n", + " random_state=SEED\n", + " )\n", + " \n", + " return X_tr, X_te\n", + " \n", + " elif how == SPLIT_TYPE.INTER_USER_STATIC:\n", + " \n", + " train_ids = ['810be63d084746e3b7da9d943dd88e8c', 'bf774cbe6c3040b0a022278d36a23f19', '8a8332a53a1b4cdd9f3680434e91a6ef', \n", + " '5ad862e79a6341f69f28c0096fe884da', '7f89656bd4a94d12ad8e5ad9f0afecaf', 'fbaa338d7cd7457c8cad4d0e60a44d18', \n", + " '3b25446778824941a4c70ae5774f4c68', '28cb1dde85514bbabfd42145bdaf7e0a', '3aeb5494088542fdaf798532951aebb0', \n", + " '531732fee3c24366a286d76eb534aebc', '950f4287bab5444aa0527cc23fb082b2', '737ef8494f26407b8b2a6b1b1dc631a4', \n", + " 'e06cf95717f448ecb81c440b1b2fe1ab', '7347df5e0ac94a109790b31ba2e8a02a', 'bd9cffc8dbf1402da479f9f148ec9e60', \n", + " '2f3b66a5f98546d4b7691fba57fa640f', 'f289f7001bd94db0b33a7d2e1cd28b19', '19a043d1f2414dbcafcca44ea2bd1f19', \n", + " '68788082836e4762b26ad0877643fdcf', '4e8b1b7f026c4384827f157225da13fa', '703a9cee8315441faff7eb63f2bfa93f', \n", + " 'add706b73839413da13344c355dde0bb', '47b5d57bd4354276bb6d2dcd1438901d', 'e4cfb2a8f600426897569985e234636e', \n", + " '0154d71439284c34b865e5a417cd48af', '234f4f2366244fe682dccded2fa7cc4e', '0d0ae3a556414d138c52a6040a203d24', \n", + " '44c10f66dec244d6b8644231d4a8fecb', '30e9b141d7894fbfaacecd2fa18929f9', '0eb313ab00e6469da78cc2d2e94660fb', \n", + " 'fc51d1258e4649ecbfb0e6ecdaeca454', 'a1954793b1454b2f8cf95917d7547169', '6656c04c6cba4c189fed805eaa529741', \n", + " '6a0f3653b80a4c949e127d6504debb55', 'dfe5ca1bb0854b67a6ffccad9565d669', '8b1f3ba43de945bea79de6a81716ad04', \n", + " 'cde34edb8e3a4278a18e0adb062999e5', '6d96909e5ca442ccb5679d9cdf3c8f5b', 'a60a64d82d1c439a901b683b73a74d73', \n", + " '60e6a6f6ed2e4e838f2bbed6a427028d', '88041eddad7542ea8c92b30e5c64e198', '1635c003b1f94a399ebebe21640ffced', \n", + " '1581993b404a4b9c9ca6b0e0b8212316', 'b1aed24c863949bfbfa3a844ecf60593', '4b89612d7f1f4b368635c2bc48bd7993', \n", + " 'eb2e2a5211564a9290fcb06032f9b4af', '26767f9f3da54e93b692f8be6acdac43', '8a98e383a2d143e798fc23869694934a', \n", + " 'b346b83b9f7c4536b809d5f92074fdae', 'd929e7f8b7624d76bdb0ec9ada6cc650', '863e9c6c8ec048c4b7653f73d839c85b', \n", + " 'f50537eb104e4213908f1862c8160a3e', '4a9db5a9bac046a59403b44b883cc0ba', 'cded005d5fd14c64a5bba3f5c4fe8385', \n", + " 'c7ce889c796f4e2a8859fa2d7d5068fe', '405b221abe9e43bc86a57ca7fccf2227', '0b3e78fa91d84aa6a3203440143c8c16', \n", + " 'fbff5e08b7f24a94ab4b2d7371999ef7', 'e35e65107a34496db49fa5a0b41a1e9e', 'd5137ebd4f034dc193d216128bb7fc9a', \n", + " '3f7f2e536ba9481e92f8379b796ad1d0', 'dc75e0b776214e1b9888f6abd042fd95', 'b41dd7d7c6d94fe6afe2fd26fa4ac0bd', \n", + " 'eec6936e1ac347ef9365881845ec74df', '8c7d261fe8284a42a777ffa6f380ba3b', '4baf8c8af7b7445e9067854065e3e612', \n", + " 'c6e4db31c18b4355b02a7dd97deca70b', 'f0db3b1999c2410ba5933103eca9212f', '487e20ab774742378198f94f5b5b0b43', \n", + " 'dc1ed4d71e3645d0993885398d5628ca', '8c3c63abb3ec4fc3a61e7bf316ee4efd', '15eb78dd6e104966ba6112589c29dc41', \n", + " 'c23768ccb817416eaf08be487b2e3643', 'ecd2ae17d5184807abd87a287115c299', '71f21d53b655463784f3a3c63c56707b', \n", + " '2931e0a34319495bbb5898201a54feb5', '92bde0d0662f45ac864629f486cffe77', '42b3ee0bc02a481ab1a94644a8cd7a0d', \n", + " '15aa4ba144a34b8b8079ed7e049d84df', '509b909390934e988eb120b58ed9bd8c', '14103cda12c94642974129989d39e50d', \n", + " '8b0876430c2641bcaea954ea00520e64', 'baa4ff1573ae411183e10aeb17c71c53', '14fe8002bbdc4f97acbd1a00de241bf6', \n", + " '1b7d6dfea8464bcab9321018b10ec9c9', '487ad897ba93404a8cbe5de7d1922691', '5182d93d69754d7ba06200cd1ac5980a', \n", + " '91f3ca1c278247f79a806e49e9cc236f', 'e66e63b206784a559d977d4cb5f1ec34', '840297ae39484e26bfebe83ee30c5b3e', \n", + " 'c6807997194c4c528a8fa8c1f6ee1595', '802667b6371f45b29c7abb051244836a', 'b2bbe715b6a14fd19f751cae8adf6b4e', \n", + " 'feb1d940cd3647d1a101580c2a3b3f8c', '1b9883393ab344a69bc1a0fab192a94c', 'ac604b44fdca482fb753034cb55d1351', \n", + " 'f446bf3102ff4bd99ea1c98f7d2f7af0', 'c2c5d4b9a607487ea405a99c721079d4', '85ddd3c34c58407392953c47a32f5428', \n", + " 'd51de709f95045f8bacf473574b96ba5', '6373dfb8cb9b47e88e8f76adcfadde20', '313d003df34b4bd9823b3474fc93f9f9', \n", + " '53e78583db87421f8decb529ba859ca4', '8fdc9b926a674a9ea07d91df2c5e06f2', '90480ac60a3d475a88fbdab0a003dd5d', \n", + " '7559c3f880f341e898a402eba96a855d', '19a4c2cf718d40588eb96ac25a566353', 'f4427cccaa9442b48b42bedab5ab648e', \n", + " 'e192b8a00b6c422296851c93785deaf7', '355e25bdfc244c5e85d358e39432bd44', 'a0c3a7b410b24e18995f63369a31d123', \n", + " '03a395b4d8614757bb8432b4984559b0', 'a2d48b05d5454d428c0841432c7467b6', '3d981e617b304afab0f21ce8aa6c9786', \n", + " '2cd5668ac9054e2eb2c88bb4ed94bc6d', 'd7a732f4a8644bcbb8dedfc8be242fb2', '367eb90b929d4f6e9470d15c700d2e3f', \n", + " 'e049a7b2a6cb44259f907abbb44c5abc', 'a231added8674bef95092b32bc254ac8', 'e88a8f520dde445484c0a9395e1a0599',\n", + " 'cba570ae38f341faa6257342727377b7', '97953af1b97d4e268c52e1e54dcf421a', 'd200a61757d84b1dab8fbac35ff52c28', \n", + " 'fc68a5bb0a7b4b6386b3f08a69ead36f', '4a8210aec25e443391efb924cc0e5f23', '903742c353ce42c3ad9ab039fc418816', \n", + " '2114e2a75304475fad06ad201948fbad', 'ac917eae407c4deb96625dd0dc2f2ba9', '3dddfb70e7cd40f18a63478654182e9a', \n", + " 'd3735ba212dd4c768e1675dca7bdcb6f', '7abe572148864412a33979592fa985fb', 'd3dff742d07942ca805c2f72e49e12c5' \n", + " ]\n", + " \n", + " X_tr = data.loc[data.user_id.isin(train_ids), :]\n", + " X_te = data.loc[~data.user_id.isin(train_ids), :]\n", + " \n", + " return X_tr, X_te\n", + " \n", + " raise NotImplementedError(\"Unknown split type\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b34ced0", + "metadata": {}, + "outputs": [], + "source": [ + "def drop_columns(df: pd.DataFrame):\n", + " to_drop = [\n", + " 'raw_trip',\n", + " 'start_ts',\n", + " 'start_loc',\n", + " 'start_place',\n", + " 'end_place',\n", + " 'cleaned_trip',\n", + " 'inferred_labels',\n", + " 'inferred_trip',\n", + " 'expectation',\n", + " 'confidence_threshold',\n", + " 'expected_trip',\n", + " 'user_input',\n", + " 'start:year',\n", + " 'start:month',\n", + " 'start:day',\n", + " 'start:hour',\n", + " 'start_local_dt_minute',\n", + " 'start_local_dt_second',\n", + " 'start_local_dt_weekday',\n", + " 'start_local_dt_timezone',\n", + " 'end:year',\n", + " 'end:month',\n", + " 'end:day',\n", + " 'end:hour',\n", + " 'end_local_dt_minute',\n", + " 'end_local_dt_second',\n", + " 'end_local_dt_weekday',\n", + " 'end_local_dt_timezone',\n", + " '_id',\n", + " 'metadata_write_ts',\n", + " 'additions',\n", + " 'mode_confirm',\n", + " 'purpose_confirm',\n", + " 'distance_miles',\n", + " 'Mode_confirm',\n", + " 'Trip_purpose',\n", + " 'original_user_id',\n", + " 'program',\n", + " 'opcode',\n", + " 'Timestamp',\n", + " 'birth_year',\n", + " 'gender_Man',\n", + " 'gender_Man;Nonbinary/genderqueer/genderfluid',\n", + " 'gender_Nonbinary/genderqueer/genderfluid',\n", + " 'gender_Prefer not to say',\n", + " 'gender_Woman',\n", + " 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", + " 'has_multiple_jobs_No',\n", + " 'has_multiple_jobs_Prefer not to say',\n", + " 'has_multiple_jobs_Yes',\n", + " \"highest_education_Bachelor's degree\",\n", + " 'highest_education_Graduate degree or professional degree',\n", + " 'highest_education_High school graduate or GED',\n", + " 'highest_education_Less than a high school graduate',\n", + " 'highest_education_Prefer not to say',\n", + " 'highest_education_Some college or associates degree',\n", + " 'primary_job_type_Full-time',\n", + " 'primary_job_type_Part-time',\n", + " 'primary_job_type_Prefer not to say',\n", + " 'is_overnight_trip',\n", + " 'n_working_residents',\n", + " 'start_lat',\n", + " 'start_lng',\n", + " 'end_lat',\n", + " 'end_lng',\n", + " 'source', 'end_ts', 'end_fmt_time', 'end_loc',\n", + " ]\n", + "\n", + " # Drop section_mode_argmax and available_modes.\n", + " return df.drop(\n", + " columns=to_drop, \n", + " inplace=False\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "904fa4dc", + "metadata": {}, + "outputs": [], + "source": [ + "processed = drop_columns(data)\n", + "\n", + "train_df, test_df = get_train_test_splits(data=processed, how=SPLIT_TYPE.INTER_USER_STATIC, shuffle=True)\n", + "\n", + "scaler = SectionScaler()\n", + "scaler.compute_stats(train_df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44354097", + "metadata": {}, + "outputs": [], + "source": [ + "print(scaler.dist)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c4fee4f-0da8-4391-9528-ef5fd7837365", + "metadata": {}, + "outputs": [], + "source": [ + "train_df = scaler.apply(train_df)\n", + "test_df = scaler.apply(test_df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71eed47f-3a58-4072-8dbe-f5287084f4c4", + "metadata": {}, + "outputs": [], + "source": [ + "train_df.shape, test_df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30d39919", + "metadata": {}, + "outputs": [], + "source": [ + "train_df.section_distances.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ff1c96e-7f18-44bd-8df2-f92239114e9e", + "metadata": {}, + "outputs": [], + "source": [ + "class SectionEmbedding(nn.Module):\n", + " def __init__(self, input_dim, emb_dim=32):\n", + " super(SectionEmbedding, self).__init__()\n", + " self.dpt = nn.Dropout(0.2)\n", + " self.encoder = nn.Linear(input_dim, emb_dim)\n", + " self.decoder = nn.Linear(emb_dim, input_dim)\n", + " self.act = nn.LeakyReLU()\n", + " \n", + " def forward(self, x):\n", + " '''\n", + " Input will be a one-hot encoded matrix, where nrows=number of modes, ncols=input_dim\n", + " dim = (B, N, D)\n", + " \n", + " '''" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97a8d6b2", + "metadata": {}, + "outputs": [], + "source": [ + "class ReplacedModeDataset(Dataset):\n", + " def __init__(self, df: pd.DataFrame):\n", + " self.data = df\n", + " \n", + " def __len__(self):\n", + " return len(self.data.ix.unique())\n", + " \n", + " def __getitem__(self, ix):\n", + " \n", + " # Could be between 1 - 15.\n", + " sequence = self.data.loc[self.data.ix == ix, :]\n", + " \n", + " # Static features that do not vary with time.\n", + " demographic_features = ['n_residence_members', \n", + " 'primary_job_commute_time', 'income_category',\n", + " 'n_residents_u18', 'n_residents_with_license', 'n_motor_vehicles', 'age', \n", + " 'p_micro', 'walk', 's_micro', 'ridehail', 'car', 'transit', 's_car', 'no_trip', 'unknown',\n", + " 'has_drivers_license_No', 'has_drivers_license_Prefer not to say', 'has_drivers_license_Yes', \n", + " 'primary_job_description_Clerical or administrative support', 'primary_job_description_Custodial', \n", + " 'primary_job_description_Education', 'primary_job_description_Food service', \n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming', \n", + " 'primary_job_description_Medical/healthcare', 'primary_job_description_Other', \n", + " 'primary_job_description_Professional, managerial, or technical', \n", + " 'primary_job_description_Sales or service', 'primary_job_commute_mode_Active transport', \n", + " 'primary_job_commute_mode_Car transport', 'primary_job_commute_mode_Hybrid', \n", + " 'primary_job_commute_mode_Public transport', 'primary_job_commute_mode_Unknown', \n", + " 'primary_job_commute_mode_WFH', 'duration', 'distance']\n", + " \n", + " seq_features = ['section_distances', 'section_durations', 'section_modes', 'mph']\n", + " \n", + " weather_features = ['temperature_2m (°F)', \n", + " 'relative_humidity_2m (%)', 'dew_point_2m (°F)', 'rain (inch)', 'snowfall (inch)', \n", + " 'wind_speed_10m (mp/h)', 'wind_gusts_10m (mp/h)']\n", + " \n", + " return (\n", + " sequence[seq_features], sequence[demographic_features], \n", + " sequence[weather_features], sequence['target']\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3b36058", + "metadata": {}, + "outputs": [], + "source": [ + "dset = ReplacedModeDataset(train_df)\n", + "\n", + "print(dset.__getitem__(20))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02b78758", + "metadata": {}, + "outputs": [], + "source": [ + "train_dset = CustomDataset(train_df)\n", + "test_dset = CustomDataset(test_df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "627b6fa4", + "metadata": {}, + "outputs": [], + "source": [ + "def collate(batch):\n", + " X, y = zip(*batch)\n", + " \n", + " seq_modes = [x[0] for x in X]\n", + " seq_metrics = [x[1] for x in X]\n", + " features = [x[-1] for x in X]\n", + "\n", + " padded_seq = pad_sequence([s for s in seq_modes], batch_first=True)\n", + " padded_metrics = pad_sequence([m for m in seq_metrics], batch_first=True)\n", + " lengths = [len(seq) for seq in seq_modes]\n", + " stacked_features = torch.stack(features)\n", + "\n", + " return (padded_seq, padded_metrics, stacked_features), torch.stack(y), lengths" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ca34681", + "metadata": {}, + "outputs": [], + "source": [ + "train_loader = DataLoader(train_dset, batch_size=16, collate_fn=collate, shuffle=True, drop_last=False)\n", + "test_loader = DataLoader(test_dset, batch_size=16, collate_fn=collate, shuffle=True, drop_last=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31ca5ab1", + "metadata": {}, + "outputs": [], + "source": [ + "(modes, metrics, features), sY1, lX = next(iter(train_loader))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9eb5a93a", + "metadata": {}, + "outputs": [], + "source": [ + "metrics.size(), modes.size()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0abf380", + "metadata": {}, + "outputs": [], + "source": [ + "# Set to 0 for no dropout.\n", + "DROPOUT = 0." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48871ea4", + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "\n", + "class GELU_new(nn.Module):\n", + " \"\"\"\n", + " Taken from OpenAI GPT-2 implementation.\n", + " \"\"\"\n", + " \n", + " def __init__(self):\n", + " super(GELU_new, self).__init__()\n", + " \n", + " def forward(self, x):\n", + " return 0.5 * x * (1.0 + torch.tanh(math.sqrt(2.0 / math.pi) * (x + 0.044715 * torch.pow(x, 3.0))))\n", + "\n", + "\n", + "class DilatedBlock(nn.Module):\n", + " def __init__(self, n_c):\n", + " super(DilatedBlock, self).__init__()\n", + " \n", + " self.block = nn.Sequential(\n", + " nn.Linear(n_c, 4*n_c, bias=False),\n", + " GELU_new(),\n", + " nn.Linear(4*n_c, n_c, bias=False),\n", + " nn.Dropout(DROPOUT)\n", + " )\n", + " \n", + " def forward(self, x):\n", + " return self.block(x)\n", + "\n", + " \n", + "class SelfAttention(nn.Module):\n", + " def __init__(self, n_features, head_size):\n", + " super(SelfAttention, self).__init__()\n", + " # in: (B, F, 64)\n", + " self.k = nn.Linear(n_features, head_size, bias=False)\n", + " self.q = nn.Linear(n_features, head_size, bias=False)\n", + " self.v = nn.Linear(n_features, head_size, bias=False)\n", + " self.dpt = nn.Dropout(DROPOUT)\n", + " self.sqrt_d = torch.sqrt(torch.tensor(head_size))\n", + " \n", + " def forward(self, x):\n", + " k = self.k(x)\n", + " q = self.q(x)\n", + " v = self.v(x)\n", + " \n", + " # Q.K.t\n", + " dot = torch.bmm(q, k.permute(0, 2, 1))\n", + " \n", + " # normalize dot product.\n", + " dot /= self.sqrt_d\n", + " \n", + " # softmax over -1 dim.\n", + " softmax = self.dpt(torch.softmax(dot, dim=-1))\n", + " \n", + " # dot with values. (B, F, F) * (B, F, x) = (B, F, x)\n", + " return torch.bmm(softmax, v)\n", + " \n", + "\n", + "class MultiHeadAttention(nn.Module):\n", + " def __init__(self, n_heads, n_dim):\n", + " super(MultiHeadAttention, self).__init__()\n", + " \n", + " # 64 dims, 4 heads => 16 dims per head.\n", + " head_size = n_dim//n_heads\n", + " self.heads = nn.ModuleList([SelfAttention(n_dim, head_size) for _ in range(n_heads)])\n", + " self.proj = nn.Linear(n_dim, n_dim, bias=False)\n", + " \n", + " def forward(self, x):\n", + " # x is (B, seq, n_dim)\n", + " cat = torch.cat([head(x) for head in self.heads], dim=-1)\n", + " return self.proj(cat)\n", + "\n", + "\n", + "class Block(nn.Module):\n", + " def __init__(self, n_c):\n", + " super(Block, self).__init__()\n", + " \n", + " self.sa = MultiHeadAttention(n_heads=4, n_dim=n_c)\n", + " self.dilated = DilatedBlock(n_c)\n", + " self.ln1 = nn.LayerNorm(n_c)\n", + " self.ln2 = nn.LayerNorm(n_c)\n", + " \n", + " \n", + " def forward(self, x):\n", + " x = x + self.sa(self.ln1(x))\n", + " x = x + self.dilated(self.ln2(x))\n", + " return x\n", + " \n", + "\n", + "class LSTMLayer(nn.Module):\n", + " def __init__(\n", + " self, input_size: int, hidden_size: int, \n", + " output_size: int, n_lstm_layers: int = 1\n", + " ):\n", + " super(LSTMLayer, self).__init__()\n", + " \n", + " n_embed_mode = 16\n", + " \n", + " self.hidden_size = hidden_size\n", + " self.embedding = nn.Embedding(7, n_embed_mode, padding_idx=0)\n", + " self.dpt = nn.Dropout(DROPOUT)\n", + " \n", + " self.lstm = nn.LSTM(\n", + " input_size=input_size + n_embed_mode,\n", + " hidden_size=hidden_size,\n", + " bias=False,\n", + " bidirectional=True,\n", + " batch_first=True,\n", + " num_layers=n_lstm_layers\n", + " )\n", + " \n", + " def forward(self, modes, x, lengths):\n", + " mode_emb = self.embedding(modes)\n", + " x = torch.cat([x, mode_emb], dim=-1)\n", + " \n", + " packed = pack_padded_sequence(x, lengths, batch_first=True, enforce_sorted=False)\n", + " out, _ = self.lstm(packed)\n", + " unpacked, _ = pad_packed_sequence(out, batch_first=True)\n", + " \n", + " return self.dpt(unpacked)\n", + "\n", + "\n", + "class Model(nn.Module):\n", + " def __init__(\n", + " self, input_size: int, hidden_size: int, output_size: int, \n", + " n_features: int, n_lstm_layers: int = 1, **kwargs\n", + " ):\n", + " super(Model, self).__init__()\n", + " \n", + " block1_ip_dim = hidden_size*2\n", + " block2_ip_dim = (hidden_size*2) + n_features\n", + " \n", + " self.lstm = LSTMLayer(\n", + " input_size, hidden_size, \n", + " output_size, n_lstm_layers\n", + " )\n", + " \n", + " self.block_l1 = nn.ModuleList([Block(block1_ip_dim) for _ in range(kwargs['l1_blocks'])])\n", + " self.block_l2 = nn.ModuleList([Block(block2_ip_dim) for _ in range(kwargs['l2_blocks'])])\n", + " self.final_proj = nn.Linear(block2_ip_dim, output_size, bias=True)\n", + " \n", + " def forward(self, modes, x, features, lengths):\n", + " \n", + " b = x.size(0)\n", + " \n", + " # Out = (B, seq, hidden*2)\n", + " lstm_out = self.lstm(modes, x, lengths)\n", + " \n", + " # Pass the raw output through the blocks.\n", + " for module in self.block_l1:\n", + " lstm_out = module(lstm_out)\n", + " \n", + " features_rshp = features.unsqueeze(1).expand(b, lstm_out.size(1), -1)\n", + " \n", + " # Out = (B, seq, n+40)\n", + " cat = torch.cat([lstm_out, features_rshp], dim=-1)\n", + " \n", + " for module in self.block_l2:\n", + " cat = module(cat)\n", + " \n", + " # (8, 3, 104) -> (B, 104)\n", + " # flattened = cat.view(b, -1)\n", + " \n", + " # proj = self.runtime_ffw(flattened.size(-1), 64)(flattened)\n", + " proj = cat.mean(dim=1)\n", + " \n", + " return self.final_proj(proj)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70b4d4ea", + "metadata": {}, + "outputs": [], + "source": [ + "import torch.nn.init as init\n", + "\n", + "def init_weights(module):\n", + " if isinstance(module, nn.Embedding):\n", + " module.weight.data.normal_(mean=0.0, std=1.0)\n", + " if module.padding_idx is not None:\n", + " module.weight.data[module.padding_idx].zero_()\n", + " elif isinstance(module, nn.LayerNorm):\n", + " module.bias.data.zero_()\n", + " module.weight.data.fill_(1.0)\n", + " elif isinstance(module, nn.BatchNorm1d):\n", + " init.normal_(m.weight.data, mean=1, std=0.02)\n", + " init.constant_(m.bias.data, 0)\n", + " elif isinstance(module, nn.Linear):\n", + " init.xavier_normal_(module.weight.data)\n", + " if module.bias is not None:\n", + " init.normal_(module.bias.data)\n", + " elif isinstance(module, nn.LSTM):\n", + " for param in module.parameters():\n", + " if len(param.shape) >= 2:\n", + " init.orthogonal_(param.data)\n", + " else:\n", + " init.normal_(param.data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "282ecd1a", + "metadata": {}, + "outputs": [], + "source": [ + "model = Model(\n", + " n_lstm_layers=3,\n", + " input_size=3,\n", + " hidden_size=32, \n", + " output_size=num_classes,\n", + " n_features=40,\n", + " l1_blocks=4,\n", + " l2_blocks=4\n", + ")\n", + "\n", + "model = model.apply(init_weights)\n", + "\n", + "print(model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20fec22b", + "metadata": {}, + "outputs": [], + "source": [ + "print(sum(p.numel() for p in model.parameters()))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ca4b65a", + "metadata": {}, + "outputs": [], + "source": [ + "weights = train_df.shape[0]/(np.bincount(train_df.chosen.values) * len(np.unique(train_df.chosen)))\n", + "\n", + "print(weights)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7a2017b", + "metadata": {}, + "outputs": [], + "source": [ + "INIT_LR = 1e-3\n", + "optimizer = optim.Adam(model.parameters(), lr=INIT_LR)\n", + "criterion = nn.CrossEntropyLoss(weight=torch.Tensor(weights))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5bbda7c", + "metadata": {}, + "outputs": [], + "source": [ + "class Trainer:\n", + " def __init__(self, model, tr_loader, te_loader):\n", + " pass\n", + " \n", + " def set_optim_params(self, **kwargs):\n", + " pass\n", + " \n", + " def set_criterion(self, **kwargs):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e53e4fd1", + "metadata": {}, + "outputs": [], + "source": [ + "def train(epoch, model, loader, opt, criterion, val_ix):\n", + " \n", + " print(\"\\tBeginning training.\")\n", + " \n", + " n_batches = len(loader)\n", + " print_every = n_batches//5\n", + " \n", + " train_losses, val_losses = [], []\n", + " \n", + " for ix, (X, y, lengths) in enumerate(loader):\n", + " \n", + " # Unpack X.\n", + " modes, metrics, features = X\n", + " # Cast y to appropriate type.\n", + " y = y.float()\n", + " \n", + " if ix in val_ix:\n", + " model.eval()\n", + " with torch.no_grad():\n", + " y_pred = model(modes, metrics.float(), features.float(), lengths)\n", + " loss = criterion(y_pred.view(-1, num_classes), y.view(-1, num_classes))\n", + " val_losses.append(loss.item())\n", + " else:\n", + " model.train()\n", + " \n", + " opt.zero_grad()\n", + "\n", + " y_pred = model(modes, metrics.float(), features.float(), lengths)\n", + " loss = criterion(y_pred.view(-1, num_classes), y.view(-1, num_classes))\n", + " train_losses.append(loss.item())\n", + "\n", + " loss.backward()\n", + "\n", + " optimizer.step()\n", + " \n", + " if ix and ix % print_every == 0:\n", + " print(\n", + " f\"\\t-> Train loss: {np.nanmean(train_losses)}\\n\\t-> Val loss: {np.nanmean(val_losses)}\"\n", + " )\n", + " print('\\t'+20*'*')\n", + "\n", + " print(50*'-')\n", + " return train_losses, val_losses" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a33fefa", + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate(model, loader, criterion):\n", + " \n", + " print(\"\\tBeginning evaluation.\")\n", + " \n", + " model.eval()\n", + " \n", + " print_every = len(loader)//5\n", + " \n", + " losses = []\n", + " \n", + " for ix, (X, y, lengths) in enumerate(loader):\n", + " \n", + " modes, metrics, features = X\n", + "\n", + " y_pred = model(modes, metrics.float(), features.float(), lengths)\n", + " y = y.float()\n", + " \n", + " loss = criterion(y_pred.view(-1, num_classes), y.view(-1, num_classes))\n", + "\n", + " losses.append(loss.item())\n", + " \n", + " if ix and ix % print_every == 0:\n", + " print(f\"\\t -> Average loss: {np.nanmean(losses)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "650a5240", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.metrics import f1_score\n", + "\n", + "\n", + "def evaluate_f1(model, tr_loader, val_ix, te_loader=None):\n", + " \n", + " tr_preds, val_preds, te_preds = np.array([]), np.array([]), np.array([])\n", + " tr_gt, val_gt, te_gt = np.array([]), np.array([]), np.array([])\n", + " \n", + " model.eval()\n", + " print(\"\\tEvaluating F1...\")\n", + " \n", + " with torch.no_grad():\n", + " for ix, (X, y, lengths) in enumerate(tr_loader):\n", + " \n", + " modes, metrics, features = X\n", + "\n", + " y_pred = model(modes, metrics.float(), features.float(), lengths).view(-1, num_classes)\n", + " y = y.float().view(-1, num_classes)\n", + "\n", + " preds = torch.argmax(F.softmax(y_pred, dim=-1), dim=-1).numpy().ravel()\n", + " true = torch.argmax(y.long(), dim=-1).numpy().ravel()\n", + " \n", + " if ix in val_ix:\n", + " val_preds = np.append(val_preds, preds)\n", + " val_gt = np.append(val_gt, true)\n", + " else:\n", + " tr_preds = np.append(tr_preds, preds)\n", + " tr_gt = np.append(tr_gt, true)\n", + " \n", + " tr_f1 = f1_score(y_true=tr_gt, y_pred=tr_preds, average='weighted')\n", + " val_f1 = f1_score(y_true=val_gt, y_pred=val_preds, average='weighted')\n", + " print(f\"\\t -> Train F1: {tr_f1}, Val F1: {val_f1}\")\n", + " \n", + " if not te_loader:\n", + " return tr_f1, val_f1, None\n", + "\n", + " for ix, (X, y, lengths) in enumerate(te_loader):\n", + " \n", + " modes, metrics, features = X\n", + "\n", + " y_pred = model(modes, metrics.float(), features.float(), lengths).view(-1, num_classes)\n", + " y = y.float().view(-1, num_classes)\n", + " \n", + " preds = torch.argmax(F.softmax(y_pred, dim=-1), dim=-1).numpy().ravel()\n", + " true = torch.argmax(y.long(), dim=-1).numpy().ravel()\n", + "\n", + " te_preds = np.append(te_preds, preds)\n", + " te_gt = np.append(te_gt, true)\n", + " \n", + " te_f1 = f1_score(y_true=te_gt, y_pred=te_preds, average='weighted')\n", + " print(f\"\\t -> Test F1: {te_f1}\")\n", + " \n", + " return tr_f1, val_f1, te_f1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7191e78b", + "metadata": {}, + "outputs": [], + "source": [ + "# Other training hyperparameters.\n", + "num_epochs = 18\n", + "num_decays = 6\n", + "decay_at = num_epochs // num_decays\n", + "decay = 0.9\n", + "eval_every = 3\n", + "\n", + "# Static hold-out val set.\n", + "n_batches = len(train_loader)\n", + "val_split = 0.2\n", + "val_batches = np.random.choice(n_batches, size=(int(val_split * n_batches),), replace=False)\n", + "\n", + "# Just checking what LRs should be after decaying.\n", + "for power in range(num_decays):\n", + " print(f\"{decay_at * power} - {decay_at * (power + 1)} :: {INIT_LR * decay**power:.5f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc4b72de", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# We'd like to start at a loss of at most -ln(1/9) ~ 2.19\n", + "\n", + "# Wrapper to contain all losses.\n", + "tr_losses, val_losses = list(), list()\n", + "save_at_best_loss = True\n", + "best_loss = np.inf\n", + "model_name = \"../models/LSTM_{epoch}_{loss}.pt\"\n", + "patience, delta = 2, 0\n", + "\n", + "for epoch_ix in range(1, num_epochs+1):\n", + " print(f\"Epoch {epoch_ix}:\")\n", + " tr_loss, val_loss = train(epoch_ix, model, train_loader, optimizer, criterion, val_batches)\n", + " \n", + " tr_losses.extend(tr_loss)\n", + " val_losses.extend(val_loss)\n", + " \n", + " mean_val_loss = np.nanmean(val_loss)\n", + " \n", + " if epoch_ix and epoch_ix % eval_every == 0:\n", + " # evaluate(epoch_ix, model, test_loader, criterion)\n", + " tr_f1, val_f1, _ = evaluate_f1(model, train_loader, val_batches)\n", + " \n", + " if mean_val_loss < best_loss and save_at_best_loss:\n", + " best_loss = mean_val_loss\n", + " \n", + " # Reset delta.\n", + " delta = 0\n", + " \n", + " loss_str = str(best_loss).replace(\".\", \"_\")\n", + " torch.save(model.state_dict(), model_name.format(epoch=str(epoch_ix), loss=loss_str))\n", + " print(\"\\tSaved model checkpoint.\")\n", + " else:\n", + " # Increase delta by 1.\n", + " delta += 1\n", + " print(f\"\\tLoss did not decrease. Status is now {delta}/{patience}\")\n", + " \n", + " # Tolerate for `patience` epochs.\n", + " if delta == patience + 1:\n", + " # Stop training.\n", + " break\n", + "\n", + " if epoch_ix % decay_at == 0:\n", + " optimizer.param_groups[0]['lr'] *= decay\n", + " print(f\"\\tLearning rate is now: {optimizer.param_groups[0]['lr']:.5f}\")\n", + " \n", + " print(50*'-')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2bd1ffc7", + "metadata": {}, + "outputs": [], + "source": [ + "# Evaluate once on the test set.\n", + "evaluate(model, test_loader, criterion)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "396b615f", + "metadata": {}, + "outputs": [], + "source": [ + "final_tr_f1, final_val_f1, te_f1 = evaluate_f1(model, train_loader, val_batches, test_loader)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bcc396c", + "metadata": {}, + "outputs": [], + "source": [ + "# fig, ax = plt.subplots(figsize=(10, 6))\n", + "# ax.plot(tr_losses, 'r-')\n", + "# ax.plot(val_losses, 'b-')\n", + "# ax.set_title('Training and Validation losses')\n", + "# plt.legend(['Training loss', 'Validation loss'], loc='best')\n", + "# plt.tight_layout()\n", + "# plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a7d53498", + "metadata": {}, + "source": [ + "## Benchmarking\n", + "\n", + "\n", + "\n", + "epochs = 30\n", + "\n", + "```\n", + "LR scheme:\n", + "0 - 5 :: 0.00070\n", + "5 - 10 :: 0.00067\n", + "10 - 15 :: 0.00063\n", + "15 - 20 :: 0.00060\n", + "20 - 25 :: 0.00057\n", + "25 - 30 :: 0.00054\n", + "```\n", + "\n", + "```language=python\n", + "model = Model(\n", + " n_lstm_layers=1,\n", + " input_size=3,\n", + " hidden_size=16, \n", + " output_size=9,\n", + " n_features=40,\n", + " l1_blocks=6,\n", + " l2_blocks=6\n", + ")\n", + "```\n", + "\n", + "\\# params: ~450k\n", + "\n", + "mode_embedding = 4\n", + "\n", + "Best stats:\n", + "\t -> Train F1: 0.7047532574096045\n", + "\t -> Test F1: 0.6560129685481192\n", + "\n", + "
\n", + "\n", + "epochs = 40\n", + "\n", + "Same LR scheme as above.\n", + "\n", + "```language=python\n", + "model = Model(\n", + " n_lstm_layers=3,\n", + " input_size=3,\n", + " hidden_size=32, \n", + " output_size=9,\n", + " n_features=40,\n", + " l1_blocks=4,\n", + " l2_blocks=4\n", + ")\n", + "```\n", + "\n", + "\\# params: 770k\n", + "\n", + "mode_embedding = 4\n", + "\n", + "Best stats:\n", + "\t -> Train F1: 0.7365035440256072\n", + "\t -> Test F1: 0.6610215030981759\n", + " \n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46a8dc7d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pytorch", + "language": "python", + "name": "pytorch" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/replacement_mode_modeling/experimental_notebooks/README.md b/replacement_mode_modeling/experimental_notebooks/README.md new file mode 100644 index 00000000..13bb9e83 --- /dev/null +++ b/replacement_mode_modeling/experimental_notebooks/README.md @@ -0,0 +1,3 @@ +# All these scripts and notebooks are not verified to run, + +I am simply pushing these in this directory so that it might be of help for reference or to know what has already been tried. Please do not expect these notebooks to run seamlessly since a lot of them rely on intermediate pre-processed data. \ No newline at end of file diff --git a/replacement_mode_modeling/experimental_notebooks/baseline_modeling0.ipynb b/replacement_mode_modeling/experimental_notebooks/baseline_modeling0.ipynb new file mode 100644 index 00000000..54472292 --- /dev/null +++ b/replacement_mode_modeling/experimental_notebooks/baseline_modeling0.ipynb @@ -0,0 +1,1011 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Notebook used for extensive experimentation on trip-level models with AllCEO data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### All experiments are logged in Notion [here](https://www.notion.so/Replacement-mode-modeling-257c2f460377498d921e6b167f465945)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from pathlib import Path" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from enum import Enum\n", + "import random\n", + "\n", + "# Math and graphing.\n", + "import pandas as pd\n", + "import numpy as np\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# sklearn imports.\n", + "from sklearn.model_selection import train_test_split, StratifiedGroupKFold, GroupKFold\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.metrics import f1_score, r2_score, ConfusionMatrixDisplay\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Global experiment flags and variables.\n", + "SEED = 19348\n", + "TARGETS = ['p_micro', 'no_trip', 's_car', 'transit', 'car', 's_micro', 'ridehail', 'walk', 'unknown']\n", + "\n", + "DROP_S_MICRO = True\n", + "\n", + "# Set the Numpy seed too.\n", + "random.seed(SEED)\n", + "np.random.seed(SEED)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SPLIT_TYPE(Enum):\n", + " INTRA_USER = 0\n", + " INTER_USER = 1\n", + " TARGET = 2\n", + " MODE = 3\n", + " INTER_USER_STATIC = 4\n", + " \n", + "\n", + "class SPLIT(Enum):\n", + " TRAIN = 0\n", + " TEST = 1\n", + "\n", + "\n", + "def get_train_test_splits(data: pd.DataFrame, how=SPLIT_TYPE, test_ratio=0.2, shuffle=True):\n", + " \n", + " if how == SPLIT_TYPE.INTER_USER:\n", + "\n", + " X = data.drop(columns=['target'])\n", + " y = data['target'].values\n", + " groups = data.user_id.values\n", + " \n", + " splitter = StratifiedGroupKFold(n_splits=5, shuffle=shuffle, random_state=SEED)\n", + " # splitter = GroupKFold(n_splits=5)\n", + " \n", + " for train_index, test_index in splitter.split(X, y, groups):\n", + " X_tr = data.iloc[train_index, :]\n", + " X_te = data.iloc[test_index, :]\n", + " \n", + " # Iterate only once and break.\n", + " break\n", + "\n", + " return X_tr, X_te\n", + " \n", + " elif how == SPLIT_TYPE.INTRA_USER:\n", + " \n", + " # There are certain users with only one observation. What do we do with those?\n", + " # As per the mobilitynet modeling pipeline, we randomly assign them to either the\n", + " # training or test set.\n", + " \n", + " value_counts = data.user_id.value_counts()\n", + " single_count_ids = value_counts[value_counts == 1].index\n", + " \n", + " data_filtered = data.loc[~data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " data_single_counts = data.loc[data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data_filtered, test_size=test_ratio, shuffle=shuffle, stratify=data_filtered.user_id,\n", + " random_state=SEED\n", + " )\n", + " \n", + " data_single_counts['assigned'] = np.random.choice(['train', 'test'], len(data_single_counts))\n", + " X_tr_merged = pd.concat(\n", + " [X_tr, data_single_counts.loc[data_single_counts.assigned == 'train', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " X_te_merged = pd.concat(\n", + " [X_te, data_single_counts.loc[data_single_counts.assigned == 'test', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " return X_tr_merged, X_te_merged\n", + " \n", + " elif how == SPLIT_TYPE.TARGET:\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data, test_size=test_ratio, shuffle=shuffle, stratify=data.target,\n", + " random_state=SEED\n", + " )\n", + " \n", + " return X_tr, X_te\n", + " \n", + " elif how == SPLIT_TYPE.MODE:\n", + " X_tr, X_te = train_test_split(\n", + " data, test_size=test_ratio, shuffle=shuffle, stratify=data.section_mode_argmax,\n", + " random_state=SEED\n", + " )\n", + " \n", + " return X_tr, X_te\n", + " \n", + " elif how == SPLIT_TYPE.INTER_USER_STATIC:\n", + " \n", + " train_ids = ['810be63d084746e3b7da9d943dd88e8c', 'bf774cbe6c3040b0a022278d36a23f19', '8a8332a53a1b4cdd9f3680434e91a6ef', \n", + " '5ad862e79a6341f69f28c0096fe884da', '7f89656bd4a94d12ad8e5ad9f0afecaf', 'fbaa338d7cd7457c8cad4d0e60a44d18', \n", + " '3b25446778824941a4c70ae5774f4c68', '28cb1dde85514bbabfd42145bdaf7e0a', '3aeb5494088542fdaf798532951aebb0', \n", + " '531732fee3c24366a286d76eb534aebc', '950f4287bab5444aa0527cc23fb082b2', '737ef8494f26407b8b2a6b1b1dc631a4', \n", + " 'e06cf95717f448ecb81c440b1b2fe1ab', '7347df5e0ac94a109790b31ba2e8a02a', 'bd9cffc8dbf1402da479f9f148ec9e60', \n", + " '2f3b66a5f98546d4b7691fba57fa640f', 'f289f7001bd94db0b33a7d2e1cd28b19', '19a043d1f2414dbcafcca44ea2bd1f19', \n", + " '68788082836e4762b26ad0877643fdcf', '4e8b1b7f026c4384827f157225da13fa', '703a9cee8315441faff7eb63f2bfa93f', \n", + " 'add706b73839413da13344c355dde0bb', '47b5d57bd4354276bb6d2dcd1438901d', 'e4cfb2a8f600426897569985e234636e', \n", + " '0154d71439284c34b865e5a417cd48af', '234f4f2366244fe682dccded2fa7cc4e', '0d0ae3a556414d138c52a6040a203d24', \n", + " '44c10f66dec244d6b8644231d4a8fecb', '30e9b141d7894fbfaacecd2fa18929f9', '0eb313ab00e6469da78cc2d2e94660fb', \n", + " 'fc51d1258e4649ecbfb0e6ecdaeca454', 'a1954793b1454b2f8cf95917d7547169', '6656c04c6cba4c189fed805eaa529741', \n", + " '6a0f3653b80a4c949e127d6504debb55', 'dfe5ca1bb0854b67a6ffccad9565d669', '8b1f3ba43de945bea79de6a81716ad04', \n", + " 'cde34edb8e3a4278a18e0adb062999e5', '6d96909e5ca442ccb5679d9cdf3c8f5b', 'a60a64d82d1c439a901b683b73a74d73', \n", + " '60e6a6f6ed2e4e838f2bbed6a427028d', '88041eddad7542ea8c92b30e5c64e198', '1635c003b1f94a399ebebe21640ffced', \n", + " '1581993b404a4b9c9ca6b0e0b8212316', 'b1aed24c863949bfbfa3a844ecf60593', '4b89612d7f1f4b368635c2bc48bd7993', \n", + " 'eb2e2a5211564a9290fcb06032f9b4af', '26767f9f3da54e93b692f8be6acdac43', '8a98e383a2d143e798fc23869694934a', \n", + " 'b346b83b9f7c4536b809d5f92074fdae', 'd929e7f8b7624d76bdb0ec9ada6cc650', '863e9c6c8ec048c4b7653f73d839c85b', \n", + " 'f50537eb104e4213908f1862c8160a3e', '4a9db5a9bac046a59403b44b883cc0ba', 'cded005d5fd14c64a5bba3f5c4fe8385', \n", + " 'c7ce889c796f4e2a8859fa2d7d5068fe', '405b221abe9e43bc86a57ca7fccf2227', '0b3e78fa91d84aa6a3203440143c8c16', \n", + " 'fbff5e08b7f24a94ab4b2d7371999ef7', 'e35e65107a34496db49fa5a0b41a1e9e', 'd5137ebd4f034dc193d216128bb7fc9a', \n", + " '3f7f2e536ba9481e92f8379b796ad1d0', 'dc75e0b776214e1b9888f6abd042fd95', 'b41dd7d7c6d94fe6afe2fd26fa4ac0bd', \n", + " 'eec6936e1ac347ef9365881845ec74df', '8c7d261fe8284a42a777ffa6f380ba3b', '4baf8c8af7b7445e9067854065e3e612', \n", + " 'c6e4db31c18b4355b02a7dd97deca70b', 'f0db3b1999c2410ba5933103eca9212f', '487e20ab774742378198f94f5b5b0b43', \n", + " 'dc1ed4d71e3645d0993885398d5628ca', '8c3c63abb3ec4fc3a61e7bf316ee4efd', '15eb78dd6e104966ba6112589c29dc41', \n", + " 'c23768ccb817416eaf08be487b2e3643', 'ecd2ae17d5184807abd87a287115c299', '71f21d53b655463784f3a3c63c56707b', \n", + " '2931e0a34319495bbb5898201a54feb5', '92bde0d0662f45ac864629f486cffe77', '42b3ee0bc02a481ab1a94644a8cd7a0d', \n", + " '15aa4ba144a34b8b8079ed7e049d84df', '509b909390934e988eb120b58ed9bd8c', '14103cda12c94642974129989d39e50d', \n", + " '8b0876430c2641bcaea954ea00520e64', 'baa4ff1573ae411183e10aeb17c71c53', '14fe8002bbdc4f97acbd1a00de241bf6', \n", + " '1b7d6dfea8464bcab9321018b10ec9c9', '487ad897ba93404a8cbe5de7d1922691', '5182d93d69754d7ba06200cd1ac5980a', \n", + " '91f3ca1c278247f79a806e49e9cc236f', 'e66e63b206784a559d977d4cb5f1ec34', '840297ae39484e26bfebe83ee30c5b3e', \n", + " 'c6807997194c4c528a8fa8c1f6ee1595', '802667b6371f45b29c7abb051244836a', 'b2bbe715b6a14fd19f751cae8adf6b4e', \n", + " 'feb1d940cd3647d1a101580c2a3b3f8c', '1b9883393ab344a69bc1a0fab192a94c', 'ac604b44fdca482fb753034cb55d1351', \n", + " 'f446bf3102ff4bd99ea1c98f7d2f7af0', 'c2c5d4b9a607487ea405a99c721079d4', '85ddd3c34c58407392953c47a32f5428', \n", + " 'd51de709f95045f8bacf473574b96ba5', '6373dfb8cb9b47e88e8f76adcfadde20', '313d003df34b4bd9823b3474fc93f9f9', \n", + " '53e78583db87421f8decb529ba859ca4', '8fdc9b926a674a9ea07d91df2c5e06f2', '90480ac60a3d475a88fbdab0a003dd5d', \n", + " '7559c3f880f341e898a402eba96a855d', '19a4c2cf718d40588eb96ac25a566353', 'f4427cccaa9442b48b42bedab5ab648e', \n", + " 'e192b8a00b6c422296851c93785deaf7', '355e25bdfc244c5e85d358e39432bd44', 'a0c3a7b410b24e18995f63369a31d123', \n", + " '03a395b4d8614757bb8432b4984559b0', 'a2d48b05d5454d428c0841432c7467b6', '3d981e617b304afab0f21ce8aa6c9786', \n", + " '2cd5668ac9054e2eb2c88bb4ed94bc6d', 'd7a732f4a8644bcbb8dedfc8be242fb2', '367eb90b929d4f6e9470d15c700d2e3f', \n", + " 'e049a7b2a6cb44259f907abbb44c5abc', 'a231added8674bef95092b32bc254ac8', 'e88a8f520dde445484c0a9395e1a0599',\n", + " 'cba570ae38f341faa6257342727377b7', '97953af1b97d4e268c52e1e54dcf421a', 'd200a61757d84b1dab8fbac35ff52c28', \n", + " 'fc68a5bb0a7b4b6386b3f08a69ead36f', '4a8210aec25e443391efb924cc0e5f23', '903742c353ce42c3ad9ab039fc418816', \n", + " '2114e2a75304475fad06ad201948fbad', 'ac917eae407c4deb96625dd0dc2f2ba9', '3dddfb70e7cd40f18a63478654182e9a', \n", + " 'd3735ba212dd4c768e1675dca7bdcb6f', '7abe572148864412a33979592fa985fb', 'd3dff742d07942ca805c2f72e49e12c5' \n", + " ]\n", + " \n", + " X_tr = data.loc[data.user_id.isin(train_ids), :]\n", + " X_te = data.loc[~data.user_id.isin(train_ids), :]\n", + " \n", + " return X_tr, X_te\n", + " \n", + " raise NotImplementedError(\"Unknown split type\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modeling" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Read the data.\n", + "data = pd.read_csv('../data/ReplacedMode_Fix_02142024.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if DROP_S_MICRO:\n", + " data.drop(\n", + " index=data.loc[data.target == 6, :].index,\n", + " inplace=True\n", + " )\n", + " \n", + " # Shift all values after 6 by -1\n", + " data.loc[data.target > 5, 'target'] -= 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data.drop_duplicates(inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_hist(df, features=None):\n", + " if not features:\n", + " # All features.\n", + " features = df.columns.tolist()\n", + " \n", + " n_features = len(features)\n", + " \n", + " ncols = 6\n", + " nrows = n_features//ncols if n_features%ncols == 0 else (n_features//ncols) + 1\n", + " \n", + " fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=(10, 10))\n", + " for ix, ax in enumerate(axes.flatten()):\n", + " \n", + " if ix > n_features:\n", + " break\n", + " \n", + " df[features[ix]].hist(ax=ax)\n", + " ax.set(title=features[ix])\n", + " \n", + " plt.tight_layout()\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, we map the user IDs to ints.\n", + "\n", + "# USERS = list(data.user_id.unique())\n", + "\n", + "# USER_MAP = {\n", + "# u: i+1 for (i, u) in enumerate(USERS)\n", + "# }\n", + "\n", + "# data['user_id'] = data['user_id'].apply(lambda x: USER_MAP[x])\n", + "\n", + "# data.rename(\n", + "# columns={'start_local_dt_weekday': 'start:DOW', 'end_local_dt_weekday': 'end:DOW'},\n", + "# inplace=True\n", + "# )\n", + "\n", + "# Drop the samples with chosen == no trip or chosen == unknown\n", + "# data.drop(index=data.loc[data.chosen.isin([2, 9])].index, inplace=True)\n", + "\n", + "# data.n_working_residents = data.n_working_residents.apply(lambda x: 0 if x < 0 else x)\n", + "\n", + "# Fix some age preprocessing issues.\n", + "# data.age = data.age.apply(lambda x: x if x < 100 else 2024-x)\n", + "\n", + "# Collapse 'train' and 'bus' into 'transit'\n", + "# data.loc[\n", + "# data.section_mode_argmax.isin(['train', 'bus']), 'section_mode_argmax'\n", + "# ] = 'transit'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# display(data.section_mode_argmax.value_counts())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# transit = data.loc[data.section_mode_argmax == 'transit', :].copy()\n", + "# transit['section_duration_argmax'] /= 60.\n", + "\n", + "# transit['mph'] = transit['section_distance_argmax']/transit['section_duration_argmax']\n", + "\n", + "# display(transit[['section_duration_argmax', 'section_distance_argmax', 'mph']].describe())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# import plotly.express as px\n", + "\n", + "# sp = data.loc[data.section_mode_argmax.isin(['car', 'transit', 'walking']), :]\n", + "# fig = px.line(sp, y='section_distance_argmax', color='section_mode_argmax')\n", + "# fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Close the figure above.\n", + "# plt.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_duration_estimate(df: pd.DataFrame, dset: SPLIT, model_dict: dict):\n", + " \n", + " X_features = ['section_distance_argmax', 'age']\n", + " \n", + " if 'mph' in df.columns:\n", + " X_features += ['mph']\n", + " \n", + " if dset == SPLIT.TRAIN and model_dict is None:\n", + " model_dict = dict()\n", + " \n", + " if dset == SPLIT.TEST and model_dict is None:\n", + " raise AttributeError(\"Expected model dict for testing.\")\n", + " \n", + " if dset == SPLIT.TRAIN:\n", + " for section_mode in df.section_mode_argmax.unique():\n", + " section_data = df.loc[df.section_mode_argmax == section_mode, :]\n", + " if section_mode not in model_dict:\n", + " model_dict[section_mode] = dict()\n", + "\n", + " model = LinearRegression(fit_intercept=True)\n", + "\n", + " X = section_data[\n", + " X_features\n", + " ]\n", + " Y = section_data[['section_duration_argmax']]\n", + "\n", + " model.fit(X, Y.values.ravel())\n", + "\n", + " r2 = r2_score(y_pred=model.predict(X), y_true=Y.values.ravel())\n", + " print(f\"Train R2 for {section_mode}: {r2}\")\n", + "\n", + " model_dict[section_mode]['model'] = model\n", + " \n", + " elif dset == SPLIT.TEST:\n", + " for section_mode in df.section_mode_argmax.unique():\n", + " section_data = df.loc[df.section_mode_argmax == section_mode, :]\n", + " X = section_data[\n", + " X_features\n", + " ]\n", + " Y = section_data[['section_duration_argmax']]\n", + " \n", + " y_pred = model_dict[section_mode]['model'].predict(X)\n", + " r2 = r2_score(y_pred=y_pred, y_true=Y.values.ravel())\n", + " print(f\"Test R2 for {section_mode}: {r2}\")\n", + " \n", + " # Create the new columns for the duration.\n", + " new_columns = ['p_micro','no_trip','s_car','transit','car','s_micro','ridehail','walk','unknown']\n", + " df[new_columns] = 0\n", + " df['temp'] = 0\n", + " \n", + " for section in df.section_mode_argmax.unique():\n", + " X_section = df.loc[df.section_mode_argmax == section, X_features]\n", + " \n", + " # broadcast to all columns.\n", + " df.loc[df.section_mode_argmax == section, 'temp'] = model_dict[section]['model'].predict(X_section)\n", + " \n", + " for c in new_columns:\n", + " df[c] = df['av_' + c] * df['temp']\n", + " \n", + " df.drop(columns=['temp'], inplace=True)\n", + " \n", + " df.rename(columns=dict([(x, 'tt_'+x) for x in new_columns]), inplace=True)\n", + " \n", + " # return model_dict, result_df\n", + " return model_dict, df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now, we split the data.\n", + "train_data, test_data = get_train_test_splits(data=data, how=SPLIT_TYPE.INTER_USER)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# If split is inter-user, we should verify test size.\n", + "\n", + "n_tr, n_te = len(train_data.user_id.unique()), len(test_data.user_id.unique())\n", + "n_ex_tr, n_ex_te = train_data.shape[0], test_data.shape[0]\n", + "\n", + "print(n_tr/(n_tr+n_te))\n", + "print(n_ex_tr/(n_ex_tr+n_ex_te))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(train_data.columns.tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "params, train_data = get_duration_estimate(train_data, SPLIT.TRAIN, None)\n", + "print(10 * \"-\")\n", + "_, test_data = get_duration_estimate(test_data, SPLIT.TEST, params)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_data.shape, test_data.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Some helper functions that will help ease redundancy in the code.\n", + "\n", + "def drop_columns(df: pd.DataFrame):\n", + " to_drop = [\n", + " 'source', 'end_ts', 'end_fmt_time', 'end_loc', 'raw_trip', 'start_ts', \n", + " 'start_fmt_time', 'start_loc', 'duration', 'distance', 'start_place', \n", + " 'end_place', 'cleaned_trip', 'inferred_labels', 'inferred_trip', 'expectation',\n", + " 'confidence_threshold', 'expected_trip', 'user_input', 'start:year', 'start:month', \n", + " 'start:day', 'start_local_dt_minute', 'start_local_dt_second', \n", + " 'start_local_dt_weekday', 'start_local_dt_timezone', 'end:year', 'end:month', 'end:day', \n", + " 'end_local_dt_minute', 'end_local_dt_second', 'end_local_dt_weekday', \n", + " 'end_local_dt_timezone', '_id', 'user_id', 'metadata_write_ts', 'additions', \n", + " 'mode_confirm', 'purpose_confirm', 'Mode_confirm', 'Trip_purpose', \n", + " 'original_user_id', 'program', 'opcode', 'Timestamp', 'birth_year', \n", + " 'available_modes', 'section_coordinates_argmax', 'section_mode_argmax'\n", + " ]\n", + " \n", + " # Drop section_mode_argmax and available_modes.\n", + " return df.drop(\n", + " columns=to_drop, \n", + " inplace=False\n", + " )\n", + "\n", + "\n", + "def scale_values(df: pd.DataFrame, split: SPLIT, scalers=None):\n", + " # Scale costs using StandardScaler.\n", + " costs = df[[c for c in df.columns if 'cost_' in c]].copy()\n", + " times = df[[c for c in df.columns if 'tt_' in c or 'duration' in c]].copy()\n", + " distances = df[[c for c in df.columns if 'distance' in c]]\n", + " \n", + " print(\n", + " \"Cost columns to be scaled: \", costs.columns,\"\\nTime columns to be scaled: \", times.columns, \\\n", + " \"\\nDistance columns to be scaled: \", distances.columns\n", + " )\n", + " \n", + " if split == SPLIT.TRAIN and scalers is None:\n", + " cost_scaler = StandardScaler()\n", + " tt_scaler = StandardScaler()\n", + " dist_scaler = StandardScaler()\n", + " \n", + " cost_scaled = pd.DataFrame(\n", + " cost_scaler.fit_transform(costs), \n", + " columns=costs.columns, \n", + " index=costs.index\n", + " )\n", + " \n", + " tt_scaled = pd.DataFrame(\n", + " tt_scaler.fit_transform(times),\n", + " columns=times.columns,\n", + " index=times.index\n", + " )\n", + " \n", + " dist_scaled = pd.DataFrame(\n", + " dist_scaler.fit_transform(distances),\n", + " columns=distances.columns,\n", + " index=distances.index\n", + " )\n", + " \n", + " elif split == SPLIT.TEST and scalers is not None:\n", + " \n", + " cost_scaler, tt_scaler, dist_scaler = scalers\n", + " \n", + " cost_scaled = pd.DataFrame(\n", + " cost_scaler.transform(costs), \n", + " columns=costs.columns, \n", + " index=costs.index\n", + " )\n", + " \n", + " tt_scaled = pd.DataFrame(\n", + " tt_scaler.transform(times), \n", + " columns=times.columns, \n", + " index=times.index\n", + " )\n", + " \n", + " dist_scaled = pd.DataFrame(\n", + " dist_scaler.transform(distances),\n", + " columns=distances.columns,\n", + " index=distances.index\n", + " )\n", + " \n", + " else:\n", + " raise NotImplementedError(\"Unknown split\")\n", + " \n", + " # Drop the original columns.\n", + " df.drop(\n", + " columns=costs.columns.tolist() + times.columns.tolist() + distances.columns.tolist(), \n", + " inplace=True\n", + " )\n", + " \n", + " df = df.merge(right=cost_scaled, left_index=True, right_index=True)\n", + " df = df.merge(right=tt_scaled, left_index=True, right_index=True)\n", + " df = df.merge(right=dist_scaled, left_index=True, right_index=True)\n", + " \n", + " return df, (cost_scaler, tt_scaler, dist_scaler)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, drop columns.\n", + "\n", + "train_data = drop_columns(train_data)\n", + "\n", + "# Scale cost.\n", + "# train_data, scalers = scale_values(train_data, SPLIT.TRAIN, None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "test_data = drop_columns(test_data)\n", + "\n", + "# Scale cost.\n", + "# test_data, _ = scale_values(test_data, SPLIT.TEST, scalers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(train_data.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "len(train_data.target.unique())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# train_data.to_csv('../data/train.csv', index=False)\n", + "# test_data.to_csv('../data/test.csv', index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.metrics import classification_report\n", + "from sklearn.model_selection import GridSearchCV, StratifiedKFold\n", + "from pprint import pprint\n", + "from sklearn.inspection import permutation_importance\n", + "from time import perf_counter" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Random Forest classifier" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "CV = False\n", + "SAVE_MODEL = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.ensemble import RandomForestClassifier\n", + "\n", + "# exp question - compute sample weights using user_id.\n", + "\n", + "rf_train = train_data.drop(columns=['target', \n", + " 'start_lat', 'start_lng', 'end_lat', 'end_lng'\n", + " ])\n", + "rf_test = test_data.drop(columns=['target', \n", + " 'start_lat', 'start_lng', 'end_lat', 'end_lng'\n", + " ])\n", + "\n", + "if CV:\n", + "\n", + " model = RandomForestClassifier(random_state=SEED)\n", + "\n", + " # We want to build bootstrapped trees that would not always use all the features.\n", + "\n", + " param_set2 = {\n", + " 'n_estimators': [150, 200, 250, 300],\n", + " 'min_samples_split': [2, 3, 4],\n", + " 'min_samples_leaf': [1, 2, 3],\n", + " 'class_weight': ['balanced_subsample'],\n", + " 'max_features': [None, 'sqrt'],\n", + " 'bootstrap': [True]\n", + " }\n", + "\n", + " cv_set2 = StratifiedKFold(n_splits=3, shuffle=True, random_state=SEED)\n", + "\n", + " clf_set2 = GridSearchCV(model, param_set2, cv=cv_set2, n_jobs=-1, scoring='f1_weighted', verbose=1)\n", + "\n", + " start = perf_counter()\n", + "\n", + " clf_set2.fit(\n", + " rf_train,\n", + " train_data.target.values.ravel()\n", + " )\n", + "\n", + " time_req = (perf_counter() - start)/60.\n", + "\n", + " best_model = clf_set2.best_estimator_\n", + "else:\n", + " best_model = RandomForestClassifier(\n", + " n_estimators=150,\n", + " max_depth=None,\n", + " min_samples_leaf=2,\n", + " bootstrap=True,\n", + " class_weight='balanced_subsample',\n", + " random_state=SEED,\n", + " n_jobs=-1\n", + " ).fit(rf_train, train_data.target.values.ravel())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "best_model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tr_f1_set2 = f1_score(\n", + " y_true=train_data.target.values,\n", + " y_pred=best_model.predict(rf_train),\n", + " average='weighted'\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "te_f1_set2 = f1_score(\n", + " y_true=test_data.target.values,\n", + " y_pred=best_model.predict(rf_test),\n", + " average='weighted'\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Without location:\n", + "#. intra-user split:\n", + "# [BOOTSTRAPPED] | Train F1: 0.9983454261487021, Test F1: 0.7192048995905516\n", + "# if stratified by section_mode_argmax:\n", + "# [BOOTSTRAPPED] | Train F1: 0.9987250576328509, Test F1: 0.7242573620109232\n", + "\n", + "# With location:\n", + "# [BOOTSTRAPPED] | Train F1: 0.9992402006853468, Test F1: 0.7654135199070202\n", + "\n", + "print(f\"[BOOTSTRAPPED] | Train F1: {tr_f1_set2}, Test F1: {te_f1_set2}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if SAVE_MODEL:\n", + "\n", + " import pickle\n", + "\n", + " with open('../models/tuned_rf_model.pkl', 'wb') as f:\n", + " f.write(pickle.dumps(best_model))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Feature importances - gini entropy\n", + "\n", + "pprint(\n", + " sorted(\n", + " zip(\n", + " best_model.feature_names_in_, \n", + " best_model.feature_importances_\n", + " ), \n", + " key=lambda x: x[-1], reverse=True\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# importance = permutation_importance(\n", + "# best_model,\n", + "# rf_test,\n", + "# test_data.target.values,\n", + "# n_repeats=5,\n", + "# random_state=SEED,\n", + "# n_jobs=-1,\n", + "# scoring='f1_weighted'\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# pd.DataFrame(\n", + "# {\n", + "# 'feature names': test_data.columns.delete(\n", + "# test_data.columns.isin(['target'])\n", + "# ),\n", + "# 'imp_mean': importance.importances_mean, \n", + "# 'imp_std': importance.importances_std\n", + "# }\n", + "# ).sort_values(by=['imp_mean'], axis='rows', ascending=False).head(20)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# fig, ax = plt.subplots(nrows=1, ncols=2)\n", + "y_pred = best_model.predict(rf_test)\n", + "pred_df = pd.DataFrame(\n", + " {\n", + " 'y_pred': y_pred.ravel(),\n", + " 'y_true': test_data.target.values.ravel()\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(7, 7))\n", + "cm = ConfusionMatrixDisplay.from_estimator(\n", + " best_model,\n", + " X=rf_test,\n", + " y=test_data[['target']],\n", + " ax=ax\n", + ")\n", + "# ax.set_xticklabels(TARGETS, rotation=45)\n", + "# ax.set_yticklabels(TARGETS)\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# print(classification_report(y_true=pred_df.y_true, y_pred=pred_df.y_pred, target_names=TARGETS))\n", + "print(classification_report(y_true=pred_df.y_true, y_pred=pred_df.y_pred))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## XGBoost" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# from sklearn.utils.class_weight import compute_sample_weight\n", + "\n", + "# sample_weights = compute_sample_weight(class_weight='balanced', y=train_data.user_id.values.ravel())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# from xgboost import XGBClassifier\n", + "\n", + "# y_train = train_data.target.values.ravel() - 1\n", + "# y_test = test_data.target.values.ravel() - 1\n", + "\n", + "# # weights = compute_class_weight(class_weight='balanced', classes=np.unique(y_pred), y_pred)\n", + "\n", + "# xgm = XGBClassifier(\n", + "# n_estimators=300,\n", + "# max_depth=None,\n", + "# tree_method='hist',\n", + "# objective='multi:softmax',\n", + "# num_class=9\n", + "# ).fit(rf_train, y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# preds = xgm.predict(rf_test)\n", + "\n", + "# print(classification_report(y_true=y_test, y_pred=preds, target_names=TARGETS))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# import pickle\n", + "\n", + "# # RF_RM.pkl = 0.8625 on test.\n", + "# # RF_RM_1.pkl = 0.77 on test.\n", + "# with open('../models/RF_RM_1.pkl', 'wb') as f:\n", + "# f.write(pickle.dumps(model))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TODO:\n", + "\n", + "\n", + "- Explain why location might not be a good feature to add (plot start and end on map and explain how model might just overfit to the raw coordinates)\n", + "- Merge `unknown` and `no_trip` into one category and validate against models trained on (a) separate labels (b) dropped labels\n", + "- Explore more of the abnormal `walking` trips" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "ab0c6e94c9422d07d42069ec9e3bb23090f5e156fc0e23cc25ca45a62375bf53" + }, + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/replacement_mode_modeling/experimental_notebooks/biogeme_modeling train_test_w_splits.ipynb b/replacement_mode_modeling/experimental_notebooks/biogeme_modeling train_test_w_splits.ipynb new file mode 100644 index 00000000..5cc4f68a --- /dev/null +++ b/replacement_mode_modeling/experimental_notebooks/biogeme_modeling train_test_w_splits.ipynb @@ -0,0 +1,1107 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Biogeme modeling for inter-user modeling. Contains outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from enum import Enum\n", + "from sklearn.model_selection import train_test_split" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class SPLIT_TYPE(Enum):\n", + " INTRA_USER = 0\n", + " INTER_USER = 1\n", + " \n", + "\n", + "class SPLIT(Enum):\n", + " TRAIN = 0\n", + " TEST = 1\n", + "\n", + "\n", + "def get_splits(count_df: pd.DataFrame, n:int, test_size=0.2):\n", + " maxsize = int(n * test_size)\n", + "\n", + " max_threshold = int(maxsize * 1.05)\n", + " min_threshold = int(maxsize * 0.95)\n", + "\n", + " print(f\"{min_threshold=}, {max_threshold=}\")\n", + " \n", + " # Allow a 10% tolerance\n", + " def _dp(ix, curr_size, ids, cache):\n", + " \n", + " if ix >= count_df.shape[0]:\n", + " return []\n", + "\n", + " key = ix\n", + "\n", + " if key in cache:\n", + " return cache[key]\n", + "\n", + " if curr_size > max_threshold:\n", + " return []\n", + "\n", + " if min_threshold <= curr_size <= max_threshold:\n", + " return ids\n", + "\n", + " # two options - either pick the current id or skip it.\n", + " branch_a = _dp(ix, curr_size+count_df.loc[ix, 'count'], ids+[count_df.loc[ix, 'index']], cache)\n", + " branch_b = _dp(ix+1, curr_size, ids, cache)\n", + " \n", + " curr_max = []\n", + " if branch_a and len(branch_a) > 0:\n", + " curr_max = branch_a\n", + " \n", + " if branch_b and len(branch_b) > len(branch_a):\n", + " curr_max = branch_b\n", + " \n", + " cache[key] = curr_max\n", + " return cache[key]\n", + " \n", + " return _dp(0, 0, ids=list(), cache=dict())\n", + "\n", + "\n", + "def get_train_test_splits(data: pd.DataFrame, how=SPLIT_TYPE, test_ratio=0.2, shuffle=True):\n", + "\n", + " n_users = list(data.user_id.unique())\n", + " n = data.shape[0]\n", + " \n", + " if shuffle:\n", + " data = data.sample(data.shape[0]).reset_index(drop=True, inplace=False)\n", + "\n", + " if how == SPLIT_TYPE.INTER_USER:\n", + " # Make the split, ensuring that a user in one fold is not leaked into the other fold.\n", + " # Basic idea: we want to start with the users with the highest instances and place alternating users in each set.\n", + " counts = data.user_id.value_counts().reset_index(drop=False, inplace=False, name='count')\n", + "\n", + " # Now, start with the user_id at the top, and keep adding to either split.\n", + " # This can be achieved using a simple DP program.\n", + " test_ids = get_splits(counts, data.shape[0])\n", + " test_data = data.loc[data.user_id.isin(test_ids), :]\n", + " train_index = data.index.difference(test_data.index)\n", + " train_data = data.loc[data.user_id.isin(train_index), :]\n", + " \n", + " return train_data, test_data\n", + " \n", + " elif how == SPLIT_TYPE.INTRA_USER:\n", + " \n", + " # There are certain users with only one observation. What do we do with those?\n", + " # As per the mobilitynet modeling pipeline, we randomly assign them to either the\n", + " # training or test set.\n", + " \n", + " value_counts = data.user_id.value_counts()\n", + " single_count_ids = value_counts[value_counts == 1].index\n", + " \n", + " data_filtered = data.loc[~data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " data_single_counts = data.loc[data.user_id.isin(single_count_ids), :].reset_index(drop=True)\n", + " \n", + " X_tr, X_te = train_test_split(\n", + " data_filtered, test_size=test_ratio, shuffle=shuffle, stratify=data_filtered.user_id\n", + " )\n", + " \n", + " data_single_counts['assigned'] = np.random.choice(['train', 'test'], len(data_single_counts))\n", + " X_tr_merged = pd.concat(\n", + " [X_tr, data_single_counts.loc[data_single_counts.assigned == 'train', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " X_te_merged = pd.concat(\n", + " [X_te, data_single_counts.loc[data_single_counts.assigned == 'test', :].drop(\n", + " columns=['assigned'], inplace=False\n", + " )],\n", + " ignore_index=True, axis=0\n", + " )\n", + " \n", + " return X_tr_merged, X_te_merged\n", + " \n", + " raise NotImplementedError(\"Unknown split type\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modeling" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import biogeme.biogeme as bio\n", + "import biogeme.database as db\n", + "from biogeme import models\n", + "from biogeme.expressions import Beta, DefineVariable\n", + "from biogeme.expressions import Variable\n", + "import numpy as np\n", + "\n", + "from sklearn.preprocessing import MinMaxScaler" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "n_rows: 164281\n" + ] + } + ], + "source": [ + "# Read the data.\n", + "data = pd.read_csv('../data/preprocessed_data_split_chosen.csv')\n", + "\n", + "print(\"n_rows: \", data.shape[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# First, we map the user IDs to ints.\n", + "\n", + "USER_MAP = {\n", + " u: i+1 for (i, u) in enumerate(data.user_id.unique())\n", + "}\n", + "\n", + "data['user_id'] = data['user_id'].apply(lambda x: USER_MAP[x])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Now, we split the data (either inter-user or intra-user split)\n", + "\n", + "# 0.98???\n", + "# train_data, test_data = get_train_test_splits(data=data, how=SPLIT_TYPE.INTER_USER, shuffle=True)\n", + "\n", + "# 0.975???\n", + "train_data, test_data = get_train_test_splits(data=data, how=SPLIT_TYPE.INTRA_USER, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Some helper functions that will help ease redundancy in the code.\n", + "\n", + "def drop_columns(df: pd.DataFrame):\n", + " # Drop section_mode_argmax and available_modes.\n", + " return df.drop(columns=[\n", + " 'section_mode_argmax', 'available_modes', 'section_duration_argmax', 'section_distance_argmax'\n", + " ], inplace=False)\n", + "\n", + "\n", + "def scale_time(df: pd.DataFrame):\n", + " # Convert from min -> hrs\n", + " df[[c for c in df.columns if 'tt_' in c]] /= 60.\n", + " return df\n", + "\n", + "\n", + "def scale_cost(df: pd.DataFrame, split: SPLIT, scaler=None):\n", + " # Scale costs using MinMaxScaler.\n", + " costs = df[[c for c in df.columns if 'cost_' in c]].copy()\n", + " \n", + " if split == SPLIT.TRAIN and scaler is None:\n", + " scaler = MinMaxScaler()\n", + " cost_scaled = pd.DataFrame(\n", + " scaler.fit_transform(costs), \n", + " columns=['scaled_' + c for c in costs.columns], \n", + " index=costs.index\n", + " )\n", + " \n", + " elif split == SPLIT.TEST and scaler is not None:\n", + " cost_scaled = pd.DataFrame(\n", + " scaler.transform(costs), \n", + " columns=['scaled_' + c for c in costs.columns], \n", + " index=costs.index\n", + " )\n", + " \n", + " else:\n", + " raise NotImplementedError(\"Unknown split\")\n", + " \n", + " df = df.merge(right=cost_scaled, left_index=True, right_index=True)\n", + " \n", + " return df, scaler\n", + "\n", + "\n", + "def get_database(df: pd.DataFrame, split: SPLIT):\n", + " return db.Database(split.name + '_db', df)\n", + "\n", + "\n", + "def get_variables():\n", + " USER_ID = Variable('user_id')\n", + "\n", + " # Availability.\n", + " AV_P_MICRO = Variable('av_p_micro')\n", + " AV_NO_TRIP = Variable('av_no_trip')\n", + " AV_S_CAR = Variable('av_s_car')\n", + " AV_TRANSIT = Variable('av_transit')\n", + " AV_CAR = Variable('av_car')\n", + " AV_S_MICRO = Variable('av_s_micro')\n", + " AV_RIDEHAIL = Variable('av_ridehail')\n", + " AV_WALK = Variable('av_walk')\n", + " AV_UNKNOWN = Variable('av_unknown')\n", + "\n", + " # Time.\n", + " TT_P_MICRO = Variable('tt_p_micro')\n", + " TT_NO_TRIP = Variable('tt_no_trip')\n", + " TT_S_CAR = Variable('tt_s_car')\n", + " TT_TRANSIT = Variable('tt_transit')\n", + " TT_CAR = Variable('tt_car')\n", + " TT_S_MICRO = Variable('tt_s_micro')\n", + " TT_RIDEHAIL = Variable('tt_ridehail')\n", + " TT_WALK = Variable('tt_walk')\n", + " TT_UNKNOWN = Variable('tt_unknown')\n", + "\n", + " # Cost.\n", + " CO_P_MICRO = Variable('scaled_cost_p_micro')\n", + " CO_NO_TRIP = Variable('scaled_cost_no_trip')\n", + " CO_S_CAR = Variable('scaled_cost_s_car')\n", + " CO_TRANSIT = Variable('scaled_cost_transit')\n", + " CO_CAR = Variable('scaled_cost_car')\n", + " CO_S_MICRO = Variable('scaled_cost_s_micro')\n", + " CO_RIDEHAIL = Variable('scaled_cost_ridehail')\n", + " CO_WALK = Variable('scaled_cost_walk')\n", + " CO_UNKNOWN = Variable('scaled_cost_unknown')\n", + "\n", + " # Choice.\n", + " CHOICE = Variable('chosen')\n", + " \n", + " # return the filtered locals() dictionary.\n", + " return {k:v for k,v in locals().items() if not k.startswith('_')}\n", + "\n", + "\n", + "def exclude_from_db(v_dict: dict, db: db.Database):\n", + " EXCLUDE = (v_dict['CHOICE'] == 2) + (v_dict['CHOICE'] == 9) > 0\n", + " db.remove(EXCLUDE)\n", + "\n", + "\n", + "def get_params():\n", + " B_TIME = Beta('B_TIME', 0, None, 0, 0)\n", + " B_COST = Beta('B_COST', 0, None, None, 0)\n", + "\n", + " # Alternative-Specific Constants.\n", + " ASC_P_MICRO = Beta('ASC_P_MICRO', 0, None, None, 0)\n", + " ASC_NO_TRIP = Beta('ASC_NO_TRIP', 0, None, None, 0)\n", + " ASC_S_CAR = Beta('ASC_S_CAR', 0, None, None, 0)\n", + " ASC_TRANSIT = Beta('ASC_TRANSIT', 0, None, None, 0)\n", + " ASC_CAR = Beta('ASC_CAR', 0, None, None, 0)\n", + " ASC_S_MICRO = Beta('ASC_S_MICRO', 0, None, None, 0)\n", + " ASC_RIDEHAIL = Beta('ASC_RIDEHAIL', 0, None, None, 0)\n", + " ASC_WALK = Beta('ASC_WALK', 0, None, None, 0)\n", + " ASC_UNKNOWN = Beta('ASC_UNKNOWN', 0, None, None, 0)\n", + " \n", + " # Return filtered locals dict.\n", + " return {k:v for k,v in locals().items() if not k.startswith('_')}\n", + "\n", + "\n", + "def get_utility_functions(v: dict):\n", + " V_P_MICRO = (\n", + " v['ASC_P_MICRO'] +\n", + " v['B_TIME'] * v['TT_P_MICRO']\n", + " + v['B_COST'] * v['CO_P_MICRO']\n", + " )\n", + "\n", + " V_NO_TRIP = (\n", + " v['ASC_NO_TRIP'] +\n", + " v['B_TIME'] * v['TT_NO_TRIP'] +\n", + " v['B_COST'] * v['CO_NO_TRIP']\n", + " )\n", + "\n", + " V_S_CAR = (\n", + " v['ASC_S_CAR'] +\n", + " v['B_TIME'] * v['TT_S_CAR'] +\n", + " v['B_COST'] * v['CO_S_CAR']\n", + " )\n", + "\n", + " V_TRANSIT = (\n", + " v['ASC_TRANSIT'] +\n", + " v['B_TIME'] * v['TT_TRANSIT'] +\n", + " v['B_COST'] * v['CO_TRANSIT']\n", + " )\n", + "\n", + " V_CAR = (\n", + " v['ASC_CAR'] +\n", + " v['B_TIME'] * v['TT_CAR'] +\n", + " v['B_COST'] * v['CO_CAR']\n", + " )\n", + "\n", + " V_S_MICRO = (\n", + " v['ASC_S_MICRO'] +\n", + " v['B_TIME'] * v['TT_S_MICRO'] +\n", + " v['B_COST'] * v['CO_S_MICRO']\n", + " )\n", + "\n", + " V_RIDEHAIL = (\n", + " v['ASC_RIDEHAIL'] +\n", + " v['B_TIME'] * v['TT_RIDEHAIL'] +\n", + " v['B_COST'] * v['CO_RIDEHAIL']\n", + " )\n", + "\n", + " V_WALK = (\n", + " v['ASC_WALK'] +\n", + " v['B_TIME'] * v['TT_WALK']\n", + " + v['B_COST'] * v['CO_WALK']\n", + " )\n", + "\n", + " V_UNKNOWN = (\n", + " v['ASC_UNKNOWN'] +\n", + " v['B_TIME'] * v['TT_UNKNOWN'] +\n", + " v['B_COST'] * v['CO_UNKNOWN']\n", + " )\n", + " \n", + " # Remember to exclude the input argument.\n", + " return {k:v for k,v in locals().items() if not k.startswith('_') and k != 'v'}\n", + "\n", + "\n", + "def get_utility_mapping(var: dict):\n", + " # Map alterative to utility functions.\n", + " return {\n", + " 1: var['V_P_MICRO'], \n", + " 2: var['V_NO_TRIP'],\n", + " 3: var['V_S_CAR'], \n", + " 4: var['V_TRANSIT'],\n", + " 5: var['V_CAR'], \n", + " 6: var['V_S_MICRO'],\n", + " 7: var['V_RIDEHAIL'], \n", + " 8: var['V_WALK'], \n", + " 9: var['V_UNKNOWN']\n", + " }\n", + "\n", + "\n", + "def get_availability_mapping(var: dict):\n", + " return {\n", + " 1: var['AV_P_MICRO'],\n", + " 2: var['AV_NO_TRIP'],\n", + " 3: var['AV_S_CAR'],\n", + " 4: var['AV_TRANSIT'],\n", + " 5: var['AV_CAR'],\n", + " 6: var['AV_S_MICRO'],\n", + " 7: var['AV_RIDEHAIL'],\n", + " 8: var['AV_WALK'],\n", + " 9: var['AV_UNKNOWN']\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# First, drop columns.\n", + "\n", + "train_data = drop_columns(train_data)\n", + "\n", + "# Next, scale time.\n", + "train_data = scale_time(train_data)\n", + "\n", + "# Scale cost.\n", + "train_data, scaler = scale_cost(train_data, SPLIT.TRAIN, None)\n", + "\n", + "# get dbs.\n", + "train_db = get_database(train_data, SPLIT.TRAIN)\n", + "\n", + "# get vars.\n", + "train_vars = get_variables()\n", + "\n", + "# exclude wrong points.\n", + "exclude_from_db(train_vars, train_db)\n", + "\n", + "train_params = get_params()\n", + "train_vars.update(train_params)\n", + "\n", + "train_V = get_utility_functions(train_vars)\n", + "train_vars.update(train_V)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "V = get_utility_mapping(train_vars)\n", + "av = get_availability_mapping(train_vars)\n", + "train_logprob = models.loglogit(V, av, train_vars['CHOICE'])\n", + "\n", + "model = bio.BIOGEME(train_db, train_logprob)\n", + "model.modelName = 'splitChoiceModel'" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "train_results = model.estimate()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Results for model splitChoiceModel\n", + "Nbr of parameters:\t\t11\n", + "Sample size:\t\t\t129291\n", + "Excluded data:\t\t\t2133\n", + "Final log likelihood:\t\t-0.07647159\n", + "Akaike Information Criterion:\t22.15294\n", + "Bayesian Information Criterion:\t129.621\n", + "\n" + ] + } + ], + "source": [ + "print(train_results.short_summary())" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "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", + "
ValueRob. Std errRob. t-testRob. p-value
ASC_CAR88.7937272.832838e-023.134444e+030.0
ASC_NO_TRIP-623.2883331.797693e+308-3.467156e-3061.0
ASC_P_MICRO83.2864685.705798e-021.459681e+030.0
ASC_RIDEHAIL88.7602042.370587e-023.744230e+030.0
ASC_S_CAR88.8067072.278816e-023.897055e+030.0
ASC_S_MICRO85.1029973.619103e-022.351494e+030.0
ASC_TRANSIT85.5809325.083868e-021.683382e+030.0
ASC_UNKNOWN0.0000001.797693e+3080.000000e+001.0
ASC_WALK102.9572971.408207e-017.311235e+020.0
B_COST-2879.4061372.303798e+01-1.249852e+020.0
B_TIME-107.1993082.970404e-01-3.608913e+020.0
\n", + "
" + ], + "text/plain": [ + " Value Rob. Std err Rob. t-test Rob. p-value\n", + "ASC_CAR 88.793727 2.832838e-02 3.134444e+03 0.0\n", + "ASC_NO_TRIP -623.288333 1.797693e+308 -3.467156e-306 1.0\n", + "ASC_P_MICRO 83.286468 5.705798e-02 1.459681e+03 0.0\n", + "ASC_RIDEHAIL 88.760204 2.370587e-02 3.744230e+03 0.0\n", + "ASC_S_CAR 88.806707 2.278816e-02 3.897055e+03 0.0\n", + "ASC_S_MICRO 85.102997 3.619103e-02 2.351494e+03 0.0\n", + "ASC_TRANSIT 85.580932 5.083868e-02 1.683382e+03 0.0\n", + "ASC_UNKNOWN 0.000000 1.797693e+308 0.000000e+00 1.0\n", + "ASC_WALK 102.957297 1.408207e-01 7.311235e+02 0.0\n", + "B_COST -2879.406137 2.303798e+01 -1.249852e+02 0.0\n", + "B_TIME -107.199308 2.970404e-01 -3.608913e+02 0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(train_results.getEstimatedParameters())" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def get_utility_df(results, data):\n", + "\n", + " def compute_utilities(betas, row: pd.Series):\n", + " data = row.to_dict()\n", + "\n", + " utility_p_micro = betas['ASC_P_MICRO'] + (betas['B_TIME'] * data['tt_p_micro'])\n", + " utility_no_trip = betas['ASC_NO_TRIP'] + (betas['B_TIME'] * data['tt_no_trip']) + (betas['B_COST'] * data['scaled_cost_no_trip'])\n", + " utility_s_car = betas['ASC_S_CAR'] + (betas['B_COST'] * data['scaled_cost_s_car']) + (betas['B_TIME'] * data['tt_s_car'])\n", + " utility_transit = betas['ASC_TRANSIT'] + (betas['B_COST'] * data['scaled_cost_transit']) + (betas['B_TIME'] * data['tt_transit'])\n", + " utility_car = betas['ASC_CAR'] + (betas['B_COST'] * data['scaled_cost_car'] + (betas['B_TIME'] * data['tt_car']))\n", + " utility_s_micro = betas['ASC_S_MICRO'] + (betas['B_COST'] * data['scaled_cost_s_micro']) + (betas['B_TIME'] * data['tt_s_micro'])\n", + " utility_ridehail = betas['ASC_RIDEHAIL'] + (betas['B_COST'] * data['scaled_cost_ridehail']) + (betas['B_TIME'] * data['tt_ridehail'])\n", + " utility_walk = betas['ASC_WALK'] + (betas['B_TIME'] * data['tt_walk'])\n", + " utility_unknown = betas['ASC_UNKNOWN'] + (betas['B_TIME'] * data['tt_unknown']) + (betas['B_COST'] * data['scaled_cost_unknown'])\n", + "\n", + " return {\n", + " 'utility_p_micro': utility_p_micro, 'utility_no_trip': utility_no_trip,\n", + " 'utility_s_car': utility_s_car, 'utility_transit': utility_transit,\n", + " 'utility_car': utility_car, 'utility_s_micro': utility_s_micro,\n", + " 'utility_ridehail': utility_ridehail, 'utility_walk': utility_walk, \n", + " 'utility_unknown': utility_unknown, \n", + " }\n", + " \n", + " betas = results.getBetaValues()\n", + "\n", + " u_data = data.apply(lambda x: compute_utilities(betas, x), axis=1).tolist()\n", + " return pd.DataFrame(u_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "test_data = drop_columns(test_data)\n", + "\n", + "# Next, scale time.\n", + "test_data = scale_time(test_data)\n", + "\n", + "# Scale cost.\n", + "test_data, _ = scale_cost(test_data, SPLIT.TEST, scaler)\n", + "\n", + "# get dbs.\n", + "test_db = get_database(test_data, SPLIT.TEST)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "test_utilities = get_utility_df(train_results, test_data)" + ] + }, + { + "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", + "
utility_p_microutility_no_triputility_s_carutility_transitutility_carutility_s_microutility_ridehailutility_walkutility_unknown
067.411217-623.28833363.82887564.73419163.81589564.95953982.76410944.675225-21.398065
1-91.860937-623.288333-71.415959-97.629531-71.428939-188.098667-48.301289-669.366009-119.831550
258.227962-623.28833375.25369255.37268456.01799850.36880355.9844763.505302-27.073506
348.651631-623.28833347.89930445.61047047.88632335.15353067.326805-39.426846-32.991877
471.481893-623.28833367.28546168.88388267.27248171.42719886.11387862.924686-18.882302
\n", + "
" + ], + "text/plain": [ + " utility_p_micro utility_no_trip utility_s_car utility_transit \\\n", + "0 67.411217 -623.288333 63.828875 64.734191 \n", + "1 -91.860937 -623.288333 -71.415959 -97.629531 \n", + "2 58.227962 -623.288333 75.253692 55.372684 \n", + "3 48.651631 -623.288333 47.899304 45.610470 \n", + "4 71.481893 -623.288333 67.285461 68.883882 \n", + "\n", + " utility_car utility_s_micro utility_ridehail utility_walk \\\n", + "0 63.815895 64.959539 82.764109 44.675225 \n", + "1 -71.428939 -188.098667 -48.301289 -669.366009 \n", + "2 56.017998 50.368803 55.984476 3.505302 \n", + "3 47.886323 35.153530 67.326805 -39.426846 \n", + "4 67.272481 71.427198 86.113878 62.924686 \n", + "\n", + " utility_unknown \n", + "0 -21.398065 \n", + "1 -119.831550 \n", + "2 -27.073506 \n", + "3 -32.991877 \n", + "4 -18.882302 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(test_utilities.head())" + ] + }, + { + "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", + "
utility_p_microutility_no_triputility_s_carutility_transitutility_carutility_s_microutility_ridehailutility_walkutility_unknown
02.149431e-072.319104e-3075.977672e-091.478107e-085.900582e-091.851711e-089.999997e-012.872153e-175.793521e-46
11.208607e-191.933302e-2509.150116e-113.775868e-229.032113e-111.935398e-611.000000e+001.883732e-2708.606027e-32
24.034777e-084.236948e-3049.999999e-012.321603e-094.426337e-091.558225e-114.280415e-096.919424e-323.629633e-45
37.753087e-091.173968e-3003.653787e-093.704379e-103.606667e-091.064937e-141.000000e+004.339885e-472.704892e-44
44.419870e-078.138306e-3096.651541e-093.289330e-086.565760e-094.184619e-079.999991e-018.493006e-112.516158e-46
\n", + "
" + ], + "text/plain": [ + " utility_p_micro utility_no_trip utility_s_car utility_transit \\\n", + "0 2.149431e-07 2.319104e-307 5.977672e-09 1.478107e-08 \n", + "1 1.208607e-19 1.933302e-250 9.150116e-11 3.775868e-22 \n", + "2 4.034777e-08 4.236948e-304 9.999999e-01 2.321603e-09 \n", + "3 7.753087e-09 1.173968e-300 3.653787e-09 3.704379e-10 \n", + "4 4.419870e-07 8.138306e-309 6.651541e-09 3.289330e-08 \n", + "\n", + " utility_car utility_s_micro utility_ridehail utility_walk \\\n", + "0 5.900582e-09 1.851711e-08 9.999997e-01 2.872153e-17 \n", + "1 9.032113e-11 1.935398e-61 1.000000e+00 1.883732e-270 \n", + "2 4.426337e-09 1.558225e-11 4.280415e-09 6.919424e-32 \n", + "3 3.606667e-09 1.064937e-14 1.000000e+00 4.339885e-47 \n", + "4 6.565760e-09 4.184619e-07 9.999991e-01 8.493006e-11 \n", + "\n", + " utility_unknown \n", + "0 5.793521e-46 \n", + "1 8.606027e-32 \n", + "2 3.629633e-45 \n", + "3 2.704892e-44 \n", + "4 2.516158e-46 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "u_np = test_utilities.values\n", + "choice_df = np.exp(u_np)/np.sum(np.exp(u_np), axis=1, keepdims=True)\n", + "\n", + "choice_df = pd.DataFrame(choice_df, columns=test_utilities.columns)\n", + "display(choice_df.head())" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1 2 3 4 5 6 7 8 9]\n" + ] + } + ], + "source": [ + "from sklearn.metrics import f1_score\n", + "\n", + "y_pred = np.argmax(choice_df.values, axis=1) + 1\n", + "\n", + "print(np.unique(y_pred))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.9759923080654546\n" + ] + } + ], + "source": [ + "y_true = test_data.chosen\n", + "score = f1_score(y_true, y_pred, average='weighted')\n", + "\n", + "print(score)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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JyccPnwY77//PiZNmgQRAfD8Zrn27dtj8eLFfFgQEVERxPhARFS0ZfvhdxUqVMAvv/yC2NhY/P333xARuLu76z2tlIiIih7GByKioitHT9QGgFKlSqFRo0a5WRciInoNMD4QERU92bpRm4iIiIiI6EVMKoiIiIiISBUmFUREREREpAqTCiIiIiIiUoVJBRERERERqcKkgoiIiIiIVGFSQUREREREqjCpICIiIiIiVZhUEBERERGRKkwqiIiIiIhIFSYVRERERESkCpMKIiIiIiJShUkFERERERGpwqSCiIiIiIhUYVJBRERERESqMKkgIiIiIiJVmFQQEREREZEqTCqIiIiIiEgVJhVERERERKQKkwoiIiIiIlKFSQUREREREanCpIKIiIiIiFRhUkFERERERKowqSAiIiIiIlWMmlR8++23qF27NmxtbWFrawsvLy/8+uuvynoRQVBQEFxcXFC8eHG0bNkS58+f19tGUlISRo8eDQcHB1hbW8PPzw83btzQKxMbGwt/f39otVpotVr4+/vj4cOH+XGIRERERESvPaMmFeXKlcN//vMfnDhxAidOnEDr1q3RtWtXJXGYO3cu5s+fj0WLFuH48eNwdnaGj48PHj16pGwjMDAQoaGh2LRpEw4dOoTHjx/D19cXqampSpl+/fohIiICYWFhCAsLQ0REBPz9/fP9eImIKGvY6EREVLgYNano0qULOnXqhCpVqqBKlSqYOXMmSpQogfDwcIgIFi5ciMmTJ6N79+7w8PDA2rVrkZCQgA0bNgAA4uLisHLlSsybNw9t27ZFvXr1EBISgnPnzmHPnj0AgKioKISFhWHFihXw8vKCl5cXli9fjp9++gkXL1405uETEVEm2OhERFS4FJh7KlJTU7Fp0yY8efIEXl5euHz5MmJiYtCuXTuljIWFBVq0aIHDhw8DAE6ePIlnz57plXFxcYGHh4dS5siRI9BqtfD09FTKNGnSBFqtVimTkaSkJMTHx+u9iIgof7DRiYiocDF6UnHu3DmUKFECFhYWGD58OEJDQ1GjRg3ExMQAAJycnPTKOzk5KetiYmJgbm6OUqVKvbSMo6OjwX4dHR2VMhmZPXu20h2u1Wrh6uqq6jiJiChn2OhERFTwGT2pqFq1KiIiIhAeHo73338fAwYMwIULF5T1Go1Gr7yIGCx70YtlMir/qu1MmjQJcXFxyuv69etZPSQiIsoFbHQiIio8jJ5UmJub44033kDDhg0xe/Zs1KlTB1999RWcnZ0BwODCfufOHSWQODs7Izk5GbGxsS8tc/v2bYP93r171yAgpWdhYaHcIKh7ERFR/mGjExFR4WH0pOJFIoKkpCS4ubnB2dkZu3fvVtYlJyfjwIED8Pb2BgA0aNAAZmZmemWio6MRGRmplPHy8kJcXByOHTumlDl69Cji4uKUMkREVPCw0YmIqPAwalLxySef4ODBg7hy5QrOnTuHyZMn47fffsM777wDjUaDwMBAzJo1C6GhoYiMjMTAgQNhZWWFfv36AQC0Wi0GDx6McePGYe/evTh9+jT69++PWrVqoW3btgCA6tWro0OHDggICEB4eDjCw8MREBAAX19fVK1a1ZiHT0RE2cBGJyKigsvUmDu/ffs2/P39ER0dDa1Wi9q1ayMsLAw+Pj4AgAkTJiAxMREjRoxAbGwsPD09sWvXLtjY2CjbWLBgAUxNTdGrVy8kJiaiTZs2WLNmDUxMTJQy69evx5gxY5Qb9vz8/LBo0aL8PVgiIsqyTz75BB07doSrqysePXqETZs24bfffkNYWJheo5O7uzvc3d0xa9asTBud7O3tYWdnh/Hjx2fa6LR06VIAwNChQ9noRESUA0ZNKlauXPnS9RqNBkFBQQgKCsq0jKWlJYKDgxEcHJxpGTs7O4SEhOS0mkRElM/Y6EREVLgYNakgIiLKCBudiIgKlwJ3ozYRERERERUuTCqIiIiIiEgVJhVERERERKQKkwoiIiIiIlKFSQUREREREanCpIKIiIiIiFRhUkFERERERKowqSAiIiIiIlWYVBARERERkSpMKoiIiIiISBUmFUREREREpAqTCiIiIiIiUoVJBRERERERqcKkgoiIiIiIVGFSQUREREREqjCpICIiIiIiVZhUEBERERGRKkwqiIiIiIhIFSYVRERERESkCpMKIiIiIiJShUkFERERERGpwqSCiIiIiIhUYVJBRERERESqMKkgIiIiIiJVTI1dgdddS58OiL5976Vlyjg54LfdYflUIyIiIiKi3MWkIo9F376HeqOCX1rm9KLR+VQbIiIiIqLcx+FPRERERESkCpMKIiIiIiJShUkFERERERGpwqSCiIiIiIhU4Y3aREXMq2Yk42xkRERElF1MKoiKmFfNSMbZyIiIiCi7jDr8afbs2WjUqBFsbGzg6OiIbt264eLFi3plRARBQUFwcXFB8eLF0bJlS5w/f16vTFJSEkaPHg0HBwdYW1vDz88PN27c0CsTGxsLf39/aLVaaLVa+Pv74+HDh3l9iERERERErz2jJhUHDhzAyJEjER4ejt27dyMlJQXt2rXDkydPlDJz587F/PnzsWjRIhw/fhzOzs7w8fHBo0ePlDKBgYEIDQ3Fpk2bcOjQITx+/Bi+vr5ITU1VyvTr1w8REREICwtDWFgYIiIi4O/vn6/HS0REWcNGJyKiwsWoSUVYWBgGDhyImjVrok6dOli9ejWuXbuGkydPAngeMBYuXIjJkyeje/fu8PDwwNq1a5GQkIANGzYAAOLi4rBy5UrMmzcPbdu2Rb169RASEoJz585hz549AICoqCiEhYVhxYoV8PLygpeXF5YvX46ffvrJIEjpJCUlIT4+Xu9FRET5g41ORESFS4G6pyIuLg4AYGdnBwC4fPkyYmJi0K5dO6WMhYUFWrRogcOHD2PYsGE4efIknj17plfGxcUFHh4eOHz4MNq3b48jR45Aq9XC09NTKdOkSRNotVocPnwYVatWNajL7NmzMX369Lw6VCIieomwMP3JAlavXg1HR0ecPHkSb775pkGjEwCsXbsWTk5O2LBhA4YNG6Y0Oq1btw5t27YFAISEhMDV1RV79uxB+/btlUan8PBwJUYsX74cXl5euHjxYobxISkpCUlJScrfbHSi1wUn8iA1CkxSISIYO3YsmjVrBg8PDwBATEwMAMDJyUmvrJOTE65evaqUMTc3R6lSpQzK6N4fExMDR0dHg306OjoqZV40adIkjB07Vvk7Pj4erq6uOTw6IiJSg41ORHmPE3mQGgUmqRg1ahTOnj2LQ4cOGazTaDR6f4uIwbIXvVgmo/Iv246FhQUsLCyyUnUiIspDr3OjE1uGieh1USCSitGjR2P79u34/fffUa5cOWW5s7MzgOcX/TJlyijL79y5owQSZ2dnJCcnIzY2Vi9w3LlzB97e3kqZ27dvG+z37t27BgGJiIgKlte50Yktw0T0ujDqjdoiglGjRmHLli3Yt28f3Nzc9Na7ubnB2dkZu3fvVpYlJyfjwIEDSsLQoEEDmJmZ6ZWJjo5GZGSkUsbLywtxcXE4duyYUubo0aOIi4tTyhARUcGja3Tav39/po1O6WXW6PSyMmx0IiJSz6hJxciRIxESEoINGzbAxsYGMTExiImJQWJiIoDnrUeBgYGYNWsWQkNDERkZiYEDB8LKygr9+vUDAGi1WgwePBjjxo3D3r17cfr0afTv3x+1atVSbsyrXr06OnTogICAAISHhyM8PBwBAQHw9fXNcLwsEREZFxudiIgKF6MOf/r2228BAC1bttRbvnr1agwcOBAAMGHCBCQmJmLEiBGIjY2Fp6cndu3aBRsbG6X8ggULYGpqil69eiExMRFt2rTBmjVrYGJiopRZv349xowZo9yw5+fnh0WLFuXtARIRUY6MHDkSGzZswLZt25RGJ+B5Q1Lx4sX1Gp3c3d3h7u6OWbNmZdroZG9vDzs7O4wfPz7TRqelS5cCAIYOHcpGJyKibDJqUiEiryyj0WgQFBSEoKCgTMtYWloiODgYwcGZj0u1s7NDSEhITqpJRET5jI1ORESFS4G4UZuIiCg9NjoRERUuRr2ngoiIiIiICj8mFUREREREpAqTCiIiIiIiUoVJBRERERERqcKkgoiIiIiIVGFSQUREREREqjCpICIiIiIiVZhUEBERERGRKkwqiIiIiIhIFSYVRERERESkCpMKIiIiIiJShUkFERERERGpwqSCiIiIiIhUYVJBRERERESqMKkgIiIiIiJVmFQQEREREZEqTCqIiIiIiEgVJhVERERERKQKkwoiIiIiIlKFSQUREREREanCpIKIiIiIiFRhUkFERERERKowqSAiIiIiIlWYVBARERERkSpMKoiIiIiISBUmFUREREREpAqTCiIiIiIiUoVJBRERERERqcKkgoiIiIiIVGFSQUREREREqjCpICIiIiIiVZhUEBERERGRKkZNKn7//Xd06dIFLi4u0Gg02Lp1q956EUFQUBBcXFxQvHhxtGzZEufPn9crk5SUhNGjR8PBwQHW1tbw8/PDjRs39MrExsbC398fWq0WWq0W/v7+ePjwYR4fHRERqcEYQURUeBg1qXjy5Anq1KmDRYsWZbh+7ty5mD9/PhYtWoTjx4/D2dkZPj4+ePTokVImMDAQoaGh2LRpEw4dOoTHjx/D19cXqampSpl+/fohIiICYWFhCAsLQ0REBPz9/fP8+IiIKOcYI4iICg9TY+68Y8eO6NixY4brRAQLFy7E5MmT0b17dwDA2rVr4eTkhA0bNmDYsGGIi4vDypUrsW7dOrRt2xYAEBISAldXV+zZswft27dHVFQUwsLCEB4eDk9PTwDA8uXL4eXlhYsXL6Jq1aoZ7j8pKQlJSUnK3/Hx8bl56ERE9AoFOUYQEZG+AntPxeXLlxETE4N27dopyywsLNCiRQscPnwYAHDy5Ek8e/ZMr4yLiws8PDyUMkeOHIFWq1WCBQA0adIEWq1WKZOR2bNnK13hWq0Wrq6uuX2IRESUQ8aMEUlJSYiPj9d7EREVdQU2qYiJiQEAODk56S13cnJS1sXExMDc3BylSpV6aRlHR0eD7Ts6OiplMjJp0iTExcUpr+vXr6s6HiIiyj3GjBFsdCIiMlRgkwodjUaj97eIGCx70YtlMir/qu1YWFjA1tZW70VERAWLMWIEG52IiAwV2KTC2dkZAAxaiu7cuaO0TDk7OyM5ORmxsbEvLXP79m2D7d+9e9eghYuIiAoHY8YINjoRERkqsEmFm5sbnJ2dsXv3bmVZcnIyDhw4AG9vbwBAgwYNYGZmplcmOjoakZGRShkvLy/ExcXh2LFjSpmjR48iLi5OKUNERIULYwQRUcFi1NmfHj9+jL///lv5+/Lly4iIiICdnR3Kly+PwMBAzJo1C+7u7nB3d8esWbNgZWWFfv36AQC0Wi0GDx6McePGwd7eHnZ2dhg/fjxq1aqlzPRRvXp1dOjQAQEBAVi6dCkAYOjQofD19eWsHkREBRhjBBFR4WHUpOLEiRNo1aqV8vfYsWMBAAMGDMCaNWswYcIEJCYmYsSIEYiNjYWnpyd27doFGxsb5T0LFiyAqakpevXqhcTERLRp0wZr1qyBiYmJUmb9+vUYM2aMMgOIn59fpvOeExFRwcAYQURUeBg1qWjZsiVEJNP1Go0GQUFBCAoKyrSMpaUlgoODERwcnGkZOzs7hISEqKkqERHlM8YIIqLCo8DeU0FERERERIUDkwoiIiIiIlKFSQUREREREanCpIKIiIiIiFRhUkFERERERKowqSAiIiIiIlWYVBARERERkSpMKoiIiIiISBUmFUREREREpAqTCiIiIiIiUoVJBRERERERqcKkgoiIiIiIVGFSQUREREREqjCpICIiIiIiVUyNXQEiIiIiIvqflj4dEH37Xqbryzg54LfdYflYo1djUkFEREREVIBE376HeqOCM11/etHofKxN1nD4ExERERERqcKkgoiIiIiIVGFSQUREREREqjCpICIiIiIiVZhUEBERERGRKkwqiIiIiIhIFSYVRERERESkCpMKIiIiIiJShUkFERERERGpwqSCiIiIiIhUMTV2BYiIiqKWPh0QffveS8uUcXLAb7vD8qlGREREOcekgojICKJv30O9UcEvLXN60eh8qg0REZE6HP5ERERERESqMKkgIiIiIiJVmFQQEREREZEqTCqIiIiIiEgV3qhNRcarZtvhTDtEREUTZ2MjUq9IJRWLFy/GF198gejoaNSsWRMLFy5E8+bNjV0tyievmm2HM+0QFW2MEUUXZ2MjUq/IJBXff/89AgMDsXjxYjRt2hRLly5Fx44dceHCBZQvX97Y1ctTbKEnInq5ohwjiIhyQ5FJKubPn4/BgwdjyJAhAICFCxdi586d+PbbbzF79myD8klJSUhKSlL+jouLAwDEx8dna7+pqal4lvjklWWyu93suHHrNuoM/SLT9WeWfZSn+wde/Tnk9WfAOrAO2dl/Ya2DrqyIqKpbUZSdGJFb8QEw/m+hoDD25/C6XhNyuw5FIT68znXI8xghRUBSUpKYmJjIli1b9JaPGTNG3nzzzQzfM23aNAHAF1988VXoXtevX8+PS+trI7sxgvGBL774KsyvvIoRRaKn4t69e0hNTYWTk5PecicnJ8TExGT4nkmTJmHs2LHK32lpaXjw4AHs7e2h0WiytN/4+Hi4urri+vXrsLW1zfkBqMR6sB6sR9Goh4jg0aNHcHFxyePavV6yGyNyIz4AhftcYz1e/zqwHq9fPfI6RhSJpELnxYu9iGQaACwsLGBhYaG3rGTJkjnar62trVFPPtaD9WA9ik49tFptHtbm9ZbVGJGb8QEovOca61E06sB6vF71yMsYUSSeU+Hg4AATExODFqc7d+4YtEwREVHRwhhBRKRekUgqzM3N0aBBA+zevVtv+e7du+Ht7W2kWhERUUHAGEFEpF6RGf40duxY+Pv7o2HDhvDy8sKyZctw7do1DB8+PM/2aWFhgWnTphl0k+c31oP1YD1YD3o5xgjWoyDVoyDUgfVgPbJLI1J05h5cvHgx5s6di+joaHh4eGDBggV48803jV0tIiIqABgjiIhyrkglFURERERElPuKxD0VRERERESUd5hUEBERERGRKkwqiIiIiIhIFSYVRERERESkCpMKogKE8yZkDz8vIioqeL3LPn5m+YtJ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(8, 5))\n", + "\n", + "sns.histplot(y_pred, ax=ax[0])\n", + "sns.histplot(y_true, ax=ax[1])\n", + "\n", + "labels = [\n", + " 'p_micro', \n", + " 'no_trip',\n", + " 's_car', \n", + " 'transit',\n", + " 'car', \n", + " 's_micro',\n", + " 'ridehail', \n", + " 'walk', \n", + " 'unknown'\n", + "]\n", + "\n", + "ax[0].set(\n", + " title='predicted label distribution',\n", + " xlabel='Labels',\n", + " xticks=range(1, 10),\n", + " xticklabels=labels\n", + ")\n", + "\n", + "ax[1].set(\n", + " title='true label distribution',\n", + " xlabel='Labels',\n", + " xticks=range(1, 10),\n", + " xticklabels=labels\n", + ")\n", + "\n", + "ax[0].set_xticklabels(ax[0].get_xticklabels(), rotation=45)\n", + "ax[1].set_xticklabels(ax[0].get_xticklabels(), rotation=45)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "ab0c6e94c9422d07d42069ec9e3bb23090f5e156fc0e23cc25ca45a62375bf53" + }, + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/replacement_mode_modeling/experimental_notebooks/optimal_interuser_splits.ipynb b/replacement_mode_modeling/experimental_notebooks/optimal_interuser_splits.ipynb new file mode 100644 index 00000000..4782f9e5 --- /dev/null +++ b/replacement_mode_modeling/experimental_notebooks/optimal_interuser_splits.ipynb @@ -0,0 +1,617 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv('../data/filtered_data/preprocessed_data_openpath_prod_uprm_nicr.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1001, 52)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(df.section_mode_argmax.value_counts() < 2).any()" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import random\n", + "from scipy.special import kl_div\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/4x/l9lw50rn7qvf79m01f21x70mlpd6gh/T/ipykernel_85321/3793645385.py:1: DtypeWarning: Columns (38) have mixed types. Specify dtype option on import or set low_memory=False.\n", + " data = pd.read_csv('../data/ReplacedMode_Fix_02142024.csv')\n" + ] + } + ], + "source": [ + "data = pd.read_csv('../data/ReplacedMode_Fix_02142024.csv')\n", + "data.drop_duplicates(inplace=True)\n", + "\n", + "# data.sample(data.shape[0], random_state=SEED).reset_index(drop=True, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "ideal_tr, ideal_te = train_test_split(data, test_size=0.2, stratify=data.target, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ideal KL: 3.704099704742548e-08\n" + ] + } + ], + "source": [ + "print(f\"Ideal KL: {kl_div(ideal_tr.target.value_counts(normalize=True), ideal_te.target.value_counts(normalize=True)).mean()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0025" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2.5e-3" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def get_optimal_interuser_splits(data: pd.DataFrame, threshold=2.5e-3, maxiters=5000):\n", + " \n", + " ids = data.user_id.unique().tolist()\n", + "\n", + " best_kl = np.inf\n", + " ix = 0\n", + " best_train_ids = None\n", + "\n", + " try:\n", + " while True:\n", + "\n", + " if ix == maxiters:\n", + " break\n", + "\n", + " train_id, test_id = train_test_split(ids, test_size=0.2, shuffle=True)\n", + " train = data.loc[data.user_id.isin(train_id), :]\n", + " test = data.loc[data.user_id.isin(test_id), :]\n", + "\n", + " kl1 = kl_div(\n", + " train.section_mode_argmax.value_counts(normalize=True), \n", + " test.section_mode_argmax.value_counts(normalize=True)\n", + " ).mean()\n", + " \n", + " kl2 = kl_div(\n", + " train.target.value_counts(normalize=True), \n", + " test.target.value_counts(normalize=True)\n", + " ).mean()\n", + " \n", + " kl = kl1 + kl2 \n", + " \n", + " if kl < best_kl:\n", + " best_kl = kl\n", + " # No need to save test because test will be a complement of train.\n", + " best_train_ids = train_id\n", + " print(f'\\t\\t-> Best KL: {best_kl}')\n", + "\n", + " ix += 1\n", + "\n", + " if kl < threshold:\n", + " break\n", + "\n", + " except KeyboardInterrupt:\n", + " print(\"Stopped iterations. Best KL till now: \", best_kl)\n", + " \n", + " finally:\n", + " return best_train_ids" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t\t-> Best KL: 0.019654163171699848\n", + "\t\t-> Best KL: 0.00698817617574597\n", + "\t\t-> Best KL: 0.005533063761614154\n", + "\t\t-> Best KL: 0.003655132674484631\n", + "\t\t-> Best KL: 0.002547459671179468\n", + "\t\t-> Best KL: 0.0022263571393444375\n" + ] + } + ], + "source": [ + "best_train = get_optimal_interuser_splits(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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CCEPAAAAAGyEkGcTYWFhmj9/vsLCwqwuxS+wP7yxP7yxP7yxPxAo+F31xv7wxv74H/aFt2DcH0F94xUAAAAAsBuO5AEAAACAjRDyAAAAAMBGCHkAAAAAYCOEvDoyZMgQzZgx47TT27Vrp8WLF9dLLQ899JCSkpI8w+PHj9fIkSPrZd2ByOFwaMWKFVaXAZv75d9lffjl59LZPofO9jmG4EafC2z0OtQHep11gvph6FbKyspSkyZNLFn3008/LX+7386QIUOUlJRUb/9DcCaFhYVq0aKFJGnPnj1q3769Nm7cWO8fUoDV3njjDTVq1MjqMhCg6HOV0esA/2PXXkfIs8h5551n2bqjoqIsW3dtGWNUXl6uhg3r/le2devWdb4Of3bixAlbftih5qKjo60uAQGMPldz9Lr6QZ/Dz9m113G6Zh06efKkpk6dqubNm6tly5Z68MEHPd8s/vLQ8aFDh3THHXcoNjZW4eHh6t69u/773//q6NGjioyM1L///W+vZb/99ttq0qSJSkpKJElff/21brzxRkVHR6tJkybq06ePPv300yrr+uVpLEOGDNHdd9+tBx54QNHR0WrdurUeeughr/ds3bpVAwYMUHh4uBITE/Xee+/57FSP8ePHa+3atXr66aflcDjkcDi0bNkyORwOrVq1Sn369FFYWJjWr1+vXbt26eqrr1ZsbKyaNm2qlJQUvffee17La9eunR577DHdfvvtatasmRISEpSenu6Zfvz4cU2dOlVxcXEKDw9Xu3btlJaW5pn+8+1q3769JOniiy+Ww+HQkCFDznl760JFRYUef/xxdezYUWFhYUpISNCjjz4qSZo1a5Y6deqkiIgIdejQQXPnztWJEyc87z11KsWLL76oDh06KCwsrE6+AT/b71lBQYGuvvpqNW3aVJGRkbrhhht04MCBai1706ZNGjp0qJo1a6bIyEglJycrOzvbMz0zM1ODBg1S48aNFR8fr7vvvltHjx71TD/X35nDhw/rjjvuUKtWrRQZGanLLrtMmzZt8qrxD3/4g2JjY9WsWTNNmDBBP/7441m36+2331bz5s1VUVEhScrNzZXD4dD999/vmefOO+/UTTfdpIMHD+qmm27SBRdcoIiICPXo0UP//Oc/q7X/TnnppZcUFRWljIwMSVWf8nKm/ST9tK+TkpIUHh6uPn36aMWKFXI4HMrNza1RLQgM9Lnqo9edm0DocxK9jl6XW6Na6pRBnRg8eLBp2rSpmT59utm6dav5xz/+YSIiIkx6eroxxpi2bduap556yhhjTHl5ufnVr35lunXrZlavXm127dpl3n77bbNy5UpjjDGTJk0yw4cP91r+NddcY2699VZjjDElJSWmQ4cOZuDAgWb9+vVmx44dZvny5SYzM9MYY8z8+fNNr169PO8dN26cufrqq71qjYyMNA899JDZvn27+etf/2ocDodZvXq1p77OnTubK6+80uTm5pr169ebSy65xEgyb7755jnvq0OHDpm+ffuaSZMmmcLCQlNYWGjee+89I8n07NnTrF692uzcudMUFxeb3Nxc89xzz5nNmzeb7du3mzlz5pjw8HCzd+9ez/Latm1roqOjjcvlMjt27DBpaWmmQYMGJj8/3xhjzMKFC018fLxZt26d2bNnj1m/fr155ZVXPO//+XZ99tlnRpJ57733TGFhoTl48OA5b29deOCBB0yLFi3MsmXLzM6dO8369evNCy+8YIwx5pFHHjEbNmwwu3fvNm+99ZaJjY01jz/+uOe98+fPN02aNDFXXXWV+fzzz82mTZtMRUWFz2s80+9ZRUWFufjii82AAQNMdna2+eSTT0zv3r3N4MGDq7Xsbt26mTFjxpj8/Hyzfft289prr5nc3FxjjDGbN282TZs2NU899ZTZvn272bBhg7n44ovN+PHjPe8/l9+ZiooK079/fzNixAiTlZVltm/fbu69917TsmVLz+/L8uXLTWhoqHnhhRfM1q1bzZw5c0yzZs28/i6rcujQIdOgQQOTnZ1tjDFm8eLFJiYmxqSkpHjm6dSpk1m6dKn5+uuvzcKFC83GjRvNrl27zJ/+9CcTEhJiPvnkE6+fwfTp0722+9Tn0MKFC010dLT5+OOPzzj/mfaT2+020dHRZsyYMebLL780K1euNJ06dTKSzMaNG6vxk0Qgoc/VDL3u3ARCnzOGXkev21iNn2T9IOTVkcGDB5uuXbt6fYjMmjXLdO3a1Rjj/Qu3atUq06BBA7Nt27Yql/Xpp5+akJAQ88033xhjjPnuu+9Mo0aNzIcffmiMMeb55583zZo1O+2HcnWa34ABA7zek5KSYmbNmmWMMeadd94xDRs2NIWFhZ7pGRkZPm1+v/wD++CDD4wks2LFirO+NzEx0TzzzDOe4bZt25oxY8Z4hisqKkyrVq3M0qVLjTHGTJs2zVx22WWn/YD/+Xbt3r3b7/5of8ntdpuwsDBPszubP/7xjyY5OdkzPH/+fNOoUSNTVFRUVyUaY878e7Z69WoTEhJiCgoKPNO+/PJLI8l89tlnZ112s2bNzLJly6qcNnbsWHPHHXd4jVu/fr1p0KCBKS0tNcac2+/MmjVrTGRkpPnxxx+9xl944YXm+eefN8YY07dvXzN58mSv6ZdeeulZG58xxvTu3ds88cQTxhhjRo4caR599FETGhpq3G63KSwsNJI8jeeXhg8fbu69917P8Oka3+9+9zsTFxdnNm/e7PX+quY/035aunSpadmypWe/GmPMCy+84Pd/Q6gd+lzN0etqJ1D6nDH0OnrdxrNua33hdM069Ktf/UoOh8Mz3LdvX+3YsUPl5eVe8+Xm5uqCCy5Qp06dqlzOJZdcom7duulvf/ubJOnvf/+7EhISNGjQIM/7L7744nM6p7hnz55ew3FxcSoqKpIkbdu2TfHx8V7n719yySW1XldN9OnTx2v46NGjeuCBB5SYmKjmzZuradOm2rp1qwoKCrzm+/n2OBwOtW7d2rM948ePV25urjp37qy7775bq1evrvsNqUP5+fkqKyvT5ZdfXuX0f//73xowYIBat26tpk2bau7cuZX2V9u2bevl+pnT/Z7l5+crPj5e8fHxnmmnfsb5+flnXe7MmTM1ceJEXXHFFfrDH/6gXbt2eabl5ORo2bJlatq0qed11VVXqaKiQrt3766ytpr8zuTk5OjIkSNq2bKl1zp2797tqSM/P199+/b1qvmXw6czZMgQffjhhzLGaP369br66qvVvXt3ffTRR/rggw8UGxurLl26qLy8XI8++qh69uzpqWX16tWVfta/9OSTT+r555/XRx99pB49epy1njPtp23btqlnz54KDw/3zFNfnxWwBn3ON+h1ZxZIfU6i1/0cvc46hDw/0Lhx47POM3HiRL300kuSfjqX+LbbbvM01uq8/2x+eQGyw+HwnBttjPFq4vXpl3dmu//++/X666/r0Ucf1fr165Wbm6sePXro+PHjXvOdaXt69+6t3bt365FHHlFpaaluuOEGXXfddXW7IXXoTD//Tz75RDfeeKNSU1P13//+Vxs3btScOXMq7a/6ugPe6X4up/sdq+7v3kMPPaQvv/xSv/nNb/T+++8rMTFRb775pqSfruO48847lZub63lt2rRJO3bs0IUXXnjW2qQz/85UVFQoLi7Oa/m5ubnatm2b1/UEtTVkyBCtX79emzZtUoMGDZSYmKjBgwdr7dq1+vDDDzV48GBJPzWwp556Sg888IDef/995ebm6qqrrqr0s/6lgQMHqry8XK+99lq16qnpZ4Xxwzscov7R586MXndmgdTnJHpdbdDrfI+QV4c++eSTSsMXXXSRQkJCvMb37NlTX3/9tbZv337aZY0ZM0YFBQX605/+pC+//FLjxo3zen9ubq6+//57327A/9OlSxcVFBR4XRiclZXl03WEhoZW+ua3KuvXr9f48eN1zTXXqEePHmrdurX27NlT4/VFRkZq9OjReuGFF7R8+XK9/vrrVe6/0NBQSapWbVa56KKL1LhxY61Zs6bStA0bNqht27aaM2eO+vTpo4suukh79+61oMozS0xMVEFBgfbt2+cZl5eXp8OHD6tr167VWkanTp10zz33aPXq1Ro1apTnfxZ79+6tL7/8Uh07dqz0OvXzrY7T/c707t1b+/fvV8OGDSstPyYmRpLUtWvXKj8PqmPQoEEqKSnR4sWLNXjwYDkcDg0ePFgffvihV+M79c3nmDFj1KtXL3Xo0EE7duw46/IvueQSvfvuu3rssce0cOHCau+PqnTp0kWbN29WWVmZZ9zPbwoA+6HP1Qy9rnbs0Ocket2Z0Ot8j5BXh/bt26eZM2dq27Zt+uc//6lnnnlG06dPrzTf4MGDNWjQIF177bXKyMjQ7t279c477+jdd9/1zNOiRQuNGjVK999/v4YNG6YLLrjAM+2mm25S69atNXLkSG3YsEFfffWVXn/9dX388cc+2Y4rr7xSF154ocaNG6fNmzdrw4YNmjNnjiT57JvPdu3a6dNPP9WePXtUXFzs+bbklzp27Kg33njD8w3VzTfffNp5T+epp57Sq6++qq1bt2r79u3617/+pdatW6t58+aV5m3VqpUaN26sd999VwcOHNDhw4drs3l1Kjw8XLNmzdIDDzygv/3tb9q1a5c++eQT/eUvf1HHjh1VUFCgV199Vbt27dKf/vQnz7d+/uSKK65Qz549dcstt+jzzz/XZ599pltvvVWDBw+udBrTL5WWlmrq1Kn68MMPtXfvXm3YsEFZWVmehjlr1ix9/PHHcjqdys3N1Y4dO/TWW29p2rRp1a7vTL8zV1xxhfr27auRI0dq1apV2rNnjzIzM/Xggw96PvSnT5+uF198US+++KK2b9+u+fPn68svv6zWuqOiopSUlKR//OMfnjveDRo0SJ9//rm2b9/uGdexY0dlZGQoMzNT+fn5uvPOO7V///5qraNv37565513tGDBAj311FPV3i+/dOrv8Y477lB+fr5WrVqlJ554QpLvPivgX+hzNUOvqx079DmJXncm9DrfI+TVoVtvvVWlpaW65JJL5HQ6NW3aNN1xxx1Vzvv6668rJSVFN910kxITE/XAAw9U+kZtwoQJOn78uG6//Xav8aGhoVq9erVatWql4cOHq0ePHvrDH/5Q6ZvU2goJCdGKFSt05MgRpaSkaOLEiXrwwQclyet85HNx3333KSQkRImJiTrvvPNOe271U089pRYtWqhfv34aMWKErrrqKvXu3btG62ratKkef/xx9enTRykpKdqzZ49WrlypBg0q/zk0bNhQf/rTn/T888+rTZs2uvrqq2u1fXVt7ty5uvfeezVv3jx17dpVo0ePVlFRka6++mrdc889mjp1qpKSkpSZmam5c+daXW4lp27l3aJFCw0aNEhXXHGFOnTooOXLl5/1vSEhITp48KBuvfVWderUSTfccINSU1P18MMPS/rpCMDatWu1Y8cODRw4UBdffLHmzp2ruLi4atd3pt8Zh8OhlStXatCgQbr99tvVqVMn3XjjjdqzZ49iY2MlSaNHj9a8efM0a9YsJScna+/evbrrrruqvf6hQ4eqvLzc0+RatGjh+Vs51eDnzp2r3r1766qrrtKQIUM8/0NcXf3799f//d//ae7cufrTn/5U7ff9XGRkpN5++23l5uYqKSlJc+bM0bx58yT57rMC/oU+VzP0utoL9D4n0evOhl7nWw7jjyeRokovv/yypk+frm+//bZGh97rwoYNGzRgwADt3LnT61xvAPi5l19+WbfddpsOHz7sk+uqYG/0OQCByB97XUOrC8DZHTt2TLt371ZaWpruvPNOSxrfm2++qaZNm+qiiy7Szp07NX36dPXv35/GB8DL3/72N3Xo0EHnn3++Nm3apFmzZumGG27wm6YH/0SfAxBIAqHXcbpmAPjjH/+opKQkxcbGavbs2ZbUUFJSoilTpqhLly4aP368UlJS9J///MeSWhB8unXr5nXL5p+/Xn75ZavLw8/s379fY8aMUdeuXXXPPffo+uuvV3p6utVlwc/R5wB6XSAJhF7H6ZoA/N7evXt14sSJKqfFxsaqWbNm9VwRAAC+Ra+DLxHyAAAAAMBGOF0TAAAAAGyEkAcAAAAANkLIAwAAAAAbIeQBAAAAgI0Q8oBqcDgcWrFihdVl1Il27dpp8eLFVpcBALAYvQ6wD0Ie8DMPPfSQkpKSKo0vLCxUampq/RcEAICP0esA+2todQFAIGjdurXVJdjW8ePHFRoaanUZABD06HV1h16H+saRPASkf//73+rRo4caN26sli1b6oorrtDRo0clSS+99JK6du2q8PBwdenSRUuWLPF679dff60bb7xR0dHRatKkifr06aNPP/1Uy5Yt08MPP6xNmzbJ4XDI4XBo2bJlkiqfwrJlyxZddtllnvXfcccdOnLkiGf6+PHjNXLkSD3xxBOKi4tTy5Yt5XQ6T/uQ019q166dfv/73+vWW29V06ZN1bZtW/3nP//Rd999p6uvvlpNmzZVjx49lJ2d7fW+119/Xd26dVNYWJjatWunJ5980mt6UVGRRowYocaNG6t9+/Z6+eWXK6378OHDuuOOO9SqVStFRkbqsssu06ZNm6pV965du3T11VcrNjZWTZs2VUpKit57770qt238+PGKiorSpEmTJEkvvPCC4uPjFRERoWuuuUaLFi1S8+bNPe879c3ziy++qISEBDVt2lR33XWXysvL9cc//lGtW7dWq1at9Oijj3qtb9GiRerRo4eaNGmi+Ph4TZkyxetndfvtt6tnz54qKyuTJJ04cULJycm65ZZbqrXNAFBX6HX0Onodas0AAebbb781DRs2NIsWLTK7d+82mzdvNi6Xy5SUlJj09HQTFxdnXn/9dfPVV1+Z119/3URHR5tly5YZY4wpKSkxHTp0MAMHDjTr1683O3bsMMuXLzeZmZnm2LFj5t577zXdunUzhYWFprCw0Bw7dswYY4wk8+abbxpjjDl69Khp06aNGTVqlNmyZYtZs2aNad++vRk3bpynxnHjxpnIyEgzefJkk5+fb95++20TERFh0tPTq7WNbdu2NdHR0ea5554z27dvN3fddZdp1qyZ+fWvf21ee+01s23bNjNy5EjTtWtXU1FRYYwxJjs72zRo0MAsWLDAbNu2zbz00kumcePG5qWXXvIsNzU11XTv3t1kZmaa7Oxs069fP9O4cWPz1FNPGWOMqaioMP379zcjRowwWVlZZvv27ebee+81LVu2NAcPHjxr3bm5uea5554zmzdvNtu3bzdz5swx4eHhZu/evV7bFhkZaRYuXGh27NhhduzYYT766CPToEEDs3DhQrNt2zbjcrlMdHS0iYqK8rxv/vz5pmnTpua6664zX375pXnrrbdMaGioueqqq8y0adPM1q1bzYsvvmgkmY8//tjzvqeeesq8//775quvvjJr1qwxnTt3NnfddZdn+qnfiRkzZhhjjJk1a5ZJSEgwhw4dqtbPCgDqAr2OXkevw7kg5CHg5OTkGElmz549labFx8ebV155xWvcI488Yvr27WuMMeb55583zZo1O+2H+Pz5802vXr0qjf9540tPTzctWrQwR44c8Uz/v//7P9OgQQOzf/9+Y8xPja9t27bm5MmTnnmuv/56M3r06GptY9u2bc2YMWM8w4WFhUaSmTt3rmfcxx9/bCSZwsJCY4wxN998s7nyyiu9lnP//febxMREY4wx27ZtM5LMJ5984pmen59vJHka35o1a0xkZKT58ccfvZZz4YUXmueff75atf9SYmKieeaZZ7y2beTIkV7zjB492vzmN7/xGnfLLbdUanwRERHG7XZ7xl111VWmXbt2pry83DOuc+fOJi0t7bT1vPbaa6Zly5Ze4zIzM02jRo3M3LlzTcOGDc3atWtrtI0A4Gv0up/Q6+h1qB1O10TA6dWrly6//HL16NFD119/vV544QX98MMP+u6777Rv3z5NmDBBTZs29bx+//vfa9euXZKk3NxcXXzxxYqOjq71+vPz89WrVy81adLEM65///6qqKjQtm3bPOO6deumkJAQz3BcXJyKioqqvZ6ePXt6/h0bGytJ6tGjR6Vxp5aZn5+v/v37ey2jf//+2rFjh8rLy5Wfn6+GDRuqT58+nuldunTxOk0kJydHR44cUcuWLb324e7duz378EyOHj2qBx54QImJiWrevLmaNm2qrVu3qqCgwGu+n9cgSdu2bdMll1ziNe6Xw9JPp780a9bMax8kJiaqQYMGXuN+vp8/+OADXXnllTr//PPVrFkz3XrrrTp48KDnlCdJ6tu3r+677z498sgjuvfeezVo0KCzbisA1CV6nfc4eh29DjXDjVcQcEJCQpSRkaHMzEytXr1azzzzjObMmaO3335b0k/nu1966aWV3iNJjRs3Puf1G2PkcDiqnPbz8Y0aNao0raKiotrr+fn7Ty23qnGnlllVXcaYSv8+Xe2nlhUXF6cPP/yw0rSfN8jTuf/++7Vq1So98cQT6tixoxo3bqzrrrtOx48f95rv5//TUJ3aT6lqn55pP+/du1fDhw/X5MmT9cgjjyg6OlofffSRJkyY4HXNSEVFhTZs2KCQkBDt2LHjrNsJAHWNXuc9jl5Hr0PNcCQPAcnhcKh///56+OGHtXHjRoWGhmrDhg06//zz9dVXX6ljx45er/bt20v66RvD3Nxcff/991UuNzQ0VOXl5Wdcd2JionJzc72+HduwYYMaNGigTp06+W4jaygxMVEfffSR17jMzEx16tRJISEh6tq1q06ePOl1Afu2bdt06NAhz3Dv3r21f/9+NWzYsNI+jImJOWsN69ev1/jx43XNNdeoR48eat26tfbs2XPW93Xp0kWfffaZ17hfXmhfG9nZ2Tp58qSefPJJ/epXv1KnTp307bffVppv4cKFys/P19q1a7Vq1Sq99NJL57xuADhX9Lqq66LXeaPXoSqEPAScTz/9VI899piys7NVUFCgN954Q9999526du2qhx56SGlpaXr66ae1fft2bdmyRS+99JIWLVokSbrpppvUunVrjRw5Uhs2bNBXX32l119/XR9//LGkn06R2L17t3Jzc1VcXOy5C9XP3XLLLQoPD9e4ceP0xRdf6IMPPtC0adM0duxYz2klVrj33nu1Zs0aPfLII9q+fbv++te/6tlnn9V9990nSercubN+/etfa9KkSfr000+Vk5OjiRMnen3je8UVV6hv374aOXKkVq1apT179igzM1MPPvhgtRpRx44d9cYbbyg3N1ebNm3SzTffXK1vdKdNm6aVK1dq0aJF2rFjh55//nm98847Z/wmtjouvPBCnTx5Us8884y++uor/f3vf9dzzz3nNU9ubq7mzZunv/zlL+rfv7+efvppTZ8+XV999dU5rRsAzgW9rmr0usrodagKIQ8BJzIyUuvWrdPw4cPVqVMnPfjgg3ryySeVmpqqiRMn6s9//rOWLVumHj16aPDgwVq2bJnn283Q0FCtXr1arVq10vDhw9WjRw/94Q9/8Jzicu211+rXv/61hg4dqvPOO0///Oc/K60/IiJCq1at0vfff6+UlBRdd911uvzyy/Xs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/fRTr/maNGniNWyMkcPhqDTu5yoqKjRixAg9/vjjldYbFxfnoy0AAODM6HWAbxDyAD8VGhqq8vJyz/D69evVr18/TZkyxTNu165dZ11Oly5d9PLLL6usrExhYWGSpOzsbK95evfurddff13t2rVTw4ZVfyz8sh4AAM4VvQ6oG9xdE/BT7dq106effqo9e/aouLhYHTt2VHZ2tlatWqXt27dr7ty5ysrKOutybr75ZlVUVOiOO+5Qfn6+Vq1apSeeeEKSPN96Op1Off/997rpppv02Wef6auvvtLq1at1++23e5rdL+upqKiou40HAAQFeh1QNwh5gJ+67777FBISosTERJ133nn69a9/rVGjRmn06NG69NJLdfDgQa9vOk8nMjJSb7/9tnJzc5WUlKQ5c+Zo3rx5kuS5dqFNmzbasGGDysvLddVVV6l79+6aPn26oqKi1KBBgyrrKSgoqLuNBwAEBXodUDcc5pcnLAOwvZdfflm33XabDh8+rMaNG1tdDgAAPkevQzDjmjwgCPztb39Thw4ddP7552vTpk2e5wLR9AAAdkGvA/6HkAcEgf3792vevHnav3+/4uLidP311+vRRx+1uiwAAHyGXgf8D6drAgAAAICNcOMVAAAAALARQh4AAAAA2AghDwAAAABshJAHAAAAADZCyAMAAAAAGyHkAQAAAICNEPIAAAAAwEYIeQAAAABgI4Q8AAAAALCR/x+e6kOKIh5d4wAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "test_data = data.loc[data.user_id.isin(best_train), :]\n", + "train_data = data.loc[~data.user_id.isin(best_train), :]\n", + "\n", + "fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(9, 6))\n", + "sns.histplot(train_data.section_mode_argmax, ax=ax[0][0], discrete=True).set_yscale('log')\n", + "sns.histplot(test_data.section_mode_argmax, ax=ax[0][1], discrete=True).set_yscale('log')\n", + "sns.histplot(train_data.target, ax=ax[1][0], discrete=True).set_yscale('log')\n", + "sns.histplot(test_data.target, ax=ax[1][1], discrete=True).set_yscale('log')\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['7559c3f880f341e898a402eba96a855d', '1635c003b1f94a399ebebe21640ffced', '6656c04c6cba4c189fed805eaa529741', '4baf8c8af7b7445e9067854065e3e612', '42b3ee0bc02a481ab1a94644a8cd7a0d', 'f3a33641ffb6478f901350c55b6385f8', '14103cda12c94642974129989d39e50d', 'd7a732f4a8644bcbb8dedfc8be242fb2', '509b909390934e988eb120b58ed9bd8c', '3701bb586bf24d0caee8dd1d1421bb15', '802667b6371f45b29c7abb051244836a', 'd3dff742d07942ca805c2f72e49e12c5', 'feb6a3a8a2ef4f4a8754bd79f7154495', 'feb1d940cd3647d1a101580c2a3b3f8c', '90480ac60a3d475a88fbdab0a003dd5d', '3d981e617b304afab0f21ce8aa6c9786', 'c6e4db31c18b4355b02a7dd97deca70b', '8fdc9b926a674a9ea07d91df2c5e06f2', 'b41dd7d7c6d94fe6afe2fd26fa4ac0bd', 'e049a7b2a6cb44259f907abbb44c5abc', '3f7f2e536ba9481e92f8379b796ad1d0', '41c1182a404540a3820dff7de1c3d0e7', 'add706b73839413da13344c355dde0bb', 'fc51d1258e4649ecbfb0e6ecdaeca454', 'f446bf3102ff4bd99ea1c98f7d2f7af0', '840297ae39484e26bfebe83ee30c5b3e', 'dc1ed4d71e3645d0993885398d5628ca', 'ece8b0a509534e98a0d369f25de4a206', '43932257834649c29c5b9ccdc2416ebb', 'baa4ff1573ae411183e10aeb17c71c53', '53e78583db87421f8decb529ba859ca4', '8461560f8b4a4ca6af2cb569962dae32', 'feabfccddd6c4e8e85179d7177042483', '7abe572148864412a33979592fa985fb', 'b346b83b9f7c4536b809d5f92074fdae', '0eb313ab00e6469da78cc2d2e94660fb', '8d0bfee173d9428bae97f609e50d5570', 'eec6936e1ac347ef9365881845ec74df', '8b0876430c2641bcaea954ea00520e64', 'e4cfb2a8f600426897569985e234636e', '8c7d261fe8284a42a777ffa6f380ba3b', '234f4f2366244fe682dccded2fa7cc4e', 'cde34edb8e3a4278a18e0adb062999e5', 'a0c3a7b410b24e18995f63369a31d123', '8a8332a53a1b4cdd9f3680434e91a6ef', 'a1954793b1454b2f8cf95917d7547169', 'd3735ba212dd4c768e1675dca7bdcb6f', '4b89612d7f1f4b368635c2bc48bd7993', 'fc68a5bb0a7b4b6386b3f08a69ead36f', 'd68a36934a2649278fb6d084e1d992de', '313d003df34b4bd9823b3474fc93f9f9', '85ddd3c34c58407392953c47a32f5428', '8c3c63abb3ec4fc3a61e7bf316ee4efd', '92bde0d0662f45ac864629f486cffe77', '39db1e03b46c43129aa8dbe3bbe16687', '0b3e78fa91d84aa6a3203440143c8c16', '14fe8002bbdc4f97acbd1a00de241bf6', '1b7d6dfea8464bcab9321018b10ec9c9', '2455a5992b174239a1c926a7de96d623', 'f0db3b1999c2410ba5933103eca9212f', '93c6e0f156a44e07b920ded664419dc6', '5ad862e79a6341f69f28c0096fe884da', '703a9cee8315441faff7eb63f2bfa93f', '405b221abe9e43bc86a57ca7fccf2227', '3f067105255e4b0ca1bab377fee7ef16', '44c10f66dec244d6b8644231d4a8fecb', 'a231added8674bef95092b32bc254ac8', 'e66e63b206784a559d977d4cb5f1ec34', '9910245fee4e4ccaab4cdd2312eb0d5d', '3dddfb70e7cd40f18a63478654182e9a', '91f3ca1c278247f79a806e49e9cc236f', '6373dfb8cb9b47e88e8f76adcfadde20', '26767f9f3da54e93b692f8be6acdac43', '3b25446778824941a4c70ae5774f4c68', 'bd9cffc8dbf1402da479f9f148ec9e60', '6d96909e5ca442ccb5679d9cdf3c8f5b', '15eb78dd6e104966ba6112589c29dc41', '5a93c47d6bf34a77a2f8267ef6898943', 'e88a8f520dde445484c0a9395e1a0599', '487e20ab774742378198f94f5b5b0b43', 'c7ce889c796f4e2a8859fa2d7d5068fe', 'e35e65107a34496db49fa5a0b41a1e9e', '6a0f3653b80a4c949e127d6504debb55', 'd5137ebd4f034dc193d216128bb7fc9a', '2fc212b9508e4dc7b5a20bc79e2e9e31', 'b2bbe715b6a14fd19f751cae8adf6b4e', '8a98e383a2d143e798fc23869694934a', '2f3b66a5f98546d4b7691fba57fa640f', '0154d71439284c34b865e5a417cd48af', '88041eddad7542ea8c92b30e5c64e198', '0d0ae3a556414d138c52a6040a203d24', '903742c353ce42c3ad9ab039fc418816', '1b9883393ab344a69bc1a0fab192a94c', '2cd5668ac9054e2eb2c88bb4ed94bc6d', '97953af1b97d4e268c52e1e54dcf421a', 'c9a686318e1448cc81c715fd7e0a5811', 'e06cf95717f448ecb81c440b1b2fe1ab', 'a60a64d82d1c439a901b683b73a74d73', '60e6a6f6ed2e4e838f2bbed6a427028d', '112ab4cb44b84e73815378b997575362', 'e192b8a00b6c422296851c93785deaf7', 'bf774cbe6c3040b0a022278d36a23f19', '531732fee3c24366a286d76eb534aebc', 'd929e7f8b7624d76bdb0ec9ada6cc650', 'f50537eb104e4213908f1862c8160a3e', 'c11da556596342e79a2c62d3b116ea42', '47b5d57bd4354276bb6d2dcd1438901d', 'ac604b44fdca482fb753034cb55d1351', '742fbefae7d745a9bdf644659d21e0fa', 'fc8f71a38c82458dbf9718c3ee11a0f3', 'f2799dc202bc4249b42a4fda8770d1b6', '2931e0a34319495bbb5898201a54feb5', '00db212bc8d044cd839241ab4065e603', '810be63d084746e3b7da9d943dd88e8c', '737ef8494f26407b8b2a6b1b1dc631a4', 'cba570ae38f341faa6257342727377b7', '7381a74ba4f34f40b332ebace7ee9527', '102ff4f7be044cf2bdef164ae3a78262', '950f4287bab5444aa0527cc23fb082b2', 'fbff5e08b7f24a94ab4b2d7371999ef7', '487ad897ba93404a8cbe5de7d1922691', 'b1aed24c863949bfbfa3a844ecf60593', 'd200a61757d84b1dab8fbac35ff52c28', '355e25bdfc244c5e85d358e39432bd44', '19a4c2cf718d40588eb96ac25a566353', 'f289f7001bd94db0b33a7d2e1cd28b19', '4e8b1b7f026c4384827f157225da13fa', '3aeb5494088542fdaf798532951aebb0', 'dfe5ca1bb0854b67a6ffccad9565d669', '15aa4ba144a34b8b8079ed7e049d84df', '8a0473cae53d4720a99c0696cc1fb407', '30e9b141d7894fbfaacecd2fa18929f9']\n" + ] + } + ], + "source": [ + "print(best_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "counts = data.groupby('user_id').size()\n", + "filtered = counts[counts >= 5]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.ensemble import RandomForestClassifier\n", + "\n", + "params = {\n", + " 'ccp_alpha': 0.0031503743500287396,\n", + " 'max_depth': int(5.879792418246912 * 10), \n", + " 'max_features': 0.16332372250446126, \n", + " 'min_samples_leaf': int(1.7742589153489061 * 10), \n", + " 'min_samples_split': int(2.391021401374942 * 10), \n", + " 'n_estimators': int(100 * 0.5038646539940661)\n", + "}\n", + "\n", + "clf = RandomForestClassifier(**params)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['source',\n", + " 'end_ts',\n", + " 'end_fmt_time',\n", + " 'end_loc',\n", + " 'raw_trip',\n", + " 'start_ts',\n", + " 'start_fmt_time',\n", + " 'start_loc',\n", + " 'duration',\n", + " 'distance',\n", + " 'start_place',\n", + " 'end_place',\n", + " 'cleaned_trip',\n", + " 'inferred_labels',\n", + " 'inferred_trip',\n", + " 'expectation',\n", + " 'confidence_threshold',\n", + " 'expected_trip',\n", + " 'user_input',\n", + " 'start:year',\n", + " 'start:month',\n", + " 'start:day',\n", + " 'start:hour',\n", + " 'start_local_dt_minute',\n", + " 'start_local_dt_second',\n", + " 'start_local_dt_weekday',\n", + " 'start_local_dt_timezone',\n", + " 'end:year',\n", + " 'end:month',\n", + " 'end:day',\n", + " 'end:hour',\n", + " 'end_local_dt_minute',\n", + " 'end_local_dt_second',\n", + " 'end_local_dt_weekday',\n", + " 'end_local_dt_timezone',\n", + " '_id',\n", + " 'user_id',\n", + " 'metadata_write_ts',\n", + " 'additions',\n", + " 'mode_confirm',\n", + " 'purpose_confirm',\n", + " 'distance_miles',\n", + " 'Mode_confirm',\n", + " 'Trip_purpose',\n", + " 'original_user_id',\n", + " 'program',\n", + " 'opcode',\n", + " 'Timestamp',\n", + " 'birth_year',\n", + " 'primary_job_commute_time',\n", + " 'income_category',\n", + " 'n_residence_members',\n", + " 'n_residents_u18',\n", + " 'n_residents_with_license',\n", + " 'n_motor_vehicles',\n", + " 'available_modes',\n", + " 'age',\n", + " 'gender_Man',\n", + " 'gender_Man;Nonbinary/genderqueer/genderfluid',\n", + " 'gender_Nonbinary/genderqueer/genderfluid',\n", + " 'gender_Prefer not to say',\n", + " 'gender_Woman',\n", + " 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", + " 'has_drivers_license_No',\n", + " 'has_drivers_license_Prefer not to say',\n", + " 'has_drivers_license_Yes',\n", + " 'has_multiple_jobs_No',\n", + " 'has_multiple_jobs_Prefer not to say',\n", + " 'has_multiple_jobs_Yes',\n", + " \"highest_education_Bachelor's degree\",\n", + " 'highest_education_Graduate degree or professional degree',\n", + " 'highest_education_High school graduate or GED',\n", + " 'highest_education_Less than a high school graduate',\n", + " 'highest_education_Prefer not to say',\n", + " 'highest_education_Some college or associates degree',\n", + " 'primary_job_type_Full-time',\n", + " 'primary_job_type_Part-time',\n", + " 'primary_job_type_Prefer not to say',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Custodial',\n", + " 'primary_job_description_Education',\n", + " 'primary_job_description_Food service',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Medical/healthcare',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, managerial, or technical',\n", + " 'primary_job_description_Sales or service',\n", + " 'primary_job_commute_mode_Active transport',\n", + " 'primary_job_commute_mode_Car transport',\n", + " 'primary_job_commute_mode_Hybrid',\n", + " 'primary_job_commute_mode_Public transport',\n", + " 'primary_job_commute_mode_Unknown',\n", + " 'primary_job_commute_mode_WFH',\n", + " 'is_overnight_trip',\n", + " 'n_working_residents',\n", + " 'start_lat',\n", + " 'start_lng',\n", + " 'end_lat',\n", + " 'end_lng',\n", + " 'temperature_2m (°F)',\n", + " 'relative_humidity_2m (%)',\n", + " 'dew_point_2m (°F)',\n", + " 'rain (inch)',\n", + " 'snowfall (inch)',\n", + " 'wind_speed_10m (mp/h)',\n", + " 'wind_gusts_10m (mp/h)',\n", + " 'section_distance_argmax',\n", + " 'section_duration_argmax',\n", + " 'section_mode_argmax',\n", + " 'section_coordinates_argmax',\n", + " 'mph',\n", + " 'target',\n", + " 'av_s_micro',\n", + " 'av_ridehail',\n", + " 'av_unknown',\n", + " 'av_car',\n", + " 'av_transit',\n", + " 'av_walk',\n", + " 'av_s_car',\n", + " 'av_no_trip',\n", + " 'av_p_micro',\n", + " 'cost_p_micro',\n", + " 'cost_no_trip',\n", + " 'cost_s_car',\n", + " 'cost_transit',\n", + " 'cost_car',\n", + " 'cost_s_micro',\n", + " 'cost_ridehail',\n", + " 'cost_walk',\n", + " 'cost_unknown']" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data.drop(columns=[\n", + " 'source',\n", + " 'end_ts',\n", + " 'end_fmt_time',\n", + " 'end_loc',\n", + " 'raw_trip',\n", + " 'start_ts',\n", + " 'start_fmt_time',\n", + " 'start_loc',\n", + " 'duration',\n", + " 'distance',\n", + " 'start_place',\n", + " 'end_place',\n", + " 'cleaned_trip',\n", + " 'inferred_labels',\n", + " 'inferred_trip',\n", + " 'expectation',\n", + " 'confidence_threshold',\n", + " 'expected_trip',\n", + " 'user_input',\n", + " 'start:year',\n", + " 'start:month',\n", + " 'start:day',\n", + " 'start:hour',\n", + " 'start_local_dt_minute',\n", + " 'start_local_dt_second',\n", + " 'start_local_dt_weekday',\n", + " 'start_local_dt_timezone',\n", + " 'end:year',\n", + " 'end:month',\n", + " 'end:day',\n", + " 'end:hour',\n", + " 'end_local_dt_minute',\n", + " 'end_local_dt_second',\n", + " 'end_local_dt_weekday',\n", + " 'end_local_dt_timezone',\n", + " '_id',\n", + " 'user_id',\n", + " 'metadata_write_ts',\n", + " 'additions',\n", + " 'mode_confirm',\n", + " 'purpose_confirm',\n", + " 'distance_miles',\n", + " 'Mode_confirm',\n", + " 'Trip_purpose',\n", + " 'original_user_id',\n", + " 'program',\n", + " 'opcode',\n", + " 'Timestamp',\n", + " 'birth_year',\n", + " 'primary_job_commute_time',\n", + " 'income_category',\n", + " 'n_residence_members',\n", + " 'n_residents_u18',\n", + " 'n_residents_with_license',\n", + " 'n_motor_vehicles',\n", + " 'available_modes',\n", + " 'age',\n", + " 'gender_Man',\n", + " 'gender_Man;Nonbinary/genderqueer/genderfluid',\n", + " 'gender_Nonbinary/genderqueer/genderfluid',\n", + " 'gender_Prefer not to say',\n", + " 'gender_Woman',\n", + " 'gender_Woman;Nonbinary/genderqueer/genderfluid',\n", + " 'has_drivers_license_No',\n", + " 'has_drivers_license_Prefer not to say',\n", + " 'has_drivers_license_Yes',\n", + " 'has_multiple_jobs_No',\n", + " 'has_multiple_jobs_Prefer not to say',\n", + " 'has_multiple_jobs_Yes',\n", + " \"highest_education_Bachelor's degree\",\n", + " 'highest_education_Graduate degree or professional degree',\n", + " 'highest_education_High school graduate or GED',\n", + " 'highest_education_Less than a high school graduate',\n", + " 'highest_education_Prefer not to say',\n", + " 'highest_education_Some college or associates degree',\n", + " 'primary_job_type_Full-time',\n", + " 'primary_job_type_Part-time',\n", + " 'primary_job_type_Prefer not to say',\n", + " 'primary_job_description_Clerical or administrative support',\n", + " 'primary_job_description_Custodial',\n", + " 'primary_job_description_Education',\n", + " 'primary_job_description_Food service',\n", + " 'primary_job_description_Manufacturing, construction, maintenance, or farming',\n", + " 'primary_job_description_Medical/healthcare',\n", + " 'primary_job_description_Other',\n", + " 'primary_job_description_Professional, managerial, or technical',\n", + " 'primary_job_description_Sales or service',\n", + " 'primary_job_commute_mode_Active transport',\n", + " 'primary_job_commute_mode_Car transport',\n", + " 'primary_job_commute_mode_Hybrid',\n", + " 'primary_job_commute_mode_Public transport',\n", + " 'primary_job_commute_mode_Unknown',\n", + " 'primary_job_commute_mode_WFH',\n", + " 'is_overnight_trip',\n", + " 'n_working_residents',\n", + " 'start_lat',\n", + " 'start_lng',\n", + " 'end_lat',\n", + " 'end_lng',\n", + " 'temperature_2m (°F)',\n", + " 'relative_humidity_2m (%)',\n", + " 'dew_point_2m (°F)',\n", + " 'rain (inch)',\n", + " 'snowfall (inch)',\n", + " 'wind_speed_10m (mp/h)',\n", + " 'wind_gusts_10m (mp/h)',\n", + " 'section_distance_argmax',\n", + " 'section_duration_argmax',\n", + " 'section_mode_argmax',\n", + " 'section_coordinates_argmax',\n", + " 'mph',\n", + " 'target',\n", + " 'av_s_micro',\n", + " 'av_ridehail',\n", + " 'av_unknown',\n", + " 'av_car',\n", + " 'av_transit',\n", + " 'av_walk',\n", + " 'av_s_car',\n", + " 'av_no_trip',\n", + " 'av_p_micro',\n", + " 'cost_p_micro',\n", + " 'cost_no_trip',\n", + " 'cost_s_car',\n", + " 'cost_transit',\n", + " 'cost_car',\n", + " 'cost_s_micro',\n", + " 'cost_ridehail',\n", + " 'cost_walk',\n", + " 'cost_unknown'\n", + "])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import StratifiedGroupKFold\n", + "\n", + "cv = StratifiedGroupKFold(n_splits=2)\n", + "\n", + "for tr_ix, te_ix in cv.split(data)\n", + "\n", + "clf.fit()" + ] + } + ], + "metadata": { + "interpreter": { + "hash": "ab0c6e94c9422d07d42069ec9e3bb23090f5e156fc0e23cc25ca45a62375bf53" + }, + "kernelspec": { + "display_name": "emission", + "language": "python", + "name": "emission" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/replacement_mode_modeling/experimental_notebooks/rf_bayesian_optim.py b/replacement_mode_modeling/experimental_notebooks/rf_bayesian_optim.py new file mode 100644 index 00000000..6c911bdd --- /dev/null +++ b/replacement_mode_modeling/experimental_notebooks/rf_bayesian_optim.py @@ -0,0 +1,280 @@ +import warnings +warnings.simplefilter(action='ignore', category=Warning) + +import os +import numpy as np +import pandas as pd +import pickle +from bayes_opt import BayesianOptimization +from sklearn.linear_model import LinearRegression +from sklearn.ensemble import RandomForestClassifier +from sklearn.model_selection import StratifiedGroupKFold +from sklearn.metrics import f1_score, log_loss, r2_score + +SEED = 13210 + +class BayesianCV: + def __init__(self, data): + + init_splitter = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=SEED) + X = data.drop(columns=['target']) + groups = data.user_id.values + y = data.target.values + + for train_ix, test_ix in init_splitter.split(X, y, groups): + train = data.iloc[train_ix, :] + test = data.iloc[test_ix, :] + + break + + # Can't have split, so let it happen for two times. + # train, test = train_test_split(data, test_size=0.2, shuffle=True, stratify=data.target) + + print("Train-test split done.") + + # Estimate the test durations using the train data. + params, train = self._get_duration_estimate(train, 'train', None) + _, test = self._get_duration_estimate(test, 'test', params) + + # We drop the training duration estimates since we will be re-computing them during CV. + train.drop(columns=[c for c in train.columns if 'tt_' in c], inplace=True) + + # This is out final train and test data. + self.data = train.reset_index(drop=True) + self.test = test.reset_index(drop=True) + + self._optimizer = self._setup_optimizer() + + + def _drop_columns(self, df: pd.DataFrame): + to_drop = [ + 'source', 'end_ts', 'end_fmt_time', 'end_loc', 'raw_trip', 'start_ts', + 'start_fmt_time', 'start_loc', 'duration', 'distance', 'start_place', + 'end_place', 'cleaned_trip', 'inferred_labels', 'inferred_trip', 'expectation', + 'confidence_threshold', 'expected_trip', 'user_input', 'start:year', 'start:month', + 'start:day', 'start_local_dt_minute', 'start_local_dt_second', + 'start_local_dt_weekday', 'start_local_dt_timezone', 'end:year', 'end:month', 'end:day', + 'end_local_dt_minute', 'end_local_dt_second', 'end_local_dt_weekday', + 'end_local_dt_timezone', '_id', 'user_id', 'metadata_write_ts', 'additions', + 'mode_confirm', 'purpose_confirm', 'Mode_confirm', 'Trip_purpose', + 'original_user_id', 'program', 'opcode', 'Timestamp', 'birth_year', + 'available_modes', 'section_coordinates_argmax', 'section_mode_argmax', + 'start_lat', 'start_lng', 'end_lat', 'end_lng' + ] + + # Drop section_mode_argmax and available_modes. + return df.drop( + columns=to_drop, + inplace=False + ) + + + def _get_duration_estimate(self, df: pd.DataFrame, dset: str, model_dict: dict): + + X_features = ['section_distance_argmax', 'age'] + + if 'mph' in df.columns: + X_features += ['mph'] + + if dset == 'train' and model_dict is None: + model_dict = dict() + + if dset == 'test' and model_dict is None: + raise AttributeError("Expected model dict for testing.") + + if dset == 'train': + for section_mode in df.section_mode_argmax.unique(): + section_data = df.loc[df.section_mode_argmax == section_mode, :] + if section_mode not in model_dict: + model_dict[section_mode] = dict() + + model = LinearRegression(fit_intercept=True) + + X = section_data[ + X_features + ] + Y = section_data[['section_duration_argmax']] + + model.fit(X, Y.values.ravel()) + + r2 = r2_score(y_pred=model.predict(X), y_true=Y.values.ravel()) + # print(f"Train R2 for {section_mode}: {r2}") + + model_dict[section_mode]['model'] = model + + elif dset == 'test': + for section_mode in df.section_mode_argmax.unique(): + section_data = df.loc[df.section_mode_argmax == section_mode, :] + X = section_data[ + X_features + ] + Y = section_data[['section_duration_argmax']] + + y_pred = model_dict[section_mode]['model'].predict(X) + r2 = r2_score(y_pred=y_pred, y_true=Y.values.ravel()) + # print(f"Test R2 for {section_mode}: {r2}") + + # Create the new columns for the duration. + new_columns = ['p_micro','no_trip','s_car','transit','car','s_micro','ridehail','walk','unknown'] + df[new_columns] = 0 + df['temp'] = 0 + + for section in df.section_mode_argmax.unique(): + X_section = df.loc[df.section_mode_argmax == section, X_features] + + # broadcast to all columns. + df.loc[df.section_mode_argmax == section, 'temp'] = model_dict[section]['model'].predict(X_section) + + for c in new_columns: + df[c] = df['av_' + c] * df['temp'] + + df.drop(columns=['temp'], inplace=True) + + df.rename(columns=dict([(x, 'tt_'+x) for x in new_columns]), inplace=True) + + # return model_dict, result_df + return model_dict, df + + + def _setup_optimizer(self): + # Define search space. + hparam_dict = { + # 10-500 + 'n_estimators': (0.25, 3), + # 5-150 + 'max_depth': (0.5, 15), + # 2-20 + 'min_samples_split': (0.2, 2.5), + # 1-20 + 'min_samples_leaf': (0.1, 2.5), + # as-is. + 'ccp_alpha': (0., 0.5), + # as-is. + 'max_features': (0.1, 0.99), + # Use clip to establish mask. + 'class_weight': (0, 1), + } + + return BayesianOptimization( + self._surrogate, + hparam_dict + ) + + + def _surrogate(self, n_estimators, max_depth, min_samples_split, min_samples_leaf, ccp_alpha, max_features, class_weight): + + cw = 'balanced_subsample' if class_weight < 0.5 else 'balanced' + + # Builds a surrogate model using the samples hparams. + model = RandomForestClassifier( + n_estimators=int(n_estimators * 100), + max_depth=int(max_depth * 10), + min_samples_split=int(min_samples_split * 10), + min_samples_leaf=int(min_samples_leaf * 10), + max_features=max(min(max_features, 0.999), 1e-3), + ccp_alpha=ccp_alpha, + bootstrap=True, + class_weight=cw, + n_jobs=os.cpu_count(), + random_state=SEED + ) + + fold_crossentropy = list() + + # Use the train split and further split in train-val. + X = self.data.drop(columns=['target']) + y = self.data.target.values.ravel() + users = X.user_id.values + + gkfold = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=SEED) + + for train_ix, test_ix in gkfold.split(X, y, users): + + X_train = X.iloc[train_ix, :] + X_test = X.iloc[test_ix, :] + + y_train = y[train_ix] + y_test = y[test_ix] + + # Re-estimate durations. + params, X_train = self._get_duration_estimate(X_train, 'train', None) + _, X_test = self._get_duration_estimate(X_test, 'test', params) + + X_train = self._drop_columns(X_train) + X_test = self._drop_columns(X_test) + + model.fit( + X_train, + y_train + ) + + # Measure performance on valid split. + ce = log_loss( + y_true=y_test, + y_pred=model.predict_proba(X_test), + labels=list(range(1, 10)) + ) + + fold_crossentropy.append(ce) + + # Return the average negative crossentropy (since bayesian optimization aims to maximize an objective). + return -np.mean(fold_crossentropy) + + + def optimize(self): + self._optimizer.maximize(n_iter=100, init_points=10) + print("Done optimizing!") + best_params = self._optimizer.max['params'] + best_loss = -self._optimizer.max['target'] + return best_loss, best_params + + +def train_final_model(params, cv_obj): + # Construct the model using the params. + model = RandomForestClassifier( + n_estimators=int(params['n_estimators'] * 100), + max_depth=int(params['max_depth'] * 10), + min_samples_split=int(params['min_samples_split'] * 10), + min_samples_leaf=int(params['min_samples_leaf'] * 10), + max_features=params['max_features'], + ccp_alpha=params['ccp_alpha'], + bootstrap=True, + class_weight='balanced_subsample', + n_jobs=os.cpu_count() + ) + + + X_tr = cv_obj.data.drop(columns=['target']) + y_tr = cv_obj.data.target.values.ravel() + + X_te = cv_obj.test.drop(columns=['target']) + y_te = cv_obj.test.target.values.ravel() + + params, X_tr = cv_obj._get_duration_estimate(X_tr, 'train', None) + + X_tr = cv_obj._drop_columns(X_tr) + X_te = cv_obj._drop_columns(X_te) + + model.fit( + X_tr, + y_tr + ) + + model.fit(X_tr, y_tr) + + print(f"Train loss: {log_loss(y_true=y_tr, y_pred=model.predict_proba(X_tr))}") + print(f"Train performance: {f1_score(y_true=y_tr, y_pred=model.predict(X_tr), average='weighted')}") + print(f"Test loss: {log_loss(y_true=y_te, y_pred=model.predict_proba(X_te))}") + print(f"Test performance: {f1_score(y_true=y_te, y_pred=model.predict(X_te), average='weighted')}") + + with open('./bayes_rf.pkl', 'wb') as f: + f.write(pickle.dumps(model)) + + +if __name__ == "__main__": + data = pd.read_csv('../data/ReplacedMode_Fix_02142024.csv') + bayes_cv = BayesianCV(data) + best_loss, best_params = bayes_cv.optimize() + print(f"Best loss: {best_loss}, best params: {str(best_params)}") + train_final_model(best_params, bayes_cv) + \ No newline at end of file