Skip to content

TheoreticalSimulator

A class for performing theoretical simulations.

This class provides methods for initializing a base case, simulating the base case, and plotting the results.

Attributes:

Name Type Description
logger Logger

A logger for logging messages.

Source code in bozio_wasmer_simulations/simulation/theoretical/base.py
class TheoreticalSimulator:
    """
    A class for performing theoretical simulations.

    This class provides methods for initializing a base case, simulating the base case, and plotting the results.

    Attributes:
        logger (logging.Logger):
            A logger for logging messages.

    """

    # Initialisation
    def __init__(
        self,
        log_filename: Optional[os.PathLike] = os.path.join(
            FILE_PATH.parents[3], "logs/theoretical_simulation.log"
        ),
    ) -> None:
        """
        Constructs all the necessary attributes for the EmpiricalSimulator object.

        Args:
            log_filename (os.PathLike, optional): The path to the log file. Defaults to os.path.join(FILE_PATH.parents[3], 'logs/empirical_simulation.log').

        """
        # Initialisation du logger
        self.logger = _init_logger(filename=log_filename)

    # Fonction auxiliaire de calcul de la valeur du SMIC
    def value_smic(self, year: int) -> float:
        """
        Calculates the value of the SMIC for the given year.

        Args:
            year (int):
                The year for which the SMIC value is calculated.

        Returns:
            (float): The value of the SMIC for the given year.
        """
        # Initialisation du système socio-fiscal contenant les valeurs de SMIC en paramètres
        tax_benefit_system = FranceTaxBenefitSystem()
        value_smic = sum(
            [
                tax_benefit_system.get_parameters_at_instant(
                    instant=f"{year}-{month}"
                ).marche_travail.salaire_minimum.smic.smic_b_mensuel
                for month in [str(m).zfill(2) for m in range(1, 13)]
            ]
        )
        # Logging
        self.logger.info(f"The SMIC value computed for {year} is {value_smic} €")

        return value_smic

    # Initialisation d'un cas de base pour réaliser une simulation
    def init_base_case(
        self, year: int, simulation_step_smic: float, simulation_max_smic: float
    ) -> None:
        """
        Initializes a base case for simulation.

        Args:
            year (int):
                The year for which the simulation is performed.
            simulation_step_smic (float):
                The step size for the simulation, as a multiple of the SMIC value.
            simulation_max_smic (float):
                The maximum value for the simulation, as a multiple of the SMIC value.
        """
        # Initialisation du système socio-fiscal contenant les valeurs de SMIC en paramètres
        tax_benefit_system = FranceTaxBenefitSystem()
        # Extraction de la valeur moyenne de SMIC sur l'année
        value_smic = self.value_smic(year=year)
        # Calcul de la valeur maximale de la simulation et de la valeur du pas
        simulation_max = simulation_max_smic * value_smic
        simulation_step = simulation_step_smic * value_smic
        # Calcul du nombre d'observations dans la simulation entre le min (1 SMIC) et le max avec le pas spécifié
        simulation_count = ceil((simulation_max - value_smic) / simulation_step) + 1
        # Définition des caractéristiques de l'individu
        self.base_case = {
            "individus": {
                "individu_1": {
                    "effectif_entreprise": {year: 200},
                    "depcom_entreprise": {year: "93001"},
                    "contrat_de_travail_debut": {year: "2009-03-16"},
                    "heures_remunerees_volume": {year: 1820},
                    "prime_exceptionnelle_pouvoir_achat": {year: 0},
                    "quotite_de_travail": {year: 12},
                    "prime_partage_valeur_exoneree": {year: 0},
                    "prime_partage_valeur_non_exoneree": {year: 0},
                    "age": {year: 40},
                    "secteur_activite_employeur": {
                        year: "non_agricole"
                    },  # {year : TypesSecteurActivite.non_agricole},
                    "exoneration_cotisations_employeur_tode_eligibilite": {year: False},
                    "choix_exoneration_cotisations_employeur_agricole": {year: False},
                    "travailleur_occasionnel_agricole": {year: False},
                    "zone_restructuration_defense": {year: False},
                    "zone_revitalisation_rurale": {year: False},
                    "categorie_salarie": {
                        year: "prive_non_cadre"
                    },  # {year : TypesCategorieSalarie.prive_non_cadre},
                    "contrat_de_travail": {
                        year: "temps_plein"
                    },  # {year : TypesContratDeTravail.temps_plein},
                    "contrat_de_travail_fin": {year: "2099-12-31"},
                    "contrat_de_travail_type": {
                        year: "cdi"
                    },  # {year : TypesContrat.cdi},
                    "salarie_regime_alsace_moselle": {year: False},
                    #'salaire_de_base'
                    "remuneration_apprenti": {year: 0},
                    "apprentissage_contrat_debut": {year: "1970-01-01"},
                    "apprenti": {year: False},
                    "stage_duree_heures": {year: 0},
                    "stage_gratification": {year: 0},
                    "taux_versement_transport": {year: 0.032},
                    "taux_accident_travail": {year: 0.0212},
                }
            },
            "menages": {
                "menage_1": {
                    "personne_de_reference": ["individu_1"],
                    "depcom": {year: "93001"},
                },
            },
            "familles": {"famille_1": {"parents": ["individu_1"]}},
            "foyers_fiscaux": {"foyer_fiscal_1": {"declarants": ["individu_1"]}},
            "axes": [
                [
                    {
                        "count": simulation_count,
                        "name": "salaire_de_base",
                        "min": value_smic,
                        "max": simulation_max,
                        "period": year,
                    }
                ]
            ],
        }

        # Logging
        self.logger.info("Successfully initialized a test case")

    # Fonction auxilaire d'itération d'une simulation sur un cas
    def base_case_simulation(
        self, tax_benefit_system: TaxBenefitSystem, year: int, list_var_simul: List[str]
    ) -> pd.DataFrame:
        """
        Performs a simulation on the base case.

        Args:
            tax_benefit_system (TaxBenefitSystem):
                The tax-benefit system to use for the simulation.
            year (int):
                The year for which the simulation is performed.
            list_var_simul (List[str]):
                A list of variables to simulate.

        Returns:
            (pd.DataFrame): A dataframe containing the results of the simulation.
        """
        # Initialisation des paramètres de la simulation
        simulation_builder = SimulationBuilder()
        simulation = simulation_builder.build_from_entities(
            tax_benefit_system, self.base_case
        )
        # Initialisation du dictionnaire résultat
        dict_simul = {}
        # Itération sur la liste des variables à simuler
        for variable in list_var_simul:
            dict_simul[variable] = simulation.calculate_add(variable, year)
            # Logging
            self.logger.info(f"Successfully simulated {variable} for period {year}")
        # Conversion en dataFrame
        data_simul = pd.DataFrame(dict_simul)

        return data_simul

    # Fonction auxiliaire de tracé des graphiques
    def plot(
        self,
        data: pd.DataFrame,
        x: str,
        hue: Union[str, List[str]],
        x_label: Optional[Union[str, None]] = None,
        y_label: Optional[Union[str, None]] = None,
        hue_label: Optional[Union[str, None]] = None,
        labels: Optional[Dict[str, str]] = {},
        export_key: Optional[Union[os.PathLike, None]] = None,
        show: Optional[bool] = True,
    ) -> None:
        """
        Plots the results of the simulation.

        Args:
            data (pd.DataFrame):
                The data to plot.
            x (str):
                The variable to use for the x-axis.
            hue (Union[str, List[str]]):
                The variable(s) to use for the hue.
            x_label (Optional[Union[str, None]], optional):
                The label for the x-axis. Defaults to None.
            y_label (Optional[Union[str, None]], optional):
                The label for the y-axis. Defaults to None.
            hue_label (Optional[Union[str, None]], optional):
                The label for the hue. Defaults to None.
            labels (Optional[Dict[str, str]], optional):
                A dictionary of labels to apply to the data. Defaults to {}.
            export_key (Optional[Union[os.PathLike, None]], optional):
                The path to save the plot to. Defaults to None.
            show (Optional[bool], optional):
                Whether to display the plot. Defaults to True.

        Returns:
            None
        """
        # Conversion des arguments en liste
        if isinstance(hue, str):
            hue = [hue]

        # Création des noms à partir des labels
        id_name = x_label if (x_label is not None) else x
        var_name = hue_label if (hue_label is not None) else "Variable"
        value_name = y_label if (y_label is not None) else "Valeur"

        # Réorganisation du jeu de données
        data_graph = pd.melt(
            frame=data,
            id_vars=x,
            value_vars=hue,
            var_name=var_name,
            value_name=value_name,
        ).rename({x: id_name}, axis=1)
        # Application des labels
        data_graph[var_name] = (
            data_graph[var_name].map(labels).fillna(data_graph[var_name])
        )

        # Initialisation de la figure
        fig, ax = plt.subplots()
        # Construction du graphique
        sns.lineplot(data=data_graph, x=id_name, y=value_name, hue=var_name)
        # Formattage de l'axe des ordonnées
        if all(["_prop_" in var_hue for var_hue in hue]):
            ax.yaxis.set_major_formatter(PercentFormatter(xmax=1))
        # Exportation
        if export_key is not None:
            plt.savefig(export_key, bbox_inches="tight")

        # Logging
        self.logger.info(f"Successfully build graph")

        if show:
            plt.show()
        else:
            plt.close("all")

