示例#1
0
def location_choice_model(
    name="workplace_location",
    edb_directory="output/estimation_data_bundle/{name}/",
    coefficients_file="{name}_coefficients.csv",
    spec_file="{name}_SPEC.csv",
    size_spec_file="{name}_size_terms.csv",
    alt_values_file="{name}_alternatives_combined.csv",
    chooser_file="{name}_choosers_combined.csv",
    settings_file="{name}_model_settings.yaml",
    landuse_file="{name}_landuse.csv",
    return_data=False,
):
    model_selector = name.replace("_location", "")
    model_selector = model_selector.replace("_destination", "")
    model_selector = model_selector.replace("_subtour", "")
    model_selector = model_selector.replace("_tour", "")
    if model_selector == 'joint':
        model_selector = 'non_mandatory'
    edb_directory = edb_directory.format(name=name)

    def _read_csv(filename, **kwargs):
        filename = filename.format(name=name)
        return pd.read_csv(os.path.join(edb_directory, filename), **kwargs)

    coefficients = _read_csv(
        coefficients_file,
        index_col="coefficient_name",
    )
    spec = _read_csv(spec_file, comment="#")
    alt_values = _read_csv(alt_values_file)
    chooser_data = _read_csv(chooser_file)
    landuse = _read_csv(landuse_file, index_col="zone_id")
    master_size_spec = _read_csv(size_spec_file)

    # remove temp rows from spec, ASim uses them to calculate the other values written
    # to the EDB, but they are not actually part of the utility function themselves.
    spec = spec.loc[~spec.Expression.isna()]
    spec = spec.loc[~spec.Expression.str.startswith("_")].copy()

    settings_file = settings_file.format(name=name)
    with open(os.path.join(edb_directory, settings_file), "r") as yf:
        settings = yaml.load(
            yf,
            Loader=yaml.SafeLoader,
        )

    include_settings = settings.get("include_settings")
    if include_settings:
        include_settings = os.path.join(edb_directory, include_settings)
    if include_settings and os.path.exists(include_settings):
        with open(include_settings, "r") as yf:
            more_settings = yaml.load(
                yf,
                Loader=yaml.SafeLoader,
            )
        settings.update(more_settings)

    CHOOSER_SEGMENT_COLUMN_NAME = settings.get("CHOOSER_SEGMENT_COLUMN_NAME")
    SEGMENT_IDS = settings.get("SEGMENT_IDS")
    if SEGMENT_IDS is None:
        SEGMENTS = settings.get("SEGMENTS")
        if SEGMENTS is not None:
            SEGMENT_IDS = {i: i for i in SEGMENTS}

    SIZE_TERM_SELECTOR = settings.get('SIZE_TERM_SELECTOR', model_selector)

    # filter size spec for this location choice only
    size_spec = (master_size_spec.query(
        f"model_selector == '{SIZE_TERM_SELECTOR}'").drop(
            columns="model_selector").set_index("segment"))
    size_spec = size_spec.loc[:, size_spec.max() > 0]

    size_coef = size_coefficients_from_spec(size_spec)

    indexes_to_drop = [
        "util_size_variable",  # pre-computed size (will be re-estimated)
        "util_size_variable_atwork",  # pre-computed size (will be re-estimated)
        "util_utility_adjustment",  # shadow pricing (ignored in estimation)
        "@df['size_term'].apply(np.log1p)",  # pre-computed size (will be re-estimated)
    ]
    if 'Label' in spec.columns:
        indexes_to_drop = [
            i for i in indexes_to_drop if i in spec.Label.to_numpy()
        ]
        label_column_name = 'Label'
    elif 'Expression' in spec.columns:
        indexes_to_drop = [
            i for i in indexes_to_drop if i in spec.Expression.to_numpy()
        ]
        label_column_name = 'Expression'
    else:
        raise ValueError("cannot find Label or Expression in spec file")

    expression_labels = None
    if label_column_name == 'Expression':
        expression_labels = {
            expr: f"variable_label{n:04d}"
            for n, expr in enumerate(spec.Expression.to_numpy())
        }

    # Remove shadow pricing and pre-existing size expression for re-estimation
    spec = (spec.set_index(label_column_name).drop(
        index=indexes_to_drop).reset_index())

    if label_column_name == 'Expression':
        spec.insert(0, "Label", spec['Expression'].map(expression_labels))
        alt_values['variable'] = alt_values['variable'].map(expression_labels)
        label_column_name = "Label"

    if name == 'trip_destination':
        CHOOSER_SEGMENT_COLUMN_NAME = 'primary_purpose'
        primary_purposes = spec.columns[3:]
        SEGMENT_IDS = {pp: pp for pp in primary_purposes}

    chooser_index_name = chooser_data.columns[0]
    x_co = chooser_data.set_index(chooser_index_name)
    x_ca = cv_to_ca(
        alt_values.set_index([chooser_index_name, alt_values.columns[1]]))

    if CHOOSER_SEGMENT_COLUMN_NAME is not None:
        # label segments with names
        SEGMENT_IDS_REVERSE = {v: k for k, v in SEGMENT_IDS.items()}
        x_co["_segment_label"] = x_co[CHOOSER_SEGMENT_COLUMN_NAME].apply(
            lambda x: SEGMENT_IDS_REVERSE[x])
    else:
        x_co["_segment_label"] = size_spec.index[0]

    # compute total size values by segment
    for segment in size_spec.index:
        total_size_segment = pd.Series(0, index=landuse.index)
        x_co["total_size_" + segment] = 0
        for land_use_field in size_spec.loc[segment].index:
            total_size_segment += (landuse[land_use_field] *
                                   size_spec.loc[segment, land_use_field])
        x_co["total_size_" + segment] = total_size_segment.loc[
            x_co["override_choice"]].to_numpy()

    # for each chooser, collate the appropriate total size value
    x_co["total_size_segment"] = 0
    for segment in size_spec.index:
        labels = "total_size_" + segment
        rows = x_co["_segment_label"] == segment
        x_co.loc[rows, "total_size_segment"] = x_co[labels][rows]

    # Remove choosers with invalid observed choice (appropriate total size value = 0)
    valid_observed_zone = x_co["total_size_segment"] > 0
    x_co = x_co[valid_observed_zone]
    x_ca = x_ca[x_ca.index.get_level_values(chooser_index_name).isin(
        x_co.index)]

    # Merge land use characteristics into CA data
    try:
        x_ca_1 = pd.merge(x_ca, landuse, on="zone_id", how="left")
    except KeyError:
        # Missing the zone_id variable?
        # Use the alternative id's instead, which assumes no sampling of alternatives
        x_ca_1 = pd.merge(x_ca,
                          landuse,
                          left_on=x_ca.index.get_level_values(1),
                          right_index=True,
                          how="left")
    x_ca_1.index = x_ca.index

    # Availability of choice zones
    if "util_no_attractions" in x_ca_1:
        av = x_ca_1["util_no_attractions"].apply(
            lambda x: False if x == 1 else True).astype(np.int8)
    elif "@df['size_term']==0" in x_ca_1:
        av = x_ca_1["@df['size_term']==0"].apply(
            lambda x: False if x == 1 else True).astype(np.int8)
    else:
        av = 1

    d = DataFrames(co=x_co, ca=x_ca_1, av=av)

    m = Model(dataservice=d)
    if len(spec.columns) == 4 and all(
            spec.columns ==
        ['Label', 'Description', 'Expression', 'coefficient']):
        m.utility_ca = linear_utility_from_spec(
            spec,
            x_col="Label",
            p_col=spec.columns[-1],
            ignore_x=("local_dist", ),
        )
    elif len(spec.columns) == 4 \
            and all(spec.columns[:3] == ['Label', 'Description', 'Expression']) \
            and len(SEGMENT_IDS) == 1 \
            and spec.columns[3] == list(SEGMENT_IDS.values())[0]:
        m.utility_ca = linear_utility_from_spec(
            spec,
            x_col="Label",
            p_col=spec.columns[-1],
            ignore_x=("local_dist", ),
        )
    else:
        m.utility_ca = linear_utility_from_spec(
            spec,
            x_col=label_column_name,
            p_col=SEGMENT_IDS,
            ignore_x=("local_dist", ),
            segment_id=CHOOSER_SEGMENT_COLUMN_NAME,
        )

    if CHOOSER_SEGMENT_COLUMN_NAME is None:
        assert len(size_spec) == 1
        m.quantity_ca = sum(
            P(f"{i}_{q}") * X(q) for i in size_spec.index
            for q in size_spec.columns if size_spec.loc[i, q] != 0)
    else:
        m.quantity_ca = sum(
            P(f"{i}_{q}") * X(q) *
            X(f"{CHOOSER_SEGMENT_COLUMN_NAME}=={str_repr(SEGMENT_IDS[i])}")
            for i in size_spec.index for q in size_spec.columns
            if size_spec.loc[i, q] != 0)

    apply_coefficients(coefficients, m)
    apply_coefficients(size_coef, m, minimum=-6, maximum=6)

    m.choice_co_code = "override_choice"

    if return_data:
        return (
            m,
            Dict(
                edb_directory=Path(edb_directory),
                alt_values=alt_values,
                chooser_data=chooser_data,
                coefficients=coefficients,
                landuse=landuse,
                spec=spec,
                size_spec=size_spec,
                master_size_spec=master_size_spec,
                model_selector=model_selector,
                settings=settings,
            ),
        )

    return m
