Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supply and Demand Corrections #119

Merged
merged 37 commits into from
Oct 17, 2014
Merged

Supply and Demand Corrections #119

merged 37 commits into from
Oct 17, 2014

Conversation

jiffyclub
Copy link
Member

@fscottfoti, this implements the supply/demand comparison and adjustment we'd specced out. Very simple, straight comparison of (probabilities * len(choosers)).groupby(alternatives[col].values).sum() / alternatives[col].value_counts() with adjustments done across 5 iterations, capped at 0.75-1.25 fractional change per iteration.

On a basic LCM the .probabilities method returns an array of
probabilities and a Series of the alternatives those probabilities
are associated with. Right now those alternatives corresponding
to exactly the alternatives given because we calculate probabilities
for only one chooser, but that could change in the future.

On segmented LCMs and LCM groups there are two new methods.
.probabilities returns a dictionary where the keys are segment
names from the choosers table and the values are arrays of
probabilities for each segment. The .summed_probabilities methods
return one array of probabilities calculated by taking the
individual segment probabilities, normalizing them, and
multiplying by the number of members in the segment.
Right now it's a simple function that works with an LCM, choosers,
and alternatives. It compares summed probabilities from the LCM (demand) to
counts of probabilities (supply) and makes adjustments to prices accordingly.
@jiffyclub
Copy link
Member Author

fa3e7f8 will be the most interesting changes in terms of the supply/demand code, but you mentioned also that you'd be interested in the LCM .probabilities methods in c0a11fa.

@waddell
Copy link
Member

waddell commented Sep 30, 2014

I'd love to see some performance benchmarking...

On Tue, Sep 30, 2014 at 4:55 PM, Matt Davis notifications@github.com
wrote:

@fscottfoti https://github.com/fscottfoti, this implements the
supply/demand comparison and adjustment we'd specced out. Very simple,
straight comparison of (probabilities *
len(choosers)).groupby(alternatives[col].values).sum() /
alternatives[col].value_counts() with adjustments done across 5

iterations, capped at 0.75-1.25 fractional change per iteration.

You can merge this Pull Request by running

git pull https://github.com/synthicity/urbansim supdem

Or view, comment on, or merge it at:

#119
Commit Summary

  • Line length adjustments.
  • Add .probabilities methods in LCM
  • Add .summed_probabilities method to basic LCM
  • Fix LCM docstrings
  • Add basic supply/demand model

File Changes

Patch Links:


Reply to this email directly or view it on GitHub
#119.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.04%) when pulling fa3e7f8 on supdem into f6b6e04 on master.

@jiffyclub
Copy link
Member Author

This has the potential to add a bit of time to runs since it's adding several extra calls to the LCM simulation functions, but we'll need @fscottfoti to throw some real data at it to see the actual effect.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.05%) when pulling 308420f on supdem into f6b6e04 on master.

@fscottfoti
Copy link
Contributor

OK this is looking good. My one question is this. I definitely want to be able for these ratios to be applied cumulatively. So maybe we cap the adjustment each year, but the next year we start with the previous year's adjustment and keep applying adjustments, and if it's still supply constrained (or high vacancy) I want to make the price difference even more extreme. Ideally you would return to me the ratios as a series with submarket id as the index and ratio as the value and I would pass this back to you the next year as the starting place for supply-demand adjustment (I would also write this out to the diagnostic logs for visualization on the maps). Presumably these start as np.ones(). I'm sure I could do all this by reversing engineering the shifters from the prices, but this is a pretty standard usage of the module and it seems simple enough to add it in - what do you think?

@jiffyclub
Copy link
Member Author

If a ratio comes back 1.25 one year and you pass that back, should it be capped again at 1.25, or are you expecting that go up the next year?

@jiffyclub
Copy link
Member Author

Each iteration through the ratios are calculated anew as (demand / supply), they aren't informed by any other inputs. Each iteration the price is adjusted by the calculated and clipped (demand / supply) ratio so that the next iteration demand has shifted and we get a new set of ratios, adjust the price again, and iterate. So how would input ratios inform that process?