base_case_simulation

base_case_simulation(tax_benefit_system: TaxBenefitSystem, year: int, list_var_simul: List[str]) -> DataFrame

Performs a simulation on the base case.

Parameters:

Name Type Description Default
tax_benefit_system TaxBenefitSystem

The tax-benefit system to use for the simulation.

required
year int

The year for which the simulation is performed.

required
list_var_simul List[str]

A list of variables to simulate.

required

Returns:

Type Description
DataFrame

A dataframe containing the results of the simulation.

Source code in bozio_wasmer_simulations/simulation/theoretical/base.py
def base_case_simulation(
    self, tax_benefit_system: TaxBenefitSystem, year: int, list_var_simul: List[str]
) -> pd.DataFrame:
    """
    Performs a simulation on the base case.

    Args:
        tax_benefit_system (TaxBenefitSystem):
            The tax-benefit system to use for the simulation.
        year (int):
            The year for which the simulation is performed.
        list_var_simul (List[str]):
            A list of variables to simulate.

    Returns:
        (pd.DataFrame): A dataframe containing the results of the simulation.
    """
    # Initialisation des paramètres de la simulation
    simulation_builder = SimulationBuilder()
    simulation = simulation_builder.build_from_entities(
        tax_benefit_system, self.base_case
    )
    # Initialisation du dictionnaire résultat
    dict_simul = {}
    # Itération sur la liste des variables à simuler
    for variable in list_var_simul:
        dict_simul[variable] = simulation.calculate_add(variable, year)
        # Logging
        self.logger.info(f"Successfully simulated {variable} for period {year}")
    # Conversion en dataFrame
    data_simul = pd.DataFrame(dict_simul)

    return data_simul

