#!/usr/bin/env python
# coding: utf-8
#
Table of Contents
#
#
# # Importance of giving a convenient period
# This notebook aim to show easily how periods work in OpenFisca.
# We need to initialize a **simulation**.
# In[1]:
from openfisca_france import FranceTaxBenefitSystem
tax_benefit_system = FranceTaxBenefitSystem()
scenario = tax_benefit_system.new_scenario()
scenario.init_single_entity(
period = 2015,
parent1 = dict(
age = 30,
salaire_de_base = 50000,
),
enfants = [
dict(age = 12),
dict(age = 18),
],
)
simulation = scenario.new_simulation()
# A simulation's variable is calculated for a specific period.
# This specific time interval have to be given when calling a variable to avoid computation problem.
#
# ### Variables with monthly formulas
# Some variables are computed over the month.
# For exemple the variable `allocation familiales`.
# If called on an annual basis, an error is displayed :
# In[2]:
simulation.calculate('af', '2015')
# This assertion error :
# "`Requested period 2015 differs from 2015-01 returned by variable af`"
# means exactly the fact that `af` are computed for a month, therefore the variable returned value for `2015-01`.
# But when called on its period (monthly), the result of the variable's formula will be returned
# In[3]:
simulation.calculate('af', '2015-01') #calculate variable af for January 2015
# ### Variable with annual formulas
# Other formulas only works on a annual basis, thus a monthly call will not work, e.g irpp (impôt sur le revenu) :
# In[4]:
simulation.calculate('irpp', '2015-01')
# It must be called on an annual basis :
# In[5]:
simulation.calculate('irpp', '2015') #calculate variable irpp for 2015
# ### Default period
# When a variable is called without period, the simulation's default period is used.
# In[6]:
simulation.period
# Here default simulation period is a year. Thus the variable `irpp` can be computed but not the variable `af`.
# In[7]:
print(simulation.calculate('irpp'))
# In this case simulation.calculate('irpp') is equivalent to simulation.calculate('irpp', '2015')
# In[8]:
print(simulation.calculate('irpp') == simulation.calculate('irpp', '2015'))
# **WARNING** : this demonstration shows the necessity of being aware over which kind of period each measure you want to compute is based on.
#
# ### How to know the definition period of a variable
#
# 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://legislation.openfisca.fr/variables).
#
# The information is located in the code source.
#
# Example for the [irpp](https://legislation.openfisca.fr/variables/irpp), a tax with annual definition, you will find the period at the end of the website page:
#
# ![](irpp_period.png)
# # Solutions
# Specific period calls insure that no errors are made by the user.
# If a annual based variable is asked to be computed monthly, the software returns an error.
#
# 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.
# ### Calculate_add : small to larger period
# The calculate_add method has the same behavior as calculate, except that it sum all variables given their instant of calculus over a period lenght.
# In[9]:
print simulation.calculate_add("af", "2015")
# This result is equivalent to do sum all monthly calculate over the period.
# In[10]:
annual_af = 0 #create annual_af equals to 0
for month in range(1,13): # [1,2,...,11,12]
annual_af += simulation.calculate("af", '2015-{}'.format(month)) #add recursively af for all month in 2014
# In[11]:
print annual_af
# We thus see that annual_af is equal to simulation.calculate_add('af', "2014").
#
# We can test that :
# In[12]:
print simulation.calculate_add('af','2015') == annual_af
# ### Calculate_divide : large to smaller period
# In[13]:
simulation.calculate_divide("irpp", "2015-01")
# In[14]:
simulation.calculate("irpp", "2015")/12
# Be warned, when a variable is calculated on a monthly basis with calculate_divide (or add), the result is stored in cache.
#
# Now you can do :
# In[15]:
simulation.calculate('irpp', '2015-01')
# ### Calculate_add_divide
# Some variables are not constant over the year but you might want it as an average value for each month.
#
# For exemple variable `'ars'` (allocation de rentrée scolaire), is computed only in september. To smooth it over the year, we must use calculate_add_divide. It will simply sum it over a given period, and then divide it over sub-periods of that period.
# In[37]:
simulation.calculate('ars', '2014')/12
# In[17]:
simulation.calculate_add_divide('ars', "2014-08")
# Que fait add_divide ?
# In[32]:
get_ipython().run_line_magic('pinfo2', 'simulation.compute_add_divide')
# # The Concept of Period
# We can also use more exotic period by using the class periods.
#
# Actually when we do : `simulation.calculate('irpp','2015')`, the '2015' string is converted into an object period.
#
# A more explicit way to do this, is : `simulation.calculate('irpp', periods.period('2015'))`
# In[20]:
from openfisca_core import periods # OpenFisca_core is the architecture of OpenFisca
periods.period('2015')
# In[21]:
print(simulation.calculate('irpp', periods.period('2015')))
print(simulation.calculate('irpp', periods.period('2015'))== simulation.calculate('irpp', 2015))
# ### Definition
# We can look at periods docstring to understand how it works :
# In[22]:
print periods.period.__doc__[: 280] #periods.period? would also display the help, suppress the brackets to get full doc
# A *period* is constituted of three parameters:
# - A unit : day, month and year
# - A start instant : the date at which it starts
# - And a size : the number of unit
#
# periods.period('day','2014-03-01', 32) would be a period going from the first of March to the first of april
# ### Computing over several months
# If we want to calculate the 'allocation familiales' from the April to July.
# In[23]:
af_march_to_july = simulation.calculate_add('af' ,periods.period('month', '2015-04', 4))
print af_march_to_july
# A simplificated version of period declaration exists with the symbol: `":"`.
#
# `year-month:n` means n months beginning at the month, year.
#
# Example with `af_march_to_july`:
# In[24]:
af_march_to_july = simulation.calculate_add('af' ,'2015-04:4')
print af_march_to_july
# ### Computing over several years with identique scenario
#
# Computing over several years needs to rethink how we've declared the scenario:
# the starting scenario has, as `period`, one year, `2015`, so it won't be able to compute anything outside this time interval.
#
# The idea is to change the period over which the scenario applies, using the syntax shown previously.
#
# **WARNING : handling the stretching of values **
# Doing that defines the other variables for the entire time interval including their values.
# In[25]:
#we have to give a new scenario
scenario_over_years = tax_benefit_system.new_scenario()
scenario_over_years.init_single_entity(
period = '2014:3', # it means three years starting in 2014
parent1 = dict(
date_naissance = 1975,
salaire_de_base = 50000 * 3 , # if we want 50000 for each of the three years
),
enfants = [
dict(date_naissance = 2001),
dict(date_naissance = 1999),
],
)
simulation_over_years = scenario_over_years.new_simulation()
# **WARNING : handling the age**
# We've changed the variable `age` to `date_naissance` in order that the individuals get older. If we've kept the `age` they would have the same age for the entire period.
#
# Now we can compute the `irpp` with the function previously used : `calculate_add`
# In[26]:
simulation_over_years.calculate_add('irpp', '2014:2') # for 2014 and 2015
# It takes in consideration the legislation change between the two years.
# Therefore it equals the sum of `irpp` for each year but not the double of `irpp` for one year.
# In[27]:
print(simulation_over_years.calculate('irpp', '2015') + simulation_over_years.calculate('irpp', '2014'))
print(simulation_over_years.calculate_add('irpp', '2014')*2)
# These formulas are still working for variables defined on a monthly basis.
# In[28]:
simulation_over_years.calculate_add('af', '2015:2')
# ### Computing over several years changing scenario
#
# You might want to make evolve some given values over the years.
#
# The tool for it will be to use a Python dictionnary.
#
# For example, if you want to give a wage evolution :
# In[29]:
scenario_over_years = tax_benefit_system.new_scenario()
scenario_over_years.init_single_entity(
period = '2014:3',
parent1 = dict(
date_naissance = 1975,
salaire_de_base = {'2014':50000, '2015': 50500, '2016':51000},
),
enfants = [
dict(date_naissance = 2001),
dict(date_naissance = 1999),
],
)
simulation_over_years = scenario_over_years.new_simulation()
# In[30]:
simulation_over_years.calculate_add('irpp', '2014:3') # for 2014, 2015 and 2016
# In[ ]:
# In[ ]:
# In[ ]:
# In[ ]:
# In[ ]:
# In[ ]:
# *Command line to get the Notebook's Table of Contents:*
# In[31]:
get_ipython().run_cell_magic('javascript', '', "$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')\n")