--- title: Plot distribution keywords: fastai sidebar: home_sidebar nb_path: "notebooks/analyses/csg_55_plot_distributions.ipynb" ---
{% raw %}
{% endraw %} {% raw %}
from IPython.core.interactiveshell import InteractiveShell

InteractiveShell.ast_node_interactivity = "all"
{% endraw %} {% raw %}
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import pandas as pd

# import plotly.express as px
import seaborn as sns
from leximpact_socio_fisca_simu_etat.config import Configuration
from leximpact_socio_fisca_simu_etat.copule import (
    copule_to_df,
    read_copule,
    sum_copule_col,
)

config = Configuration(project_name="leximpact-prepare-data")
{% endraw %} {% raw %}
def axis_in_k(ax, xunit="€", yunit="€"):
    """
    Permet d'afficher les valeurs sur les axes de façon plus lisible.
    """
    ax.ticklabel_format(useOffset=False, style="plain")
    # Avoid warning about "FixedLocator"
    ax.xaxis.set_major_locator(mticker.FixedLocator(ax.get_xticks().tolist()))
    xlabels = [f"{x:,}" + "K" + xunit for x in ax.get_xticks() / 1000]
    _ = ax.set_xticklabels(xlabels)
    ylabels = [f"{x:,}" + "K" + yunit for x in ax.get_yticks() / 1000]
    # Avoid warning about "FixedLocator"
    ax.yaxis.set_major_locator(mticker.FixedLocator(ax.get_yticks().tolist()))
    _ = ax.set_yticklabels(ylabels)
{% endraw %} {% raw %}
sample_pop = pd.read_csv(config.get("DATA_OUT") + "sample_pop_ind_csg.csv")
{% endraw %} {% raw %}
sample_pop.columns
{% endraw %} {% raw %}
sample_pop["rfr_pop"] = sample_pop["rfr"] * sample_pop["wprm"]
sample_pop["salaire_de_base_pop"] = sample_pop["salaire_de_base"] * sample_pop["wprm"]
{% endraw %}

Répartition RFR dans POTE

  • Entre 10 millions et 100 millions : 294
  • Entre 1 million et 10 millions : 10 061
  • Entre 500 000 € et 1 million : 22 745
  • Entre 250 000 et 500 000 : 88 849
  • Entre 150 000 et 250 000 : 236 470
{% raw %}
print(
    f"Nombre de personnes du ERFS FPR dont le RFR est de plus que 1 million : {sample_pop.query('rfr > 1_000_000')['rfr'].count()}"
)
print(
    f"Nombre de personnes du ERFS FPR dont le RFR est entre 500 000 et 1 million : {sample_pop.query('rfr < 1_000_000 and rfr > 500000')['rfr'].count()}"
)
print(
    f"Nombre de personnes du ERFS FPR dont le RFR est Entre 250 000 et 500 000 : {sample_pop.query('rfr > 250_000 and rfr < 500000')['rfr'].count()}"
)
print(
    f"Nombre de personnes du ERFS FPR dont le RFR est entre Entre 150 000 et 250 000  : {sample_pop.query('rfr < 250_000 and rfr > 150000')['rfr'].count()}"
)
{% endraw %} {% raw %}
sns.set(rc={"figure.figsize": (20, 8)})
ax = sns.distplot(sample_pop.query("0 < rfr < 200_000")["rfr"])
ax = sns.distplot(
    sample_pop.query("0 < salaire_de_base < 200_000")["salaire_de_base"], ax=ax
)
_ = ax.set_title("Nombre de foyers par tranche de revenu dans l'échantillon ERFS-FPR")
# axis_in_k(ax)
ax.set_xlabel("salaire_de_base (saumon) et rfr (bleu)")
ax.set_ylabel("Nombre de personne")
{% endraw %} {% raw %}
sns.set(rc={"figure.figsize": (20, 8)})
ax = sns.distplot(sample_pop.query("0 < rfr_pop < 10_000_000")["rfr_pop"])
ax = sns.distplot(
    sample_pop.query("0 < salaire_de_base_pop < 10_000_000")["salaire_de_base_pop"],
    ax=ax,
)
_ = ax.set_title(
    "Nombre de foyers par tranche de revenu dans ERFS-FPR, ramené à la population"
)
# axis_in_k(ax)
ax.set_xlabel("salaire_de_base (saumon) et rfr (bleu)")
ax.set_ylabel("Nombre de personne")
{% endraw %}