init_base_case

init_base_case(year: int, simulation_step_smic: float, simulation_max_smic: float) -> None

Initializes a base case for simulation.

Parameters:

Name Type Description Default
year int

The year for which the simulation is performed.

required
simulation_step_smic float

The step size for the simulation, as a multiple of the SMIC value.

required
simulation_max_smic float

The maximum value for the simulation, as a multiple of the SMIC value.

required
Source code in bozio_wasmer_simulations/simulation/theoretical/base.py
def init_base_case(
    self, year: int, simulation_step_smic: float, simulation_max_smic: float
) -> None:
    """
    Initializes a base case for simulation.

    Args:
        year (int):
            The year for which the simulation is performed.
        simulation_step_smic (float):
            The step size for the simulation, as a multiple of the SMIC value.
        simulation_max_smic (float):
            The maximum value for the simulation, as a multiple of the SMIC value.
    """
    # Initialisation du système socio-fiscal contenant les valeurs de SMIC en paramètres
    tax_benefit_system = FranceTaxBenefitSystem()
    # Extraction de la valeur moyenne de SMIC sur l'année
    value_smic = self.value_smic(year=year)
    # Calcul de la valeur maximale de la simulation et de la valeur du pas
    simulation_max = simulation_max_smic * value_smic
    simulation_step = simulation_step_smic * value_smic
    # Calcul du nombre d'observations dans la simulation entre le min (1 SMIC) et le max avec le pas spécifié
    simulation_count = ceil((simulation_max - value_smic) / simulation_step) + 1
    # Définition des caractéristiques de l'individu
    self.base_case = {
        "individus": {
            "individu_1": {
                "effectif_entreprise": {year: 200},
                "depcom_entreprise": {year: "93001"},
                "contrat_de_travail_debut": {year: "2009-03-16"},
                "heures_remunerees_volume": {year: 1820},
                "prime_exceptionnelle_pouvoir_achat": {year: 0},
                "quotite_de_travail": {year: 12},
                "prime_partage_valeur_exoneree": {year: 0},
                "prime_partage_valeur_non_exoneree": {year: 0},
                "age": {year: 40},
                "secteur_activite_employeur": {
                    year: "non_agricole"
                },  # {year : TypesSecteurActivite.non_agricole},
                "exoneration_cotisations_employeur_tode_eligibilite": {year: False},
                "choix_exoneration_cotisations_employeur_agricole": {year: False},
                "travailleur_occasionnel_agricole": {year: False},
                "zone_restructuration_defense": {year: False},
                "zone_revitalisation_rurale": {year: False},
                "categorie_salarie": {
                    year: "prive_non_cadre"
                },  # {year : TypesCategorieSalarie.prive_non_cadre},
                "contrat_de_travail": {
                    year: "temps_plein"
                },  # {year : TypesContratDeTravail.temps_plein},
                "contrat_de_travail_fin": {year: "2099-12-31"},
                "contrat_de_travail_type": {
                    year: "cdi"
                },  # {year : TypesContrat.cdi},
                "salarie_regime_alsace_moselle": {year: False},
                #'salaire_de_base'
                "remuneration_apprenti": {year: 0},
                "apprentissage_contrat_debut": {year: "1970-01-01"},
                "apprenti": {year: False},
                "stage_duree_heures": {year: 0},
                "stage_gratification": {year: 0},
                "taux_versement_transport": {year: 0.032},
                "taux_accident_travail": {year: 0.0212},
            }
        },
        "menages": {
            "menage_1": {
                "personne_de_reference": ["individu_1"],
                "depcom": {year: "93001"},
            },
        },
        "familles": {"famille_1": {"parents": ["individu_1"]}},
        "foyers_fiscaux": {"foyer_fiscal_1": {"declarants": ["individu_1"]}},
        "axes": [
            [
                {
                    "count": simulation_count,
                    "name": "salaire_de_base",
                    "min": value_smic,
                    "max": simulation_max,
                    "period": year,
                }
            ]
        ],
    }

    # Logging
    self.logger.info("Successfully initialized a test case")

