euromod.eu_euromod.calibrate.estimation

The tax-benefit schedule and how it is estimated.

The schedule

A country’s tax-benefit system is summarised by the function of Heathcote, Storesletten and Violante (HSV). For a household with gross income y, measured in multiples of mean income, disposable income is (1 - lambda) * y**(1 - tau), so the average net tax rate is:

1 - (1 - lambda) * y**(-tau)

lambda is the net tax rate at mean income (the level) and tau measures how fast the rate rises with income (the progressivity; tau = 0 is a flat rate). Benefits are included, so the rate is negative for households that receive more than they pay.

The estimator

Taking logs makes the schedule linear:

log(disposable) = log(1 - lambda) + (1 - tau) * log(y)

fit_hsv() estimates it by weighted least squares, with the survey weights dwt. There is a closed-form solution, so nothing is optimised numerically and the result does not depend on starting values.

To compare a reform with a baseline it is often useful to hold the level fixed and let only the progressivity move. With lambda_fixed the intercept is known, and tau comes from a regression through the origin of log(disposable) - log(1 - lambda) on log(y).

Household types are subsets of one sample (HOUSEHOLD_TYPES). They share its income scale, so their estimates can be compared with each other.

Below are listed the main public classes of the euromod.eu_euromod.calibrate.estimation module.

Function

binned_means(sample, bins)

Mean income and mean net tax rate in equally wide income bins.

fit_diagnostics(sample, fit, bins)

How well a fitted schedule describes a sample.

fit_hsv(sample, *, lambda_fixed)

Estimate the HSV schedule on a household sample.

hsv(income, lambda_, tau)

Average net tax rate of the HSV schedule.

marginal_hsv(income, lambda_, tau)

Marginal net tax rate of the HSV schedule: the share of an extra euro of gross

net_tax_rate_at_mean_income(sample, band)

Observed net tax rate of households at mean income.

pool(samples)

Pool the household samples of several countries, e.g. into a euro-area sample.

select_households(sample, household_type)

The households of one type.

to_calibration(fits, *, system, dataset, model_version, constants)

Export fitted schedules as a euromod.calibrate.Calibration.

Attributes

HOUSEHOLD_TYPES

-

Functions

euromod.eu_euromod.calibrate.estimation.binned_means(sample, bins=80)

Mean income and mean net tax rate in equally wide income bins.

Used to judge the shape of the fitted schedule without the scatter of individual households.

Parameters:
  • sample (pandas.DataFrame) – A household sample.

  • bins (int) – Number of bins between the lowest and highest income_norm.

Returns:

One row per non-empty bin: income_norm and net_tax_rate (plain means over the households in the bin), dwt_sum (their total weight) and n (their number).

Return type:

pandas.DataFrame

euromod.eu_euromod.calibrate.estimation.fit_diagnostics(sample, fit, bins=80)

How well a fitted schedule describes a sample.

Parameters:
  • sample (pandas.DataFrame) – The household sample the schedule was fitted on.

  • fit (dict) – Result of fit_hsv().

  • bins (int) – Number of income bins for the binned errors.

Returns:

  • net_tax_rate_at_mean: see net_tax_rate_at_mean_income().

  • rmse, mae: weighted errors of the net tax rate, household by household. Dominated by the spread of households around the schedule.

  • rmse_binned, mae_binned: the same against binned_means(), weighted by bin population. These measure the shape of the schedule.

  • gini_gross, gini_disposable: observed Gini coefficients.

  • gini_fitted: Gini of the disposable income the fitted schedule assigns to the same gross incomes. The gap to gini_disposable is the redistribution the two-parameter schedule does not capture.

Return type:

dict

euromod.eu_euromod.calibrate.estimation.fit_hsv(sample, *, lambda_fixed=None)

Estimate the HSV schedule on a household sample.

Parameters:
  • sample (pandas.DataFrame) – A household sample with income_norm, disposable_norm and dwt.

  • lambda_fixed (float, optional) – Hold the level at this value and estimate only tau.

Returns:

lambda, tau, se_tau and n, plus

  • se_intercept (standard error of log(1 - lambda)), se_lambda and r2 when both parameters are estimated;

  • r2_uncentered when lambda is fixed.

Standard errors are the classical ones of weighted least squares.

Return type:

dict

Example

>>> fit = fit_hsv(sample)
>>> fit["lambda"], fit["tau"]
(0.1925, 0.1631)
>>> fit_hsv(select_households(sample, "married"))["tau"]
0.1918
euromod.eu_euromod.calibrate.estimation.hsv(income, lambda_, tau)

Average net tax rate of the HSV schedule.

Parameters:
  • income (float or array-like) – Gross income in multiples of mean income.

  • lambda (float) – Level: the net tax rate at mean income.

  • tau (float) – Progressivity.

Return type:

float or numpy.ndarray

Example

>>> hsv(np.array([0.5, 1.0, 2.0]), 0.1925, 0.1631)
array([0.0958, 0.1925, 0.2788])
euromod.eu_euromod.calibrate.estimation.marginal_hsv(income, lambda_, tau)

Marginal net tax rate of the HSV schedule: the share of an extra euro of gross income that does not reach disposable income.

Parameters:
Return type:

float or numpy.ndarray

euromod.eu_euromod.calibrate.estimation.net_tax_rate_at_mean_income(sample, band=0.05)

Observed net tax rate of households at mean income.

A weighted straight line is fitted through the net tax rates of households whose income is within band of the mean, and read off at the mean. This is the data counterpart of lambda.

Parameters:
  • sample (pandas.DataFrame) – A household sample.

  • band (float) – Half-width of the income window around 1.0.

Returns:

If no household falls in the window, the rate of the closest household.

Return type:

float

euromod.eu_euromod.calibrate.estimation.pool(samples)

Pool the household samples of several countries, e.g. into a euro-area sample.

Each country keeps its own income scale (1.0 is that country’s mean income) and its own survey weights, so a country counts in proportion to its population.

Parameters:

samples (dict) – Household samples by system name, e.g. {"AT_2022": ..., "BE_2022": ...}.

Returns:

All households, with a country column.

Return type:

pandas.DataFrame

euromod.eu_euromod.calibrate.estimation.select_households(sample, household_type)

The households of one type.

Parameters:
Return type:

pandas.DataFrame

euromod.eu_euromod.calibrate.estimation.to_calibration(fits, *, system, dataset='', model_version='', constants=None)

Export fitted schedules as a euromod.calibrate.Calibration.

The Calibration evaluates the schedule with a numba-compiled function, which can be called from other compiled code, and can be saved to and loaded from JSON. It needs sympy and numba (pip install euromod[calibrate]).

Parameters:
  • fits (dict) – One result of fit_hsv(), or several by household type: {"all": fit, "married": fit_married}.

  • system (str) – Name of the system the fits belong to.

  • dataset (str, optional) – Recorded in the calibration.

  • model_version (str, optional) – Recorded in the calibration.

  • constants (dict, optional) – Constants that were overridden in the run, as passed to simulate().

Returns:

With one group per household type.

Return type:

euromod.calibrate.Calibration

Example

>>> cal = to_calibration(fit_hsv(sample), system="PT_2022")
>>> cal(np.array([0.5, 1.0, 2.0]))
array([0.0958, 0.1925, 0.2788])
>>> cal.to_json("PT_2022_hsv.json")
>>> schedule = cal.numba_function          # schedule(income, lambda_t, tau)

Attributes

euromod.eu_euromod.calibrate.estimation.HOUSEHOLD_TYPES