示例#2
0
def test_utility_function_output():
    k = Model()
    k.utility_ca = P.Aaa * X.Aaa + P.Bbb * X.Bbb + P.Ccc
    k.utility_co[1] = P.Dx1 + P.Dy1 * X.Yyy
    k.utility_co[2] = P.Dx2 + P.Dy2 * X.Yyy

    k.quantity_ca = P.Qaa * X.Aaa + P.Qbb * X.Bbb + P.Qcc

    k.set_values(Aaa=12, Bbb=20, Ccc=2, Dx1=0, Dy1=0.001, Dx2=0.33, Dy2=-0.002)

    u1 = k.utility_functions(resolve_parameters=False)

    assert u1.tostring() == '<div><table class="floatinghead" style="margin-top:1px;"><thead>' \
          '<tr><th>alt</th><th style="text-align:left;">formula</th></tr></thead>' \
          '<tbody><tr><td>1</td><td style="text-align:left;"><div></div> + ' \
          '<div class="tooltipped">P.Aaa<span class="tooltiptext">12</span></div> * ' \
          '<div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span>' \
          '</div><br> + <div class="tooltipped">P.Bbb<span class="tooltiptext">20</span>' \
          '</div> * <div class="tooltipped">X.Bbb<span class="tooltiptext">This is Data' \
          '</span></div><br> + <div class="tooltipped">P.Ccc<span class="tooltiptext">2' \
          '</span></div><br> + <div class="tooltipped">P.Dx1<span class="tooltiptext">0' \
          '</span></div><br> + <div class="tooltipped">P.Dy1<span class="tooltiptext">0.001' \
          '</span></div> * <div class="tooltipped">X.Yyy<span class="tooltiptext">' \
          'This is Data</span></div><br> + log(<br>\xa0\xa0 + <span></span>exp(' \
          '<div class="tooltipped">P.Qaa<span class="tooltiptext">exp(0) = 0</span></div>) ' \
          '* <div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span></div>' \
          '<br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">P.Qbb<span class="tooltiptext">' \
          'exp(0) = 0</span></div>) * <div class="tooltipped">X.Bbb<span class="tooltiptext">' \
          'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">' \
          'P.Qcc<span class="tooltiptext">exp(0) = 0</span></div>)<br>)</td></tr><tr><td>2</td>' \
          '<td style="text-align:left;"><div></div> + <div class="tooltipped">P.Aaa' \
          '<span class="tooltiptext">12</span></div> * <div class="tooltipped">X.Aaa' \
          '<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
          'P.Bbb<span class="tooltiptext">20</span></div> * <div class="tooltipped">X.Bbb' \
          '<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
          'P.Ccc<span class="tooltiptext">2</span></div><br> + <div class="tooltipped">P.Dx2' \
          '<span class="tooltiptext">0.33</span></div><br> + <div class="tooltipped">P.Dy2' \
          '<span class="tooltiptext">-0.002</span></div> * <div class="tooltipped">X.Yyy' \
          '<span class="tooltiptext">This is Data</span></div><br> + log(<br>\xa0\xa0 + ' \
          '<span></span>exp(<div class="tooltipped">P.Qaa<span class="tooltiptext">exp(0) = 0' \
          '</span></div>) * <div class="tooltipped">X.Aaa<span class="tooltiptext">' \
          'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">' \
          'P.Qbb<span class="tooltiptext">exp(0) = 0</span></div>) * <div class="tooltipped">' \
          'X.Bbb<span class="tooltiptext">This is Data</span></div><br>\xa0\xa0 + <span>' \
          '</span>exp(<div class="tooltipped">P.Qcc<span class="tooltiptext">exp(0) = 0</span>' \
          '</div>)<br>)</td></tr></tbody></table></div>'

    u2 = k.utility_functions(resolve_parameters=True)

    assert u2.tostring() == '<div><table class="floatinghead" style="margin-top:1px;"><thead><tr><th>alt</th>' \
          '<th style="text-align:left;">formula</th></tr></thead><tbody><tr><td>1</td>' \
          '<td style="text-align:left;"><div></div> + <div class="tooltipped">12' \
          '<span class="tooltiptext">P.Aaa</span></div> * <div class="tooltipped">' \
          'X.Aaa<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
          '20<span class="tooltiptext">P.Bbb</span></div> * <div class="tooltipped">X.Bbb' \
          '<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
          '2<span class="tooltiptext">P.Ccc</span></div><br> + <div class="tooltipped">0' \
          '<span class="tooltiptext">P.Dx1</span></div><br> + <div class="tooltipped">0.001' \
          '<span class="tooltiptext">P.Dy1</span></div> * <div class="tooltipped">X.Yyy' \
          '<span class="tooltiptext">This is Data</span></div><br> + log(<br>\xa0\xa0 + <span>' \
          '</span>exp(<div class="tooltipped">0<span class="tooltiptext">exp(P.Qaa)</span></div>) ' \
          '* <div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span></div>' \
          '<br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">0<span class="tooltiptext">' \
          'exp(P.Qbb)</span></div>) * <div class="tooltipped">X.Bbb<span class="tooltiptext">' \
          'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">0' \
          '<span class="tooltiptext">exp(P.Qcc)</span></div>)<br>)</td></tr><tr><td>2</td>' \
          '<td style="text-align:left;"><div></div> + <div class="tooltipped">12' \
          '<span class="tooltiptext">P.Aaa</span></div> * <div class="tooltipped">X.Aaa' \
          '<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
          '20<span class="tooltiptext">P.Bbb</span></div> * <div class="tooltipped">X.Bbb' \
          '<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">2' \
          '<span class="tooltiptext">P.Ccc</span></div><br> + <div class="tooltipped">0.33' \
          '<span class="tooltiptext">P.Dx2</span></div><br> + <div class="tooltipped">-0.002' \
          '<span class="tooltiptext">P.Dy2</span></div> * <div class="tooltipped">X.Yyy' \
          '<span class="tooltiptext">This is Data</span></div><br> + log(<br>\xa0\xa0 + <span>' \
          '</span>exp(<div class="tooltipped">0<span class="tooltiptext">exp(P.Qaa)</span></div>) ' \
          '* <div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span></div>' \
          '<br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">0<span class="tooltiptext">' \
          'exp(P.Qbb)</span></div>) * <div class="tooltipped">X.Bbb<span class="tooltiptext">' \
          'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">' \
          '0<span class="tooltiptext">exp(P.Qcc)</span></div>)<br>)</td></tr></tbody></table></div>'