plot

plot(data: DataFrame, x: str, hue: Union[str, List[str]], x_label: Optional[Union[str, None]] = None, y_label: Optional[Union[str, None]] = None, hue_label: Optional[Union[str, None]] = None, labels: Optional[Dict[str, str]] = {}, export_key: Optional[Union[PathLike, None]] = None, show: Optional[bool] = True) -> None

Plots the results of the simulation.

Parameters:

Name Type Description Default
data DataFrame

The data to plot.

required
x str

The variable to use for the x-axis.

required
hue Union[str, List[str]]

The variable(s) to use for the hue.

required
x_label Optional[Union[str, None]]

The label for the x-axis. Defaults to None.

None
y_label Optional[Union[str, None]]

The label for the y-axis. Defaults to None.

None
hue_label Optional[Union[str, None]]

The label for the hue. Defaults to None.

None
labels Optional[Dict[str, str]]

A dictionary of labels to apply to the data. Defaults to {}.

{}
export_key Optional[Union[PathLike, None]]

The path to save the plot to. Defaults to None.

None
show Optional[bool]

Whether to display the plot. Defaults to True.

True

Returns:

Type Description
None

None

Source code in bozio_wasmer_simulations/simulation/theoretical/base.py
def plot(
    self,
    data: pd.DataFrame,
    x: str,
    hue: Union[str, List[str]],
    x_label: Optional[Union[str, None]] = None,
    y_label: Optional[Union[str, None]] = None,
    hue_label: Optional[Union[str, None]] = None,
    labels: Optional[Dict[str, str]] = {},
    export_key: Optional[Union[os.PathLike, None]] = None,
    show: Optional[bool] = True,
) -> None:
    """
    Plots the results of the simulation.

    Args:
        data (pd.DataFrame):
            The data to plot.
        x (str):
            The variable to use for the x-axis.
        hue (Union[str, List[str]]):
            The variable(s) to use for the hue.
        x_label (Optional[Union[str, None]], optional):
            The label for the x-axis. Defaults to None.
        y_label (Optional[Union[str, None]], optional):
            The label for the y-axis. Defaults to None.
        hue_label (Optional[Union[str, None]], optional):
            The label for the hue. Defaults to None.
        labels (Optional[Dict[str, str]], optional):
            A dictionary of labels to apply to the data. Defaults to {}.
        export_key (Optional[Union[os.PathLike, None]], optional):
            The path to save the plot to. Defaults to None.
        show (Optional[bool], optional):
            Whether to display the plot. Defaults to True.

    Returns:
        None
    """
    # Conversion des arguments en liste
    if isinstance(hue, str):
        hue = [hue]

    # Création des noms à partir des labels
    id_name = x_label if (x_label is not None) else x
    var_name = hue_label if (hue_label is not None) else "Variable"
    value_name = y_label if (y_label is not None) else "Valeur"

    # Réorganisation du jeu de données
    data_graph = pd.melt(
        frame=data,
        id_vars=x,
        value_vars=hue,
        var_name=var_name,
        value_name=value_name,
    ).rename({x: id_name}, axis=1)
    # Application des labels
    data_graph[var_name] = (
        data_graph[var_name].map(labels).fillna(data_graph[var_name])
    )

    # Initialisation de la figure
    fig, ax = plt.subplots()
    # Construction du graphique
    sns.lineplot(data=data_graph, x=id_name, y=value_name, hue=var_name)
    # Formattage de l'axe des ordonnées
    if all(["_prop_" in var_hue for var_hue in hue]):
        ax.yaxis.set_major_formatter(PercentFormatter(xmax=1))
    # Exportation
    if export_key is not None:
        plt.savefig(export_key, bbox_inches="tight")

    # Logging
    self.logger.info(f"Successfully build graph")

    if show:
        plt.show()
    else:
        plt.close("all")

value_smic

value_smic(year: int) -> float

Calculates the value of the SMIC for the given year.

Parameters:

Name Type Description Default
year int

The year for which the SMIC value is calculated.

required

Returns:

Type Description
float

The value of the SMIC for the given year.

Source code in bozio_wasmer_simulations/simulation/theoretical/base.py
def value_smic(self, year: int) -> float:
    """
    Calculates the value of the SMIC for the given year.

    Args:
        year (int):
            The year for which the SMIC value is calculated.

    Returns:
        (float): The value of the SMIC for the given year.
    """
    # Initialisation du système socio-fiscal contenant les valeurs de SMIC en paramètres
    tax_benefit_system = FranceTaxBenefitSystem()
    value_smic = sum(
        [
            tax_benefit_system.get_parameters_at_instant(
                instant=f"{year}-{month}"
            ).marche_travail.salaire_minimum.smic.smic_b_mensuel
            for month in [str(m).zfill(2) for m in range(1, 13)]
        ]
    )
    # Logging
    self.logger.info(f"The SMIC value computed for {year} is {value_smic} €")

    return value_smic