Skip to content

Commit

Permalink
Beginning of a LocationChoiceModel class. (Implicitly MNL.)
Browse files Browse the repository at this point in the history
  • Loading branch information
jiffyclub committed Apr 15, 2014
1 parent 1fa4e55 commit 3dd7877
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 2 deletions.
71 changes: 71 additions & 0 deletions urbansim/models/lcm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import numpy as np
from patsy import dmatrix

from ..urbanchoice import interaction, mnl


class LocationChoiceModel(object):
"""
A location choice model with the ability to store an estimated
model and predict new data based on the model.
Parameters
----------
fit_filters : list of str
Filters applied before fitting the model.
predict_filters : list of str
Filters applied before calculating new data points.
model_expression : str
A patsy model expression. Should contain only a right-hand side.
sample_size : int
Number of choices to sample for estimating the model.
name : optional
Optional descriptive name for this model that may be used
in output.
"""
def __init__(self, fit_filters, predict_filters, model_expression,
sample_size, name=None):
self.fit_filters = fit_filters
self.predict_filters = predict_filters
# LCMs never have a constant
self.model_expression = model_expression + ' - 1'
self.sample_size = sample_size
self.name = name or 'LocationChoiceModel'

def fit(self, choosers, alternatives, current_choice):
"""
Fit and save model parameters based on given data.
Parameters
----------
choosers : pandas.DataFrame
Table describing the agents making choices, e.g. households.
alternatives : pandas.DataFrame
Table describing the things from which agents are choosing,
e.g. buildings.
current_choice : pandas.Series
A Series describing the `alternatives` currently chosen
by the `choosers`. Should have an index matching `choosers`
and values matching the index of `alternatives`.
Returns
-------
null_ll : float
Null Log-liklihood
conv_ll : float
Log-liklihood at convergence
ll_ratio : float
Log-liklihood ratio
"""
_, merged, chosen = interaction.mnl_interaction_dataset(
choosers, alternatives, self.sample_size, current_choice)
model_design = dmatrix(self.model_expression, data=merged)
fit, results = mnl.mnl_estimate(
model_design.as_matrix(), chosen, self.sample_size)
self.fit_results = results
return fit

def predict(self, data):
pass
7 changes: 5 additions & 2 deletions urbansim/urbanchoice/interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ def mnl_simulate(data, coeff, numalts, gpu=GPU, returnprobs=0):

def mnl_interaction_dataset(choosers, alternatives, SAMPLE_SIZE,
chosenalts=None):
# filter choosers and their current choices if they point to
# something that isn't in the alternatives table
if chosenalts is not None:
isin = chosenalts.isin(alternatives.index)
removing = isin.value_counts()[False]
Expand All @@ -73,7 +75,7 @@ def mnl_interaction_dataset(choosers, alternatives, SAMPLE_SIZE,

if SAMPLE_SIZE < numalts:
sample = np.random.choice(
alternatives.index.values, SAMPLE_SIZE * choosers.shape[0])
alternatives.index.values, SAMPLE_SIZE * numchoosers)
if chosenalts is not None:
# replace with chosen alternative
sample[::SAMPLE_SIZE] = chosenalts
Expand All @@ -97,6 +99,7 @@ def mnl_interaction_dataset(choosers, alternatives, SAMPLE_SIZE,
try:
alts_sample['join_index'] = np.repeat(choosers.index, SAMPLE_SIZE)
except:
# TODO: log the error here and re-raise the original exception
raise Exception(
"ERROR: An exception here means agents and "
"alternatives aren't merging correctly")
Expand All @@ -108,7 +111,7 @@ def mnl_interaction_dataset(choosers, alternatives, SAMPLE_SIZE,
chosen = np.zeros((numchoosers, SAMPLE_SIZE))
chosen[:, 0] = 1

return sample, alts_sample, ('mnl', chosen)
return sample, alts_sample, chosen


def mnl_choice_from_sample(sample, choices, SAMPLE_SIZE):
Expand Down

0 comments on commit 3dd7877

Please sign in to comment.