Tutorial 1a: Advanced Budget Analysis

This tutorial covers advanced topics in budget-constrained revealed preference analysis, including homothetic preferences, the Lancaster characteristics model, and latent utility recovery.

Topics covered:

  • Homothetic preferences (HARP)

  • The Lancaster characteristics model

  • Piecewise-linear utility recovery (Afriat’s theorem)

  • Marginal utility of money

Prerequisites

Note

These methods are grounded in the Lancaster (1966) model and Afriat (1967) construction theorem.

Part 1: Homothetic Preferences (HARP)

HARP (Homothetic Axiom of Revealed Preference) tests whether demand scales proportionally with income. Homothetic preferences mean the consumer buys the same proportions of goods regardless of budget level-only the scale changes.

from prefgraph import BehaviorLog, validate_proportional_scaling

# log from Tutorial 1
result = validate_proportional_scaling(log)

if result.is_consistent:
    print("Homothetic preferences: demand scales proportionally")
else:
    print(f"Non-homothetic: {len(result.violations)} scaling violations")
    print(f"Max expenditure ratio product: {result.max_cycle_product:.3f}")

Output:

Non-homothetic: 3 scaling violations
Max expenditure ratio product: 1.234

When HARP Matters

HARP is a stronger requirement than GARP. Use it when:

  • Aggregating demand across different income levels

  • Extrapolating demand to unobserved budget levels

  • Testing constant-returns-to-scale demand models

  • Validating Cobb-Douglas or CES utility assumptions

HARP vs GARP

Condition

GARP

HARP

Consistent ordinal preferences

Required

Required

Proportional budget shares

Not required

Required

Typical pass rate (field data)

5-15%

1-5%

Part 2: The Lancaster Model

The Lancaster model assumes utility derives from characteristics (e.g., nutrition) rather than products directly: \(U(x) = u(Zx)\) where \(Z\) maps products to characteristics.

When Does Lancaster Help?

CCEI Increases

CCEI Decreases

Consumer optimizes over characteristics

Consumer has product-specific preferences

Products are imperfect substitutes for characteristics

Brand loyalty matters

Characteristics matrix is well-specified

Characteristics matrix is wrong

import numpy as np
from prefgraph import transform_to_characteristics, validate_consistency

# Nutritional characteristics: [Protein, Carbs, Fat, Sodium]
Z = np.array([
    [0, 39, 0, 15],      # Soda
    [8, 12, 8, 120],     # Milk
    [9, 49, 3, 490],     # Bread
    [25, 1, 33, 620],    # Cheese
    # ... etc
])

lancaster_log = transform_to_characteristics(log, Z)
result = validate_consistency(lancaster_log)
print(f"Lancaster consistent: {result.is_consistent}")

Output:

Lancaster consistent: True

Results Comparison

Product Space vs Characteristics Space

Metric

Product Space

Characteristics Space

Mean CCEI

~0.84

~0.89 (+5%)

GARP pass rate

~5%

~8% (+60%)

Part 3: Utility Recovery

For GARP-consistent households, we can recover the utility function that rationalizes their choices using Afriat’s theorem.

from prefgraph import fit_latent_values

# For a GARP-consistent household
result = fit_latent_values(log)

if result.success:
    print(f"Recovery successful!")
    print(f"Utility values: {result.utility_values[:5]}...")  # First 5
    print(f"Marginal utility of money: {result.lagrange_multipliers[:5]}...")
else:
    print(f"Recovery failed: {result.lp_status}")

Output:

Recovery successful!
Utility values: [0.000e+00 1.234e-05 2.468e-05 3.702e-05 4.936e-05]...
Marginal utility of money: [1.000e-06 1.000e-06 1.000e-06 1.000e-06 1.000e-06]...

Interpreting Results

The recovered values satisfy Afriat’s inequalities:

\[u_s - u_t \leq \lambda_t p_t \cdot (x_s - x_t) \quad \forall s, t\]

Where:

  • \(u_t\) = utility at observation \(t\)

  • \(\lambda_t\) = marginal utility of money at \(t\)

Utility Recovery Interpretation

Value

Meaning

utility_values

Ordinal utility indices (relative ranking matters)

lagrange_multipliers

Marginal utility of money (shadow price of budget)

success=True

A rationalizing utility function exists

success=False

GARP violated; no consistent utility exists

See Also