{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "

Table of Contents

\n", "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Importance of giving a convenient period" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook aim to show easily how periods work in OpenFisca. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need to initialize a **simulation**." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from openfisca_core.simulation_builder import SimulationBuilder\n", "from openfisca_france import FranceTaxBenefitSystem\n", "\n", "tax_benefit_system = FranceTaxBenefitSystem()\n", "\n", "\n", "TEST_CASE = {\n", " 'individus': {\n", " 'parent1': {\n", " 'age': {'2015': 30},\n", " 'salaire_de_base': {'2015': 50000}\n", " },\n", " 'enfant1': {\n", " 'age': {'2015': 12}\n", " },\n", " 'enfant2': {\n", " 'age': {'2015': 18}\n", " }\n", " },\n", " 'familles': {\n", " 'famille1': {\n", " 'parents': ['parent1'],\n", " 'enfants': ['enfant1', 'enfant2']\n", " }\n", " },\n", " 'menages': {\n", " 'menage1': {\n", " 'personne_de_reference': ['parent1'],\n", " 'enfants': ['enfant1', 'enfant2']\n", " }\n", " },\n", " 'foyers_fiscaux': {\n", " 'foyer_fiscal1': {\n", " 'declarants': ['parent1'],\n", " 'personnes_a_charge': ['enfant1', 'enfant2']\n", " }\n", " }\n", "}\n", "\n", "simulation_builder = SimulationBuilder()\n", "simulation = simulation_builder.build_from_entities(tax_benefit_system, TEST_CASE)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A simulation's variable is calculated for a specific period. \n", "This specific time interval have to be given when calling a variable to avoid computation problem.\n", "\n", "### Variables with monthly formulas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some variables are computed over the month. \n", "For exemple the variable `af` (family allowance). \n", "If called on an annual basis, an error is displayed: " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unable to compute variable 'af' for period 2015: 'af' must be computed for a whole month. You can use the ADD option to sum 'af' over the requested period, or change the requested period to 'period.first_month'.\n" ] } ], "source": [ "try:\n", " simulation.calculate('af', '2015')\n", "except Exception as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This error:\n", "```\n", "Unable to compute variable 'af' for period 2015: 'af' must be computed for a whole month. You can use the ADD option to sum 'af' over the requested period, or change the requested period to 'period.first_month'.\n", "```\n", "means exactly the fact that `af` are computed for a month, therefore its '2015' calculation period should be changed for a specific month." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When called on its period (monthly), the result of the variable's formula will be returned:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([129.99], dtype=float32)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation.calculate('af', '2015-01') # calculate variable af for January 2015" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Variable with annual formulas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other formulas only works on a annual basis, thus a monthly call will not work, e.g `irpp` (income tax) :" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unable to compute variable 'irpp' for period 2015-01: 'irpp' must be computed for a whole year. You can use the DIVIDE option to get an estimate of irpp by dividing the yearly value by 12, or change the requested period to 'period.this_year'.\n" ] } ], "source": [ "try:\n", " simulation.calculate('irpp', period = '2015-01')\n", "except Exception as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It must be called on an annual basis :" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-2401.], dtype=float32)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation.calculate('irpp', period = '2015') # calculate variable irpp for 2015" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**WARNING** : this demonstration shows the necessity of being aware over which kind of period each measure you want to compute is based on.\n", "\n", "### How to know the definition period of a variable\n", "\n", "If you've forgotten over which kind of period (year or month) your variable is defined in the legislation, you may check in the [legislation explorer](https://fr.openfisca.org/legislation).\n", "\n", "Example for the  [irpp](https://fr.openfisca.org/legislation/irpp), a tax with annual definition, you will find the period on the website page, e.g.:\n", "```\n", "irpp\n", "\n", "(...)\n", "\n", "This variable applies to the entity foyer_fiscal.\n", "\n", "It has a definition period of a year.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Solutions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Specific period calls insure that no errors are made by the user. \n", "If a annual based variable is asked to be computed monthly, the software returns an error.\n", "\n", "But there is solutions to get the result of a given variable on another kind of period, a annual based variable over a month for example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Calculate_add: small to larger period" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `calculate_ad` method has the same behavior as `calculat`, except that it sum all variables given their instant of calculus over a period lenght." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1559.88], dtype=float32)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation.calculate_add(\"af\", \"2015\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This result is equivalent to do sum all monthly calculate over the period." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1559.88], dtype=float32)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "annual_af = 0 # create annual_af equals to 0\n", "for month in range(1,13): # [1,2,...,11,12]\n", " annual_af += simulation.calculate(\"af\", '2015-{}'.format(month)) # add recursively af for all month in 2014\n", "annual_af" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We thus see that annual_af is equal to simulation.calculate_add('af', \"2014\").\n", "\n", "We can test that:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ True])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation.calculate_add('af','2015') == annual_af" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Calculate_divide : large to smaller period" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-200.08333], dtype=float32)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation.calculate_divide(\"irpp\", \"2015-01\")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-200.08333], dtype=float32)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation.calculate(\"irpp\", \"2015\") / 12" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# The Concept of Period" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also use more exotic period by using the class periods. \n", "\n", "Actually when we do: `simulation.calculate('irpp','2015')`, the '2015' string is converted into an object period. \n", "\n", "A more explicit way to do this, is: `simulation.calculate('irpp', periods.period('2015'))`" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Period(('year', Instant((2015, 1, 1)), 1))" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from openfisca_core import periods # openfisca_core is the architecture of OpenFisca\n", "periods.period('2015')" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[-2401.]\n", "[ True]\n" ] } ], "source": [ "print(simulation.calculate('irpp', periods.period('2015')))\n", "print(simulation.calculate('irpp', periods.period('2015')) == simulation.calculate('irpp', 2015))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Definition\n", "We can look at periods docstring to understand how it works:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Return a new period, aka a triple (unit, start_instant, size).\n", "\n", " >>> period('2014')\n", " Period((YEAR, Instant((2014, 1, 1)), 1))\n", " >>> period('year:2014')\n", " Period((YEAR, Instant((2014, 1, 1)), 1))\n", "\n", " >>> period('2014-2')\n", " Period((MONTH, Instant((2014, 2, 1)), 1))\n", " >>> period('2014-02')\n", " Period((MONTH, Instant((2014, 2, 1)), 1))\n", " >>> period('month:2014-2')\n", " Period((MONTH, Instant((2014, 2, 1)), 1))\n", "\n", " >>> period('year:2014-2')\n", " Period((YEAR, Instant((2014, 2, 1)), 1))\n", " \n" ] } ], "source": [ "print(periods.period.__doc__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `Period` object is initialized with three parameters:\n", "- A unit: day, month and year\n", "- A start instant: the date at which it starts\n", "- And a size: the number of unit \n", "\n", "`periods.Period('day', periods.Instant((2014, 3, 01)), 32)` would be a period going from the first of March to the first of April." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('day', Instant((2014, 3, 1)), 32)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "period = periods.Period(('day', periods.Instant((2014, 3, 1)), 32)) \n", "period.unit, period.start, period.size" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Computing over several months" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to calculate the `af` (family allowance) from April to July." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[519.18]\n" ] } ], "source": [ "af_april_to_july = simulation.calculate_add(\n", " 'af', \n", " period = periods.Period(('month', periods.Instant((2014, 3, 1)), 4))\n", ")\n", "print(af_april_to_july)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A simplificated version of period declaration exists with the symbol: `\":\"`.\n", "\n", "`month:year-month:n` means n months beginning at the month, year.\n", "\n", "Example with `af_april_to_july`:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[519.96]\n" ] } ], "source": [ "af_april_to_july = simulation.calculate_add('af', period = periods.period(\"month:2014-04:4\"))\n", "print(af_april_to_july)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A simplified instant declaration of instant also exists " ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Instant((2014, 1, 1))" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "periods.instant(\"2014-01\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Computing over several years with identique simulation\n", "\n", "Computing over several years needs to rethink how we've declared the simulation: \n", "the starting simulation has, as input data `period`, one year, `2015`, so it won't be able to compute anything outside this time interval." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Income tax on 2014 [0.]\n", "Income tax on 2015 [-2401.]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Income tax on 2016 [0.]\n" ] } ], "source": [ "print('Income tax on 2014', simulation.calculate('irpp', '2014'))\n", "print('Income tax on 2015', simulation.calculate('irpp', '2015'))\n", "print('Income tax on 2016', simulation.calculate('irpp', '2016'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The idea is to change the period over which those input data apply and stretch their values using the syntax shown previously." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Income tax on 2014 [-2413.]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Income tax on 2015 [-2401.]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Income tax on 2016 [-2391.]\n" ] } ], "source": [ "# We have to initialise a new simulation\n", "TEST_CASE_OVER_YEARS = {\n", " 'individus': {\n", " 'parent1': {\n", " 'date_naissance': {'ETERNITY': 1975},\n", " 'salaire_de_base': {'year:2014:3': 50000 * 3} # three years starting in 2014\n", " # multiplication by 3 is need so salaire de base is 50000 € for each of the three years\n", " },\n", " 'enfant1': {\n", " 'date_naissance': {'ETERNITY': 2001} # a birth date doesn't change over time\n", " },\n", " 'enfant2': {\n", " 'date_naissance': {'ETERNITY': 1999}\n", " }\n", " },\n", " 'familles': {\n", " 'famille1': {\n", " 'parents': ['parent1'],\n", " 'enfants': ['enfant1', 'enfant2']\n", " }\n", " },\n", " 'menages': {\n", " 'menage1': {\n", " 'personne_de_reference': ['parent1'],\n", " 'enfants': ['enfant1', 'enfant2']\n", " }\n", " },\n", " 'foyers_fiscaux': {\n", " 'foyer_fiscal1': {\n", " 'declarants': ['parent1'],\n", " 'personnes_a_charge': ['enfant1', 'enfant2']\n", " }\n", " }\n", "}\n", "\n", "simulation_builder = SimulationBuilder()\n", "simulation_over_years = simulation_builder.build_from_entities(tax_benefit_system, TEST_CASE_OVER_YEARS)\n", "\n", "print('Income tax on 2014', simulation_over_years.calculate('irpp', '2014'))\n", "print('Income tax on 2015', simulation_over_years.calculate('irpp', '2015'))\n", "print('Income tax on 2016', simulation_over_years.calculate('irpp', '2016'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**WARNING : handling the age** \n", "We've changed the variable `age` to `date_naissance` (birth date) in order that the individuals get older. If we've kept the `age` they would have the same age for the entire period.\n", "\n", "Now we can compute the `irpp` with the function previously used : `calculate_add`" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-4814.], dtype=float32)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation_over_years.calculate_add('irpp', period = 'year:2014-01:2') # for 2014 and 2015" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It takes in consideration the legislation change between the two years. \n", "Therefore it equals the sum of `irpp` for each year but not the double of `irpp` for one year." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[-4814.]\n", "[-4826.]\n" ] } ], "source": [ "print(simulation_over_years.calculate('irpp', '2015') + simulation_over_years.calculate('irpp', '2014'))\n", "print(simulation_over_years.calculate_add('irpp', '2014') * 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These formulas are still working for variables defined on a monthly basis." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.], dtype=float32)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation_over_years.calculate_add('af', 'month:2015-01:2')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Computing over several years changing simulation\n", "\n", "You might want to make evolve some given values over the years.\n", "\n", "The tool for it will be to use a Python dictionnary.\n", "\n", "For example, if you want to give a wage evolution:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "TEST_CASE_MULTIPLE_YEARS = {\n", " 'individus': {\n", " 'parent1': {\n", " 'date_naissance': {'ETERNITY': 1975},\n", " 'salaire_de_base': {\n", " '2014': 50000, \n", " '2015': 50500, \n", " '2016': 51000\n", " }\n", " },\n", " 'enfant1': {\n", " 'date_naissance': {'ETERNITY': 2001}\n", " },\n", " 'enfant2': {\n", " 'date_naissance': {'ETERNITY': 1999}\n", " }\n", " },\n", " 'familles': {\n", " 'famille1': {\n", " 'parents': ['parent1'],\n", " 'enfants': ['enfant1', 'enfant2']\n", " }\n", " },\n", " 'menages': {\n", " 'menage1': {\n", " 'personne_de_reference': ['parent1'],\n", " 'enfants': ['enfant1', 'enfant2']\n", " }\n", " },\n", " 'foyers_fiscaux': {\n", " 'foyer_fiscal1': {\n", " 'declarants': ['parent1'],\n", " 'personnes_a_charge': ['enfant1', 'enfant2']\n", " }\n", " }\n", "}\n", "\n", "simulation_builder = SimulationBuilder()\n", "simulation_multiple_years = simulation_builder.build_from_entities(tax_benefit_system, TEST_CASE_MULTIPLE_YEARS)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-7363.], dtype=float32)" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simulation_multiple_years.calculate_add('irpp', 'year:2014:3') # for 2014, 2015 and 2016" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Command line to get the Notebook's Table of Contents:*" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%javascript\n", "$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 1 }