La tête des courbes n'est pas du tout la même entre l'échantillon ERFS-FPR et quand on le projette sur la population à l'aide du poids "wprm" fournit par l'INSEE.

Attention : les axes ne sont pas sur les mêmes valeurs car la multiplication par WPRM ne change pas le nombre de personne mais augmente leurs revenus.

Quantiles

{% raw %}
sample_pop.rfr_pop.max()
{% endraw %} {% raw %}
nb_quantiles = 100
df_quantiles = sample_pop.query("rfr > 0")["rfr_pop"].quantile(
    [(1 / nb_quantiles) * (i + 1) for i in range(nb_quantiles)]
)
df_quantiles = pd.DataFrame(df_quantiles)
df_quantiles["quantiles"] = df_quantiles.index * 100
df_quantiles["quantiles"] = df_quantiles["quantiles"].astype(int)
df_quantiles
{% endraw %} {% raw %}
ax = sns.barplot(data=df_quantiles, y="rfr_pop", x="quantiles")
_ = ax.set_yscale("log")
_ = ax.set_xticklabels(labels=ax.get_xticklabels(), rotation=90)
_ = ax.set_title(
    "Centiles du RFR ramené à la population d'après l'ERFS-FPR\nEchelle logarithmique"
)
{% endraw %} {% raw %}
df = sample_pop.query("rfr > 500_000")
ax = sns.histplot(data=df, x="rfr", bins=10)
{% endraw %}

Fonction de répartition

  • "Rk": seuil_inférieur,
  • "Nk": nombre de foyers déclarant plus que le seuil / nombre de foyers,
  • "Ark": somme des rfr des foyers déclarant plus que le seuil / nombre de foyers au dessus du seuil,

La "fonction de répartition du RFR" calcul pour 53 seuils:

  • Un ratio entre la somme cumulée des foyers et le nombre total de foyers. => Ce ratio correspond à celui à calculer pour tracer une courbe de Pareto: https://medium.com/swlh/pareto-chart-with-python-5200459ee65c
  • Un ratio entre la somme cumulée des RFR et la somme cumulée des foyers : donc une moyenne cumulative de RFR ?
{% raw %}
df_fdr = pd.read_csv(config.get("COPULE_FOLDER") + "CalibPOTE_2019.csv")
nbff = 39_264_696
df_fdr.columns = ["seuil_rfr", "ratio_nb_foyer", "mean_rfr"]
df_fdr.tail()
len(df_fdr)
{% endraw %} {% raw %}
print(
    f"Somme des ratios : {df_fdr.ratio_nb_foyer.sum()} => Elle n'est pas égale à 100% car on considère tous les foyers au dessus du seuil, pas entre deux seuils"
)
print(
    f"Total des RFR moyen des seuils {df_fdr.mean_rfr.sum():,} € => Ca n'a pas de sens"
)
{% endraw %} {% raw %}
from matplotlib.ticker import PercentFormatter

ax = sns.barplot(data=df_fdr, x="seuil_rfr_str", y="seuil_rfr")
_ = ax.set_title("Pareto du RFR")
ax2 = ax.twinx()
ax3 = sns.lineplot(data=df, x="seuil_rfr_str", y="pareto", ax=ax2)
ax3.yaxis.set_major_formatter(PercentFormatter())
_ = ax.set_xticklabels(labels=ax.get_xticklabels(), rotation=90)
{% endraw %}

Ici l'axe horizontale n'est pas linéaire du tout : chaque point correspond à un seuil et l'écart entre les points est le même quelque soit l(écart en valeur. Avec un écart correspondant à la valeur de seuil de rfr la courbe de Pareto devient:

{% raw %}
df = df_fdr
df["seuil_rfr_str"] = df_fdr.seuil_rfr.astype(str)
df["seuil_rfr"] = df_fdr.seuil_rfr.astype(int)
df["pareto"] = (1 - df_fdr.ratio_nb_foyer) * 100
ax = sns.lineplot(data=df, x="seuil_rfr", y="pareto")
{% endraw %} {% raw %}
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(10, 8))
_ = fig.suptitle("Fonction de répartition du RFR dans POTE")
ax = sns.scatterplot(
    data=df_fdr.query("seuil_rfr < 100_000"),
    x="seuil_rfr",
    y="ratio_nb_foyer",
    ax=axes[0],
)
_ = ax.set_title("RFR < 100 000 €")
ax = sns.scatterplot(
    data=df_fdr.query("500_000 < seuil_rfr < 50_000_000"),
    x="seuil_rfr",
    y="ratio_nb_foyer",
    ax=axes[1],
)
_ = ax.set_title("RFR > 500 000 €")
fig.tight_layout()
{% endraw %}

Copules

{% raw %}
copule_rk = read_copule(
    config.get("COPULE_FOLDER") + "20210610ExportCopule-rev_capital_partiel.txt"
)
df_copule_rk = copule_to_df(copule_rk, 1)  # 1 : somme de Var
df_copule_rk["sum_rk"] = df_copule_rk.apply(sum_copule_col, axis=1)
print(f"Sommes des revenus du capital {df_copule_rk['sum_rk'].sum():,} €")
{% endraw %} {% raw %}
assert 33836323865 == df_copule_rk["sum_rk"].sum()
{% endraw %} {% raw %}
# df_copule_rk_mean.tail()
{% endraw %} {% raw %}
fig, axs = plt.subplots(nrows=2, ncols=1, figsize=(20, 8))
ax = sns.scatterplot(
    data=df_copule_rk, x="lower_bound", y="nb_people_nonzero", ax=axs[0]
)
axis_in_k(ax, yunit="")
ax = sns.lineplot(data=df_copule_rk, x="lower_bound", y="sum_rk", marker="D", ax=axs[1])
axis_in_k(ax)
_ = fig.suptitle("Analyse des seuils de RFR des copules de revenus du capital")
_ = axs[0].set_title("Par personne ayant un revenu")
_ = axs[1].set_title("Par revenu du capital")
fig.tight_layout()
{% endraw %} {% raw %}
ax = sns.lineplot(data=df_copule_rk, x="lower_bound", y="nb_people_nonzero", marker="X")
axis_in_k(ax, yunit="")
ax2 = ax.twinx()
ax2 = sns.lineplot(
    data=df_copule_rk,
    x="lower_bound",
    y="sum_rk",
    marker="D",
    color="darkgreen",
    ax=ax2,
)
# axis_in_k(ax)
_ = ax.set_title("Analyse des seuils de RFR des copules de revenus du capital")
fig.tight_layout()
{% endraw %}

CSG

{% raw %}
import json

from leximpact_socio_fisca_simu_etat.csg_simu import (
    ReformeSocioFiscale,
    compute_all_simulation,
)

reform = ReformeSocioFiscale(
    base=2021,
    amendement={
        "prelevements_sociaux.contributions_sociales.csg.activite.imposable.taux": 0.068,
    },
    output_variables=["csg"],
    quantile_nb=100,
    quantile_compare_variables=["csg"],
)
resultat = compute_all_simulation(reform, annee_de_calcul="2021")
{% endraw %} {% raw %}
df = pd.DataFrame(resultat.result["amendement"].dict()["quantiles"])
json_struct = json.loads(df.to_json(orient="records"))
df_flat = pd.json_normalize(json_struct)  # use pd.io.json
df = df_flat
df["quantiles"] = df.fraction * 100
df["quantiles"] = df["quantiles"].astype(int)
df.csg = df.csg / -1
df.head()
{% endraw %} {% raw %}
ax = sns.barplot(data=df, y="csg", x="quantiles")
_ = ax.set_yscale("log")
_ = ax.set_xticklabels(labels=ax.get_xticklabels(), rotation=90)
_ = ax.set_title("Quantiles de CSG\nEchelle logarithmique")
{% endraw %}