Skip to content

Fix calc_prb: return the PRB slope instead of the intercept - #392

Open
nikhilsi wants to merge 1 commit into
larsiusprime:masterfrom
nikhilsi:fix-calc-prb-slope
Open

Fix calc_prb: return the PRB slope instead of the intercept#392
nikhilsi wants to merge 1 commit into
larsiusprime:masterfrom
nikhilsi:fix-calc-prb-slope

Conversation

@nikhilsi

@nikhilsi nikhilsi commented Jul 4, 2026

Copy link
Copy Markdown

What was wrong

In openavmkit/utilities/stats.py, calc_prb builds the PRB regression with
sm.add_constant(right, has_constant='add') (line 579 at 7952236), which
prepends the constant column. So model.params[0] is the intercept and
model.params[1] is the PRB coefficient. The function reads index 0
throughout:

  • line 586: the degenerate-fit guard checks model.params[0]
  • line 589: prb = float(model.params[0])
  • line 591: the confidence interval is taken from row 0

Every PRB value the library reports today is the regression intercept, which
carries no vertical-equity signal. The sign and magnitude are unrelated to
price-related bias.

The change

Index 1 instead of index 0 in all three places (guard, coefficient,
confidence interval). Three lines, no behavior change elsewhere.

One related note for reviewers: the value proxy on line 578 omits the 0.5
scaling from the IAAO formulation. Under log2 that only shifts the intercept,
not the slope, so it does not affect this fix and is left untouched here.

What changes downstream

All reported PRB numbers change, including in ratio_study.py (lines
125-126), vertical_equity_study.py (line 111), and modeling.py (line
263). That is the point of the fix: the previous numbers were intercepts.
Anyone tracking PRB across runs will see a step change after upgrading.

Verification

A test is included (tests/test_stats.py). It builds a synthetic ratio set
with a known value-correlated bias (predictions overshoot high-value parcels
and undershoot low-value ones), fits the same transformed regression by hand
with sm.OLS, and asserts three things: calc_prb matches the hand-fit
params[1] to within float tolerance, the sign matches the injected bias
direction, and an unbiased control set (predictions equal to a constant
multiple of ground truth) yields a PRB near zero. At 7952236 the biased case
fails (the intercept comes back instead of the slope); with this change it
passes.

Fixes #370.

sm.add_constant prepends the constant column, so params[0] is the
intercept and params[1] is the PRB coefficient. Read index 1 in the
degenerate-fit guard, the returned statistic, and the confidence
interval. Adds a regression test that fits the same transformed
regression by hand and checks a biased set and a flat control.
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Thank you for your contribution.
Please sign our CLA at the following link:
Click here to sign the CLA.

No action is required from you in this PR thread. Once you have signed the CLA externally, a maintainer will verify your signature and record it here on your behalf by commenting:


I affirm that this contributor has signed the CLA


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.

calc_prb returns the regression intercept, not the PRB slope

1 participant