Skip to content

feat: add calc_lycd_land_values — Least You Can Do land valuation#319

Open
drussellmrichie wants to merge 1 commit intolarsiusprime:masterfrom
drussellmrichie:feature/lycd-land-valuation
Open

feat: add calc_lycd_land_values — Least You Can Do land valuation#319
drussellmrichie wants to merge 1 commit intolarsiusprime:masterfrom
drussellmrichie:feature/lycd-land-valuation

Conversation

@drussellmrichie
Copy link
Copy Markdown

Summary

Adds calc_lycd_land_values() to land.py, implementing the Least You Can Do (LYCD) method of land valuation described by Andelson/Tideman.

How it works

For each geographic cell the method:

  1. Computes the median market value and median lot size of improved (non-vacant) parcels.
  2. Derives a uniform local land rate:
    local_land_rate = (median_market_value × land_alloc) / median_lot_size
    
  3. Applies that rate to every parcel in the cell:
    land_value = local_land_rate × parcel_lot_size
    

Because land value is driven by the typical parcel in an area rather than each parcel's own improvement value, the method avoids the absurd side-by-side disparities that arise from naively multiplying each parcel's market value by a fixed allocation fraction.

Key parameters

  • subarea_field (str | None) — column whose values define geographic subareas (e.g. "neighborhood", "census_tract"). When supplied, one rate is derived per (subarea, model_group) cell, capturing neighbourhood-to-neighbourhood price variation that a flat county-wide rate per land-use type would miss. When None, one rate is derived per model_group (the minimal viable case).
  • min_improved_per_cell (int, default 10) — cells with fewer than this many improved parcels fall back to the model-group rate, then to the global rate.
  • land_alloc (float | dict | None) — fixed fraction, per-group dict, or None to auto-derive from the vacant/improved per-unit value ratio (same cell → group → global fallback chain).

Output columns added to df

Column Description
lycd_land_alloc Land allocation fraction used for the cell
lycd_local_land_rate Implied per-area-unit land rate for the cell
lycd_land_value Resulting land value (clamped to [0, market_value])

Test plan

  • Smoke test: call with subarea_field=None on a small synthetic DataFrame and verify lycd_land_value equals local_land_rate × land_area
  • Smoke test: call with subarea_field="neighborhood" and verify cells below min_improved_per_cell fall back to group rate
  • Verify land_alloc=None auto-derives from vacant/improved ratio and falls back gracefully when a group has no vacant parcels

🤖 Generated with Claude Code

Implements the LYCD method described in "valuing land - the simplest
viable method" (Andelson / Tideman tradition).

For each geographic cell the method:
  1. Takes the median market value and median lot size of improved
     (non-vacant) parcels in the cell.
  2. Derives a uniform local land rate:
       local_land_rate = (median_market_value × land_alloc) / median_lot_size
  3. Paints every parcel in the cell with:
       land_value = local_land_rate × parcel_lot_size

Key design decisions:
- `subarea_field` parameter (e.g. "neighborhood", "census_tract") partitions
  the jurisdiction into geographic cells so that rates reflect local price
  levels rather than a flat county-wide rate per land-use type.
- Rates are computed per (subarea, model_group) cell; cells below
  `min_improved_per_cell` (default 10) fall back to the model-group rate,
  then to the global rate.
- `land_alloc` can be a float, a per-group dict, or None (auto-derived from
  the vacant/improved per-unit value ratio with the same fallback chain).
- Output columns: lycd_land_alloc, lycd_local_land_rate, lycd_land_value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Thank you for your contribution.
Please sign our CLA at the following link:
Click here to sign the CLA.
A maintainer will verify your signature and confirm it here by commenting with the following sentence:


I affirm that this contributor has signed the CLA


Russell Richie seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

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.

1 participant