示例#3
0
def test_utility_function_output():
	k = Model()
	k.utility_ca = P.Aaa * X.Aaa + P.Bbb * X.Bbb + P.Ccc
	k.utility_co[1] = P.Dx1 + P.Dy1 * X.Yyy
	k.utility_co[2] = P.Dx2 + P.Dy2 * X.Yyy

	k.quantity_ca = P.Qaa * X.Aaa + P.Qbb * X.Bbb + P.Qcc

	k.set_values(Aaa=12, Bbb=20, Ccc=2, Dx1=0, Dy1=0.001, Dx2=0.33, Dy2=-0.002)

	u1 = k.utility_functions(resolve_parameters=False)

	assert u1.tostring() == '<div><table class="floatinghead" style="margin-top:1px;"><thead>' \
							'<tr><th>alt</th><th style="text-align:left;">formula</th></tr></thead>' \
							'<tbody><tr><td>1</td><td style="text-align:left;"><div></div> + ' \
							'<div class="tooltipped">P.Aaa<span class="tooltiptext">12</span></div> * ' \
							'<div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span>' \
							'</div><br> + <div class="tooltipped">P.Bbb<span class="tooltiptext">20</span>' \
							'</div> * <div class="tooltipped">X.Bbb<span class="tooltiptext">This is Data' \
							'</span></div><br> + <div class="tooltipped">P.Ccc<span class="tooltiptext">2' \
							'</span></div><br> + <div class="tooltipped">P.Dx1<span class="tooltiptext">0' \
							'</span></div><br> + <div class="tooltipped">P.Dy1<span class="tooltiptext">0.001' \
							'</span></div> * <div class="tooltipped">X.Yyy<span class="tooltiptext">' \
							'This is Data</span></div><br> + log(<br>\xa0\xa0 + <span></span>exp(' \
							'<div class="tooltipped">P.Qaa<span class="tooltiptext">exp(0) = 0</span></div>) ' \
							'* <div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span></div>' \
							'<br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">P.Qbb<span class="tooltiptext">' \
							'exp(0) = 0</span></div>) * <div class="tooltipped">X.Bbb<span class="tooltiptext">' \
							'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">' \
							'P.Qcc<span class="tooltiptext">exp(0) = 0</span></div>)<br>)</td></tr><tr><td>2</td>' \
							'<td style="text-align:left;"><div></div> + <div class="tooltipped">P.Aaa' \
							'<span class="tooltiptext">12</span></div> * <div class="tooltipped">X.Aaa' \
							'<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
							'P.Bbb<span class="tooltiptext">20</span></div> * <div class="tooltipped">X.Bbb' \
							'<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
							'P.Ccc<span class="tooltiptext">2</span></div><br> + <div class="tooltipped">P.Dx2' \
							'<span class="tooltiptext">0.33</span></div><br> + <div class="tooltipped">P.Dy2' \
							'<span class="tooltiptext">-0.002</span></div> * <div class="tooltipped">X.Yyy' \
							'<span class="tooltiptext">This is Data</span></div><br> + log(<br>\xa0\xa0 + ' \
							'<span></span>exp(<div class="tooltipped">P.Qaa<span class="tooltiptext">exp(0) = 0' \
							'</span></div>) * <div class="tooltipped">X.Aaa<span class="tooltiptext">' \
							'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">' \
							'P.Qbb<span class="tooltiptext">exp(0) = 0</span></div>) * <div class="tooltipped">' \
							'X.Bbb<span class="tooltiptext">This is Data</span></div><br>\xa0\xa0 + <span>' \
							'</span>exp(<div class="tooltipped">P.Qcc<span class="tooltiptext">exp(0) = 0</span>' \
							'</div>)<br>)</td></tr></tbody></table></div>'

	u2 = k.utility_functions(resolve_parameters=True)

	assert u2.tostring() == '<div><table class="floatinghead" style="margin-top:1px;"><thead><tr><th>alt</th>' \
							'<th style="text-align:left;">formula</th></tr></thead><tbody><tr><td>1</td>' \
							'<td style="text-align:left;"><div></div> + <div class="tooltipped">12' \
							'<span class="tooltiptext">P.Aaa</span></div> * <div class="tooltipped">' \
							'X.Aaa<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
							'20<span class="tooltiptext">P.Bbb</span></div> * <div class="tooltipped">X.Bbb' \
							'<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
							'2<span class="tooltiptext">P.Ccc</span></div><br> + <div class="tooltipped">0' \
							'<span class="tooltiptext">P.Dx1</span></div><br> + <div class="tooltipped">0.001' \
							'<span class="tooltiptext">P.Dy1</span></div> * <div class="tooltipped">X.Yyy' \
							'<span class="tooltiptext">This is Data</span></div><br> + log(<br>\xa0\xa0 + <span>' \
							'</span>exp(<div class="tooltipped">0<span class="tooltiptext">exp(P.Qaa)</span></div>) ' \
							'* <div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span></div>' \
							'<br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">0<span class="tooltiptext">' \
							'exp(P.Qbb)</span></div>) * <div class="tooltipped">X.Bbb<span class="tooltiptext">' \
							'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">0' \
							'<span class="tooltiptext">exp(P.Qcc)</span></div>)<br>)</td></tr><tr><td>2</td>' \
							'<td style="text-align:left;"><div></div> + <div class="tooltipped">12' \
							'<span class="tooltiptext">P.Aaa</span></div> * <div class="tooltipped">X.Aaa' \
							'<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">' \
							'20<span class="tooltiptext">P.Bbb</span></div> * <div class="tooltipped">X.Bbb' \
							'<span class="tooltiptext">This is Data</span></div><br> + <div class="tooltipped">2' \
							'<span class="tooltiptext">P.Ccc</span></div><br> + <div class="tooltipped">0.33' \
							'<span class="tooltiptext">P.Dx2</span></div><br> + <div class="tooltipped">-0.002' \
							'<span class="tooltiptext">P.Dy2</span></div> * <div class="tooltipped">X.Yyy' \
							'<span class="tooltiptext">This is Data</span></div><br> + log(<br>\xa0\xa0 + <span>' \
							'</span>exp(<div class="tooltipped">0<span class="tooltiptext">exp(P.Qaa)</span></div>) ' \
							'* <div class="tooltipped">X.Aaa<span class="tooltiptext">This is Data</span></div>' \
							'<br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">0<span class="tooltiptext">' \
							'exp(P.Qbb)</span></div>) * <div class="tooltipped">X.Bbb<span class="tooltiptext">' \
							'This is Data</span></div><br>\xa0\xa0 + <span></span>exp(<div class="tooltipped">' \
							'0<span class="tooltiptext">exp(P.Qcc)</span></div>)<br>)</td></tr></tbody></table></div>'