@fscottfoti
Copy link
Contributor

Good question. If a ratio comes back at 1.25 I would expect it to be capped at 1.25*1.25 the next year (it is allowed and expected to exceed the ratio year-over-year, just not within a year). It is possible that you could return the ratios to me and I can take care of this. I would take the ratios from the previous year and multiply the price by these ratios. Then when you return new ratios to me I would multiply the existing ratios by the new ratios.

Or in a functionality equivalent way, the module could do this for me by multiplying the input price by the input ratios, running the same equilibration that exists in there now, and multiplying the input ratios by the new ratios and returning them to me. Either way would work but that is what I was thinking for functionality.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.06%) when pulling 2390122 on supdem into f6b6e04 on master.

@jiffyclub
Copy link
Member Author

Okay @fscottfoti, supply_and_demand now has a base_multiplier keyword where you can provide a series of segment: multiplier values.

@fscottfoti
Copy link
Contributor

Excellent - will try shortly

So that external things can get choosers and alternatives
filtered in the same was as used within the LCMs, e.g. in
supply_and_demand.
When calculating probabilities LCMs filter the set of
alternatives available to users. In supply_and_demand we need
to work with the same set of filtered alternatives.
Hopefully this will account for filtering done on the merged
interaction dataset, which is hard to account for from outside
the LCM.
@coveralls
Copy link

Coverage Status

Coverage decreased (-0.58%) when pulling 9bee525 on supdem into f6b6e04 on master.

supply_and_demand was returning the multipliers only from the last
iteration of the price updates. This fixes it to accumulate the
multipliers and return that.
On a basic LCM the .probabilities method returns an array of
probabilities and a Series of the alternatives those probabilities
are associated with. Right now those alternatives corresponding
to exactly the alternatives given because we calculate probabilities
for only one chooser, but that could change in the future.

On segmented LCMs and LCM groups there are two new methods.
.probabilities returns a dictionary where the keys are segment
names from the choosers table and the values are arrays of
probabilities for each segment. The .summed_probabilities methods
return one array of probabilities calculated by taking the
individual segment probabilities, normalizing them, and
multiplying by the number of members in the segment.
Right now it's a simple function that works with an LCM, choosers,
and alternatives. It compares summed probabilities from the LCM (demand) to
counts of probabilities (supply) and makes adjustments to prices accordingly.
So that external things can get choosers and alternatives
filtered in the same was as used within the LCMs, e.g. in
supply_and_demand.
When calculating probabilities LCMs filter the set of
alternatives available to users. In supply_and_demand we need
to work with the same set of filtered alternatives.
Hopefully this will account for filtering done on the merged
interaction dataset, which is hard to account for from outside
the LCM.
supply_and_demand was returning the multipliers only from the last
iteration of the price updates. This fixes it to accumulate the
multipliers and return that.
Fletcher added 2 commits October 10, 2014 16:41
…ratios

This allows the client repos pretty much complete control on how the relationship between demand and supply gets translated into an adjustment on price.  By default (if no map_func is passed) then the ratios are the same, which was the previous functionality.
@fscottfoti
Copy link
Contributor

@jiffyclub I made a small change to this by specifying a function to map supdem ratios to price ratios. Please review and feel free to merge PR if you're OK with the changes.

@jiffyclub
Copy link
Member Author

It seems like map_func would be more flexible if it took supply and demand as inputs instead of their ratio. And then you could rename map_func to multiplier_func, which is more intuitive. Right now I don't think of it as a "mapping" function so much as an arbitrary adjustment function.

Fletcher added 2 commits October 17, 2014 14:55
which takes demand and supply Series directly as input params
@jiffyclub
Copy link
Member Author

Cool, looks like a couple pep8 fixes and it'll be ready to go.

jiffyclub added a commit that referenced this pull request Oct 17, 2014
Supply and Demand Corrections
@jiffyclub jiffyclub merged commit 1bfac31 into master Oct 17, 2014
@jiffyclub jiffyclub deleted the supdem branch October 17, 2014 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants