euromod.eu_euromod.calibrate.estimation ======================================= .. py:module:: euromod.eu_euromod.calibrate.estimation .. autoapi-nested-parse:: 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) :func:`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 (:data:`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. .. list-table:: **Function** :header-rows: 0 :widths: auto :class: summarytable * - :py:obj:`binned_means `\ (sample, bins) - Mean income and mean net tax rate in equally wide income bins. * - :py:obj:`fit_diagnostics `\ (sample, fit, bins) - How well a fitted schedule describes a sample. * - :py:obj:`fit_hsv `\ (sample, \*, lambda\_fixed) - Estimate the HSV schedule on a household sample. * - :py:obj:`hsv `\ (income, lambda\_, tau) - Average net tax rate of the HSV schedule. * - :py:obj:`marginal_hsv `\ (income, lambda\_, tau) - Marginal net tax rate of the HSV schedule: the share of an extra euro of gross * - :py:obj:`net_tax_rate_at_mean_income `\ (sample, band) - Observed net tax rate of households at mean income. * - :py:obj:`pool `\ (samples) - Pool the household samples of several countries, e.g. into a euro-area sample. * - :py:obj:`select_households `\ (sample, household\_type) - The households of one type. * - :py:obj:`to_calibration `\ (fits, \*, system, dataset, model\_version, constants) - Export fitted schedules as a :class:`euromod.calibrate.Calibration`. .. list-table:: **Attributes** :header-rows: 0 :widths: auto :class: summarytable * - :py:obj:`HOUSEHOLD_TYPES ` - \- Functions --------- .. py:function:: 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. :param sample: A household sample. :type sample: pandas.DataFrame :param bins: Number of bins between the lowest and highest ``income_norm``. :type bins: :obj:`int` :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). :rtype: pandas.DataFrame .. py:function:: fit_diagnostics(sample, fit, bins=80) How well a fitted schedule describes a sample. :param sample: The household sample the schedule was fitted on. :type sample: pandas.DataFrame :param fit: Result of :func:`fit_hsv`. :type fit: dict :param bins: Number of income bins for the binned errors. :type bins: :obj:`int` :returns: - ``net_tax_rate_at_mean``: see :func:`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 :func:`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. :rtype: dict .. py:function:: fit_hsv(sample, *, lambda_fixed=None) Estimate the HSV schedule on a household sample. :param sample: A household sample with ``income_norm``, ``disposable_norm`` and ``dwt``. :type sample: pandas.DataFrame :param lambda_fixed: Hold the level at this value and estimate only ``tau``. :type lambda_fixed: float, optional :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. :rtype: dict .. rubric:: Example >>> fit = fit_hsv(sample) >>> fit["lambda"], fit["tau"] (0.1925, 0.1631) >>> fit_hsv(select_households(sample, "married"))["tau"] 0.1918 .. py:function:: hsv(income, lambda_, tau) Average net tax rate of the HSV schedule. :param income: Gross income in multiples of mean income. :type income: float or array-like :param lambda_: Level: the net tax rate at mean income. :type lambda_: float :param tau: Progressivity. :type tau: float :rtype: float or numpy.ndarray .. rubric:: Example >>> hsv(np.array([0.5, 1.0, 2.0]), 0.1925, 0.1631) array([0.0958, 0.1925, 0.2788]) .. py:function:: 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. :param income: As in :func:`hsv`. :param lambda_: As in :func:`hsv`. :param tau: As in :func:`hsv`. :rtype: float or numpy.ndarray .. py:function:: 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``. :param sample: A household sample. :type sample: pandas.DataFrame :param band: Half-width of the income window around 1.0. :type band: float :returns: If no household falls in the window, the rate of the closest household. :rtype: float .. py:function:: 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. :param samples: Household samples by system name, e.g. ``{"AT_2022": ..., "BE_2022": ...}``. :type samples: dict :returns: All households, with a ``country`` column. :rtype: pandas.DataFrame .. py:function:: select_households(sample, household_type) The households of one type. :param sample: A household sample. :type sample: pandas.DataFrame :param household_type: A key of :data:`HOUSEHOLD_TYPES`, or any condition on the sample's columns, e.g. ``"hh_size == 1"``. :type household_type: :obj:`str` :rtype: pandas.DataFrame .. py:function:: to_calibration(fits, *, system, dataset='', model_version='', constants=None) Export fitted schedules as a :class:`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]``). :param fits: One result of :func:`fit_hsv`, or several by household type: ``{"all": fit, "married": fit_married}``. :type fits: dict :param system: Name of the system the fits belong to. :type system: :obj:`str` :param dataset: Recorded in the calibration. :type dataset: :obj:`str`, optional :param model_version: Recorded in the calibration. :type model_version: :obj:`str`, optional :param constants: Constants that were overridden in the run, as passed to :func:`~euromod.eu_euromod.calibrate.simulate`. :type constants: :obj:`dict`, optional :returns: With one group per household type. :rtype: euromod.calibrate.Calibration .. rubric:: 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 ---------- .. py:data:: HOUSEHOLD_TYPES