--- title: Plot distribution keywords: fastai sidebar: home_sidebar nb_path: "notebooks/analyses/csg_55_plot_distributions.ipynb" ---
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
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")
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)
sample_pop = pd.read_csv(config.get("DATA_OUT") + "sample_pop_ind_csg.csv")
sample_pop.columns
sample_pop["rfr_pop"] = sample_pop["rfr"] * sample_pop["wprm"]
sample_pop["salaire_de_base_pop"] = sample_pop["salaire_de_base"] * sample_pop["wprm"]
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()}"
)
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")
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")
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.
sample_pop.rfr_pop.max()
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
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"
)
df = sample_pop.query("rfr > 500_000")
ax = sns.histplot(data=df, x="rfr", bins=10)
La "fonction de répartition du RFR" calcul pour 53 seuils:
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)
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"
)
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)
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:
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")
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()
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():,} €")
assert 33836323865 == df_copule_rk["sum_rk"].sum()
# df_copule_rk_mean.tail()
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()
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()
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")
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()
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")