Separate Unit Cost, Utilization, and Mix Effects—Know Which Drivers Fuel 8.2% Medical Trend vs. 2.4% Economy-Wide
python# Healthcare Inflation Attribution Engine def decompose_trend(claims_current_year, claims_prior_year, population_current, population_prior): # Step 1: Calculate aggregate trend total_cost_current = sum(c.paid_amount for c in claims_current_year) total_cost_prior = sum(c.paid_amount for c in claims_prior_year) pmpm_current = total_cost_current / len(population_current) / 12 pmpm_prior = total_cost_prior / len(population_prior) / 12 total_trend = (pmpm_current - pmpm_prior) / pmpm_prior # Step 2: Standardize service mix to isolate unit cost vs utilization service_categories = ['inpatient', 'outpatient', 'professional', 'pharmacy', 'other'] component_attribution = {} for category in service_categories: # Filter claims by category current_claims = [c for c in claims_current_year if c.category == category] prior_claims = [c for c in claims_prior_year if c.category == category] # Unit cost trend (price per service, holding utilization constant) current_unit_cost = sum(c.paid_amount for c in current_claims) / len(current_claims) if current_claims else 0 prior_unit_cost = sum(c.paid_amount for c in prior_claims) / len(prior_claims) if prior_claims else 0 unit_cost_trend = (current_unit_cost - prior_unit_cost) / prior_unit_cost if prior_unit_cost > 0 else 0 # Utilization trend (services per member, holding price constant) current_utilization = len(current_claims) / len(population_current) / 12 prior_utilization = len(prior_claims) / len(population_prior) / 12 utilization_trend = (current_utilization - prior_utilization) / prior_utilization if prior_utilization > 0 else 0 # Case mix trend (severity/complexity shift) # Use DRG weight, CPT RVU, or diagnosis severity score as proxy current_avg_severity = sum(c.case_mix_weight for c in current_claims) / len(current_claims) if current_claims else 0 prior_avg_severity = sum(c.case_mix_weight for c in prior_claims) / len(prior_claims) if prior_claims else 0 case_mix_trend = (current_avg_severity - prior_avg_severity) / prior_avg_severity if prior_avg_severity > 0 else 0 # Contribution to total trend category_pmpm_prior = sum(c.paid_amount for c in prior_claims) / len(population_prior) / 12 category_weight = category_pmpm_prior / pmpm_prior if pmpm_prior > 0 else 0 component_attribution[category] = { 'unit_cost_trend': unit_cost_trend, 'utilization_trend': utilization_trend, 'case_mix_trend': case_mix_trend, 'total_category_trend': (1 + unit_cost_trend) * (1 + utilization_trend) * (1 + case_mix_trend) - 1, 'contribution_to_total_trend': category_weight * ((1 + unit_cost_trend) * (1 + utilization_trend) * (1 + case_mix_trend) - 1) } # Aggregate components total_unit_cost_contribution = sum(v['contribution_to_total_trend'] * (v['unit_cost_trend'] / (v['total_category_trend'] or 1)) for v in component_attribution.values() if v['total_category_trend'] != 0) total_utilization_contribution = sum(v['contribution_to_total_trend'] * (v['utilization_trend'] / (v['total_category_trend'] or 1)) for v in component_attribution.values() if v['total_category_trend'] != 0) total_case_mix_contribution = sum(v['contribution_to_total_trend'] * (v['case_mix_trend'] / (v['total_category_trend'] or 1)) for v in component_attribution.values() if v['total_category_trend'] != 0) # Provider-specific unit cost attribution (top drivers) provider_inflation = {} for claim in claims_current_year: if claim.provider_id not in provider_inflation: provider_inflation[claim.provider_id] = {'current_costs': [], 'prior_costs': []} provider_inflation[claim.provider_id]['current_costs'].append(claim.paid_amount) for claim in claims_prior_year: if claim.provider_id in provider_inflation: provider_inflation[claim.provider_id]['prior_costs'].append(claim.paid_amount) provider_trends = [] for provider_id, data in provider_inflation.items(): if data['prior_costs']: avg_current = sum(data['current_costs']) / len(data['current_costs']) avg_prior = sum(data['prior_costs']) / len(data['prior_costs']) trend = (avg_current - avg_prior) / avg_prior provider_trends.append({ 'provider_id': provider_id, 'provider_name': lookup_provider_name(provider_id), 'unit_cost_trend': trend, 'claim_volume': len(data['current_costs']) }) provider_trends.sort(key=lambda x: abs(x['unit_cost_trend']), reverse=True) return { 'total_trend': total_trend, 'unit_cost_contribution': total_unit_cost_contribution, 'utilization_contribution': total_utilization_contribution, 'case_mix_contribution': total_case_mix_contribution, 'category_breakdown': component_attribution, 'top_provider_inflators': provider_trends[:20] } # Example: Decompose 2024 trend current = load_claims('2024') prior = load_claims('2023') pop_current = load_population('2024') pop_prior = load_population('2023') result = decompose_trend(current, prior, pop_current, pop_prior) print("Total Medical Trend: {:.1%}".format(result['total_trend'])) print("\nComponent Attribution:") print(" Unit Cost Inflation: {:.1%}".format(result['unit_cost_contribution'])) print(" Utilization Change: {:.1%}".format(result['utilization_contribution'])) print(" Case Mix Shift: {:.1%}".format(result['case_mix_contribution'])) print("\nCategory Breakdown:") for cat, data in result['category_breakdown'].items(): print(" {}: {:.1%} total ({:.1%} unit, {:.1%} util, {:.1%} mix)".format( cat.upper(), data['total_category_trend'], data['unit_cost_trend'], data['utilization_trend'], data['case_mix_trend'])) print("\nTop 5 Provider Inflators:") for p in result['top_provider_inflators'][:5]: print(" {}: {:.1%} unit cost trend ({} claims)".format( p['provider_name'], p['unit_cost_trend'], p['claim_volume']))
Decompose trend into unit cost, utilization, and case mix. Drill to categories and providers. Build data-driven mitigation plans. Answer board questions with precision.
Decompose Healthcare Inflation→