126 lines
4.8 KiB
Markdown
126 lines
4.8 KiB
Markdown
# BHI Composite Scoring Function
|
|
|
|
## Formula
|
|
|
|
```
|
|
composite_score =
|
|
(demand_severity * 0.25) +
|
|
(supply_shortage * 0.25) +
|
|
(pain_signal_volume * 0.20) +
|
|
(capacity_trend * 0.10) +
|
|
(workforce_shortage * 0.10) +
|
|
(regulatory_tailwind * 0.05) +
|
|
(govt_demand * 0.05)
|
|
```
|
|
|
|
All components are normalized to 0-100 before weighting. Final `composite_score` is 0-100.
|
|
Each component is computed at the **geo x niche x age-bracket** level (state, county, or MSA depending on data).
|
|
|
|
Thesis this reflects (all-of-the-above): demand is outpacing supply, delivery model is shifting, and regulation is restructuring the market — we weight demand + supply heaviest (50% combined), then real-time pain signals, then the three tailwinds.
|
|
|
|
---
|
|
|
|
## Component definitions
|
|
|
|
### 1. demand_severity (25%)
|
|
Feeder: `bhi_demand_indicators` (CDC WONDER, BRFSS, YRBSS, NSCH).
|
|
|
|
For a given geo + age bracket, combine:
|
|
- Suicide rate per 100k (CDC WONDER, ICD-10 X60-X84)
|
|
- Drug overdose death rate per 100k (CDC WONDER, X40-X44 + Y10-Y14)
|
|
- YRBSS "seriously considered suicide" % (adolescent)
|
|
- BRFSS "mental health not good 14+ days" % (young adult via 18-24 bracket)
|
|
- NSCH unmet mental health treatment need %
|
|
|
|
Normalize each to 0-100 against the national distribution (percentile rank), then average.
|
|
Trend multiplier: +10 if 5-yr CAGR > 5%.
|
|
|
|
### 2. supply_shortage (25%)
|
|
Feeders: `bhi_shortages` (HRSA HPSA) + `bhi_facilities` (SAMHSA + CMS).
|
|
|
|
For a geo:
|
|
- HPSA mental health score (0-25, already normalized; rescale x4 -> 0-100)
|
|
- Inverse of facility density: beds per 100k population (percentile-invert)
|
|
- Inverse of adolescent/young-adult-specific bed density (if scoring those brackets)
|
|
|
|
Weighted average: 50% HPSA score, 30% total bed density, 20% age-targeted bed density.
|
|
|
|
### 3. pain_signal_volume (20%)
|
|
Feeders: base Brain's `reddit_posts`, `app_reviews`, and `risk_factors` tables (already being built).
|
|
|
|
For a niche (e.g., "adolescent inpatient"):
|
|
- Count of posts/reviews/risk-factor hits matching niche keywords in last 90 days
|
|
- Z-score against the full base Brain niche distribution
|
|
- Clamp to 0-100
|
|
|
|
Depends on base Brain being live — until then, this component defaults to 50 (neutral).
|
|
|
|
### 4. capacity_trend (10%)
|
|
Feeder: `bhi_facilities` (opened_date, closed_date) + CMS POS termination records.
|
|
|
|
For the geo x niche:
|
|
- Facilities opened in last 24 months minus closed in last 24 months, normalized by baseline facility count
|
|
- Negative net = high score (more opportunity), positive net = low score (saturated)
|
|
- Formula: `100 * (1 - (net_change + baseline) / (2 * baseline))` clamped 0-100
|
|
|
|
### 5. workforce_shortage (10%)
|
|
Feeder: `bhi_workforce` (BLS OES).
|
|
|
|
For the MSA:
|
|
- Wage growth YoY for SOC codes 29-1223, 21-1014, 21-1018, 103T (percentile rank)
|
|
- Employment per 100k (inverse percentile)
|
|
- Average them
|
|
|
|
High wage growth + low employment density = high shortage score = high opportunity for new supply.
|
|
|
|
### 6. regulatory_tailwind (5%)
|
|
Feeder: `bhi_policy_events`.
|
|
|
|
Count of favorable policy events in the last 18 months for the geo:
|
|
- Medicaid rate increases for BH services
|
|
- New state mandates for adolescent crisis services
|
|
- Expanded provider types (peer support, mobile crisis)
|
|
- Federal rules (e.g., Mental Health Parity enforcement)
|
|
|
|
`count * 20`, clamped to 0-100.
|
|
|
|
### 7. govt_demand (5%)
|
|
Feeder: base Brain's `sam_gov_opportunities` table (if present) + `bhi_policy_events`.
|
|
|
|
Active + awarded SAM.gov opportunities in NAICS 621112 (Physician offices - mental), 621420 (Outpatient mental health/SUD), 623220 (Residential mental health), 623210 (Residential intellectual/developmental), 624190 (Other individual/family services). Dollar-value-weighted and geo-filtered.
|
|
|
|
Log-scale: `min(100, 10 * log10(total_dollar_value + 1))`.
|
|
|
|
---
|
|
|
|
## Age bracket handling
|
|
|
|
Every row in `bhi_demand_indicators` carries an `age_bracket`. When scoring a niche tagged for adolescents (13-17), the demand_severity and pain_signal components filter to that bracket. Young-adult scores pull 18-25. "All" niches average both brackets 50/50.
|
|
|
|
Young-adult gap note: for young-adult scoring, supply_shortage should apply an extra +15 penalty on facility density since very few IPFs have dedicated young-adult units — this is captured via the `young_adult_unit` boolean in `bhi_facilities`.
|
|
|
|
---
|
|
|
|
## Output table (to be added)
|
|
|
|
Scores write to `bhi_scores` (created at runtime, not in bhi_tables.sql v1 — add once inputs are flowing):
|
|
|
|
```sql
|
|
CREATE TABLE bhi_scores (
|
|
id SERIAL PRIMARY KEY,
|
|
niche TEXT,
|
|
geo_type TEXT,
|
|
geo_code TEXT,
|
|
age_bracket TEXT,
|
|
composite NUMERIC,
|
|
demand_severity NUMERIC,
|
|
supply_shortage NUMERIC,
|
|
pain_signal NUMERIC,
|
|
capacity_trend NUMERIC,
|
|
workforce_short NUMERIC,
|
|
reg_tailwind NUMERIC,
|
|
govt_demand NUMERIC,
|
|
computed_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
```
|