import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
# importations de modules "local"
import sys
sys.path.append('functions/')
import base_notebook_light
import css_base_light
import fonctions_perso
# import des librairies et des paramètres
from base_notebook_light import *
from css_base_light import *
# repère de début de traitement pour calculer le temps tital d'exécution du notebook
start_time_m4 = time.time()
# recupération des données de la partie 1
income_data=pd.read_csv("data/exports/income_data.csv")
gini_data = pd.read_csv("data/exports/gini_data.csv")
pop_nat_sel = pd.read_csv("data/exports/pop_nat_sel.csv")
df_gini_calc = pd.read_csv("data/exports/df_gini_calc.csv")
income_data.sample(2)
gini_data.sample(2)
pop_nat_sel.sample(2)
df_gini_calc.sample(2)
code_pays | annee | centile | income | gdp | |
---|---|---|---|---|---|
5303 | JPN | 2008 | 4 | 4199.9080 | 31307.0 |
8570 | PER | 2008 | 71 | 3600.5244 | 7858.0 |
code_pays | pays | 2004 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | gini_avg | |
---|---|---|---|---|---|---|---|---|---|---|
78 | NGA | Nigéria | NaN | NaN | NaN | NaN | 0.430 | NaN | NaN | 0.430000 |
97 | SVN | Slovénie | 0.248 | 0.244 | 0.244 | 0.237 | 0.248 | 0.249 | 0.249 | 0.245571 |
code_pays | pays | 2004 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | |
---|---|---|---|---|---|---|---|---|---|
54 | KGZ | Kirghizistan | 5039.005 | 5124.382000 | 5184.392000 | 5254.979000 | 5334.710000 | 5422.29300 | 5517.922 |
95 | SRB | Serbie | 7463.157 | 9144.194464 | 9099.451596 | 9058.355617 | 9021.595526 | 8989.47832 | 8961.978 |
code_pays | annee | val_gini | |
---|---|---|---|
61 | LKA | 2007 | 0.4022 |
103 | TLS | 2007 | 0.3198 |
La répartition des revenus par centiles n'est pas disponible pour une même année pour tous les pays
-> l'analyse va donc porter sur la période 2004-2011
# creation d'un df regroupant toutes les données
df = income_data.copy()
df
code_pays | annee | centile | income | gdp | |
---|---|---|---|---|---|
0 | ALB | 2008 | 1 | 728.89795 | 7297.0 |
1 | ALB | 2008 | 2 | 916.66235 | 7297.0 |
2 | ALB | 2008 | 3 | 1010.91600 | 7297.0 |
3 | ALB | 2008 | 4 | 1086.90780 | 7297.0 |
4 | ALB | 2008 | 5 | 1132.69970 | 7297.0 |
... | ... | ... | ... | ... | ... |
11495 | ZAF | 2008 | 96 | 24553.56800 | 9602.0 |
11496 | ZAF | 2008 | 97 | 28858.03100 | 9602.0 |
11497 | ZAF | 2008 | 98 | 35750.29000 | 9602.0 |
11498 | ZAF | 2008 | 99 | 46297.31600 | 9602.0 |
11499 | ZAF | 2008 | 100 | 82408.55000 | 9602.0 |
11500 rows × 5 columns
# creation d'une fonction qui return le nom d'un pays à partir de son code alpha3
code_corr_pays = pd.read_csv("data/inputs/sql-pays.csv")
code_corr_pays = code_corr_pays.loc[:,['alpha3', 'nom_pays_fr']]
code_corr_pays.columns = ['code_pays', 'pays']
code_corr_pays = code_corr_pays.dropna()
def nom_pays(code):
df = code_corr_pays.copy()
if code in df['code_pays'].tolist():
name = df.loc[df['code_pays'] == code, 'pays'].values[0]
else:
name = np.nan
return name
# calcul du revenu moyen 'income_avg' par pays
df_gb = df.groupby('code_pays')['income'].mean()
for cp in df_gb.index:
# ajout du nom du pays en fr
df.loc[df['code_pays'] == cp, 'pays'] = nom_pays(cp)
# ajout de 'income_avg'
df.loc[df['code_pays'] == cp, 'income_avg'] = df_gb[cp]
# ajout de l'indice de Gini
df.loc[df['code_pays'] == cp, 'gini'] = df_gini_calc.loc[df_gini_calc['code_pays'] == cp, 'val_gini'].values[0]
# ajout de la population
df.loc[df['code_pays'] == cp, 'pop'] = pop_nat_sel.loc[pop_nat_sel['code_pays'] == cp, '2008'].values[0]*1000
# modification ordre des colonnes
df=df.reindex(columns=(['code_pays', 'pays', 'annee', 'pop', 'gini', 'gdp', 'income_avg', 'centile', 'income']))
# verif de présence de valeurs nulles
df.isna().sum()
# verif de la taille du df
df.shape
# affichage random de 2 éléments
df.sample(3)
code_pays 0 pays 0 annee 0 pop 0 gini 0 gdp 0 income_avg 0 centile 0 income 0 dtype: int64
(11500, 9)
code_pays | pays | annee | pop | gini | gdp | income_avg | centile | income | |
---|---|---|---|---|---|---|---|---|---|
9788 | SVN | Slovénie | 2008 | 2023052.0 | 0.2307 | 27197.0 | 12106.007475 | 89 | 17821.676 |
3934 | GRC | Grèce | 2008 | 11040309.0 | 0.3294 | 27123.0 | 11727.274287 | 35 | 7929.339 |
9736 | SVN | Slovénie | 2008 | 2023052.0 | 0.2307 | 27197.0 | 12106.007475 | 37 | 9742.528 |
# GDIM dataset
gdim = pd.read_csv("data/inputs/GDIMMay2018.csv")
gdim.head(1)
gdim.columns
countryname | wbcode | iso3 | region | incgroup2 | incgroup4 | fragile | survey | year | status | ... | Cores2125_MAcatC1 | Shortfall0611_obs | Shortfall0611_IGP | Shortfall1217_obs | Shortfall1217_IGP | IGEincome | S1 | S2 | S3 | MLD_psu | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Afghanistan | AFG | AFG | South Asia | Developing economies | Low income | 1 | NRVA | 1980 | Co-residents only | ... | NaN | 25103.0 | 0.086197 | 18054.0 | 0.345224 | NaN | NaN | NaN | NaN | 0.1 |
1 rows × 66 columns
Index(['countryname', 'wbcode', 'iso3', 'region', 'incgroup2', 'incgroup4', 'fragile', 'survey', 'year', 'status', 'cohort', 'parent', 'child', 'obs', 'P1', 'P2', 'P3', 'P4', 'P5', 'C1', 'C2', 'C3', 'C4', 'C5', 'MEANp', 'MEANc', 'SDp', 'SDc', 'GINIp', 'GINIc', 'IGP', 'NL1', 'NL2', 'COR', 'MAcatM', 'MAcatC1', 'Q4_IGpri', 'BHQ1', 'BHQ2', 'BHQ3', 'BHQ4', 'Q4BH', 'Q4child', 'Delta50', 'Asher_Q4_IGpri', 'ThreeGen_obs', 'ThreeGen_IGPp1', 'ThreeGen_IGPg1', 'ThreeGen_IGPgsd', 'All2125_MEANp', 'All2125_MEANc', 'All2125_IGP', 'All2125_MAcatC1', 'Cores2125_MEANp', 'Cores2125_MEANc', 'Cores2125_IGP', 'Cores2125_MAcatC1', 'Shortfall0611_obs', 'Shortfall0611_IGP', 'Shortfall1217_obs', 'Shortfall1217_IGP', 'IGEincome', 'S1', 'S2', 'S3', 'MLD_psu'], dtype='object')
# on ne garde que les colonnes qui nous intéressent
gdim_temp = gdim[['countryname', 'iso3', 'region', 'incgroup4','IGEincome']]
gdim_temp.columns=['pays', 'code_pays', 'region', 'inc_groupe', 'ige']
# on ne garde que les lignes qui ont une valeur pour 'IGE'
gdim_test = gdim_temp[gdim_temp['ige'].isna() == False]
gdim_test.shape
# on supprime les doublons
gdim_test = gdim_test.drop_duplicates()
gdim_test.shape
gdim_test.nunique()
nb_pays_temp=gdim_test.pays.nunique()
print(f"{nb_pays_temp} pays ont une donnée pour la varaible 'IGE'")
gdim_test.sample(1)
(853, 5)
(75, 5)
pays 75 code_pays 75 region 7 inc_groupe 4 ige 75 dtype: int64
75 pays ont une donnée pour la varaible 'IGE'
pays | code_pays | region | inc_groupe | ige | |
---|---|---|---|---|---|
2112 | Ghana | GHA | Sub-Saharan Africa | Lower middle income | 0.561605 |
# on limite ces 75 pays à ceux qui sont présents dans df
# creation df_pays_ige pour insérer les valeurs de 'ige'
df_pays_ige = df[['code_pays', 'pays']]
df_pays_ige = df_pays_ige.drop_duplicates()
df_pays_ige['ige'] = np.nan
# code_pays présents dans df
pays_income = set(df.code_pays)
# code_pays présents dans gdim
pays_ige = set(gdim_test.code_pays)
# code_pays présents dans les 2 dataframes
cp_communs = pays_ige & pays_income
n=len(cp_communs)
print(f"{n} pays de DF ont une valeur IGE")
# insertion des valeurs 'ige' dans df_pays_ige
for cp in cp_communs:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = gdim_test.loc[gdim_test['code_pays'] == cp, 'ige'].values[0]
#df_pays_ige['ige'] = gdim_test.loc[gdim_test['code_pays'].isin(list(cp_communs)), 'ige']
display(HTML('<span>Ex pour la France :<span>'))
display((df_pays_ige.loc[df_pays_ige['code_pays'] == 'FRA', :]))
df_pays_ige.shape
df_pays_ige.sample(10)
65 pays de DF ont une valeur IGE
code_pays | pays | ige | |
---|---|---|---|
3400 | FRA | France | 0.357105 |
(115, 3)
code_pays | pays | ige | |
---|---|---|---|
4000 | GTM | Guatemala | 1.015206 |
8100 | NOR | Norvège | 0.198667 |
11100 | VNM | Viet Nam | 0.480000 |
3900 | GRC | Grèce | 0.312578 |
5600 | KGZ | Kirghizistan | 0.352871 |
11200 | XKX | Kosovo | NaN |
4400 | IDN | Indonésie | NaN |
8000 | NLD | Pays-Bas | 0.303956 |
11300 | YEM | Yémen | NaN |
6300 | LUX | Luxembourg | 0.380792 |
val_ige_manq = df_pays_ige.shape[0] - n
print(f"Valeurs IGE manquantes : {val_ige_manq}")
Valeurs IGE manquantes : 50
On va utiliser le fichier elasticity.txt
pour donner une valeur de mobilité intergénérationnelle aux 50 pays sans données
-> on va prendre la valeur de base, 'Base case', pour référence:
Ainsi, les pays sont classés géographiquement en 5 zones, avec un coefficient différent par zone (on peut regrouper en 4 zones)
On va comparer les zones définies dans ce fichier avec celles de notre df
# zones elasticity.txt -> on crée un df avec zone et valeur IGE
data = {'zone': ['eur_nord_canada', 'eur_aus_usa_nz', 'asie', 'am_lat_afr'],
'ige_base': [0.2, 0.4, 0.5, 0.66]}
df_elas_txt = pd.DataFrame(data, columns=['zone', 'ige_base'])
df_elas_txt
zone | ige_base | |
---|---|---|
0 | eur_nord_canada | 0.20 |
1 | eur_aus_usa_nz | 0.40 |
2 | asie | 0.50 |
3 | am_lat_afr | 0.66 |
# zones du df 'ige'
gdim_temp.groupby('region').size()
region East Asia & Pacific 521 Europe & Central Asia 1168 High income 2152 Latin America & Caribbean 600 Middle East & North Africa 360 South Asia 333 Sub-Saharan Africa 1370 dtype: int64
Il faudra traiter les régions 'High Income' et 'Europe & Central Asia' pays par pays
On commence par traiter les autres régions
gdim_test.sample(1)
pays | code_pays | region | inc_groupe | ige | |
---|---|---|---|---|---|
3556 | Luxembourg | LUX | High income | High income | 0.380792 |
# Liste des codes pays à traiter
pays_a_traiter = df_pays_ige.loc[df_pays_ige['ige'].isna(), 'code_pays'].tolist()
# df qui contient le nom des régions pour la correspondance
gdim_temp_a_traiter = gdim_temp.drop_duplicates()
gdim_temp_a_traiter = gdim_temp_a_traiter.loc[gdim_temp['code_pays'].isin(pays_a_traiter),:]
# liste asie avec les codes_pays des pays asie
df_asie=gdim_temp_a_traiter[(gdim_temp_a_traiter['region'] == 'East Asia & Pacific') | (gdim_temp_a_traiter['region'] == 'South Asia')]
pays_asie = df_asie.code_pays.tolist()
# liste afrique_am_lat avec les codes_pays des pays afrique et am_lat
df_afrique_am_lat=gdim_temp_a_traiter[(gdim_temp_a_traiter['region'] == 'Middle East & North Africa') | (gdim_temp_a_traiter['region'] == 'Sub-Saharan Africa') | (gdim_temp_a_traiter['region'] == 'Latin America & Caribbean')]
pays_afrique_am_latine = df_afrique_am_lat.code_pays.tolist()
# pour les pays qui ont matché, on modifie la valeur de 'ige' avec les valeurs de elasticity.txt
for cp in pays_a_traiter:
if cp in pays_asie:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = 0.5
if cp in pays_afrique_am_latine:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = 0.66
# code_pays des pays à traiter manuellement
a_traiter = df_pays_ige.loc[df_pays_ige['ige'].isna(), ['code_pays', 'pays']]
a_traiter
code_pays | pays | |
---|---|---|
200 | ARM | Arménie |
400 | AZE | Azerbaïdjan |
800 | BGR | Bulgarie |
3100 | EST | Estonie |
3600 | GEO | Géorgie |
4300 | HUN | Hongrie |
4900 | ISL | Islande |
5000 | ISR | Israël |
6200 | LTU | Lituanie |
6600 | MDA | République de Moldova |
7100 | MNE | Monténégro |
8700 | POL | Pologne |
9500 | SRB | Serbie |
10000 | SYR | République Arabe Syrienne |
10200 | TJK | Tadjikistan |
10400 | TUR | Turquie |
10700 | UKR | Ukraine |
10800 | URY | Uruguay |
11200 | XKX | Kosovo |
# listes code_pays par régions
liste_eur_nord_canada = ['ISL']
liste_eur_aus_usa_nz = ['BGR', 'EST', 'HUN', 'LTU', 'MNE', 'POL', 'SRB', 'UKR', 'XKX']
liste_asie = ['ARM', 'AZE', 'GEO', 'ISR', 'MDA', 'SYR', 'TJK', 'TUR']
liste_am_lat_afr = ['URY']
# optimation de 'ige' pour les pays restants
for cp in a_traiter.code_pays:
if cp in liste_eur_nord_canada:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = 0.2
if cp in liste_eur_aus_usa_nz:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = 0.4
if cp in liste_asie:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = 0.5
if cp in liste_am_lat_afr:
df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'] = 0.66
# on vérifie l'abscence de NaN
df_pays_ige.isna().sum()
code_pays 0 pays 0 ige 0 dtype: int64
for cp in df.code_pays:
df.loc[df['code_pays'] == cp, 'p'] = df_pays_ige.loc[df_pays_ige['code_pays'] == cp, 'ige'].values[0]
df.sample(10)
code_pays | pays | annee | pop | gini | gdp | income_avg | centile | income | p | |
---|---|---|---|---|---|---|---|---|---|---|
3217 | FIN | Finlande | 2008 | 5319449.0 | 0.2769 | 33626.0 | 16306.330495 | 18 | 9420.76500 | 0.112876 |
3679 | GEO | Géorgie | 2008 | 4142655.0 | 0.3901 | 4516.0 | 1363.758606 | 80 | 1880.46070 | 0.500000 |
6784 | MDG | Madagascar | 2010 | 19996473.0 | 0.4405 | 950.0 | 345.237074 | 85 | 524.19135 | 0.689613 |
3222 | FIN | Finlande | 2008 | 5319449.0 | 0.2769 | 33626.0 | 16306.330495 | 23 | 10265.00800 | 0.112876 |
8678 | PHL | Philippines | 2006 | 90901965.0 | 0.4407 | 3240.0 | 1474.062856 | 79 | 1939.59910 | 0.500000 |
6432 | LVA | Lettonie | 2008 | 2171259.0 | 0.3622 | 15596.0 | 6764.474571 | 33 | 4082.63480 | 0.889911 |
4325 | HUN | Hongrie | 2008 | 9991867.0 | 0.2741 | 18004.0 | 6101.341229 | 26 | 3954.08540 | 0.400000 |
4495 | IDN | Indonésie | 2009 | 235469762.0 | 0.3721 | 3689.0 | 1334.618297 | 96 | 3284.77200 | 0.500000 |
11082 | VEN | Venezuela | 2006 | 27635832.0 | 0.4340 | 11756.0 | 3167.147724 | 83 | 4676.25900 | 0.660000 |
7345 | MOZ | Mozambique | 2008 | 22276596.0 | 0.4564 | 773.0 | 692.480501 | 46 | 437.23605 | 0.660000 |
df_pays_ige['ige'] = df_pays_ige['ige'].apply(lambda x: round(x,4))
df_pays_ige
code_pays | pays | ige | |
---|---|---|---|
0 | ALB | Albanie | 0.8159 |
100 | ARG | Argentine | 0.6600 |
200 | ARM | Arménie | 0.5000 |
300 | AUT | Autriche | 0.2453 |
400 | AZE | Azerbaïdjan | 0.5000 |
... | ... | ... | ... |
11000 | VEN | Venezuela | 0.6600 |
11100 | VNM | Viet Nam | 0.4800 |
11200 | XKX | Kosovo | 0.4000 |
11300 | YEM | Yémen | 0.6600 |
11400 | ZAF | Afrique du Sud | 0.6770 |
115 rows × 3 columns
# Définition des paramètres
nb_quantiles = 10
n = 1000 * nb_quantiles
# pour un pays caractérisé par pj
def proba_cd(pj, nb_quantiles, taille_echantillon=None):
res = {}
n = 1000 * nb_quantiles
def generate_incomes(n, pj):
# générer n réalisations de ln_y_parent
ln_y_parent = st.norm(0,1).rvs(size=n)
# générer n réalisations du terme d'erreur
residues = st.norm(0,1).rvs(size=n)
return np.exp(pj*ln_y_parent + residues), np.exp(ln_y_parent)
def quantiles(l, nb_quantiles):
# revenu
size = len(l)
l_sorted = l.copy()
l_sorted = l_sorted.sort_values()
# classe de revenu
quantiles = np.round(np.arange(1, nb_quantiles+1, nb_quantiles/size) -0.5 +1./size)
q_dict = {a:int(b) for a,b in zip(l_sorted,quantiles)}
# revenus répartis par quantiles
return pd.Series([q_dict[e] for e in l])
def compute_quantiles(y_child, y_parent, nb_quantiles):
# revenus (enfants et parent)
y_child = pd.Series(y_child)
y_parent = pd.Series(y_parent)
# classes de revenus (enfants et parent)
c_i_child = quantiles(y_child, nb_quantiles)
c_i_parent = quantiles(y_parent, nb_quantiles)
# df revenus et classes
sample = pd.concat([y_child, y_parent, c_i_child, c_i_parent], axis=1)
sample.columns = ["y_child", "y_parent", "c_i_child","c_i_parent"]
return sample
##############################################################################################
# Probabilités conditionnelles
##############################################################################################
# Calcul de la part de chaque quantile 'parent' dans l'effectif total
def distribution(counts, nb_quantiles):
distrib = []
total = counts["counts"].sum()
if total == 0 :
return [0] * nb_quantiles
for q_p in range(1, nb_quantiles+1):
subset = counts[counts.c_i_parent == q_p]
distrib += ([subset["counts"].values[0] / total] if len(subset) else [0])
res['distrib'] = distrib
return distrib
# On compte toutes les combinaisons possibles de "c_i_child / c_i_parent"
def conditional_distributions(sample, nb_quantiles):
counts = sample.groupby(["c_i_child","c_i_parent"]).apply(len)
counts = counts.reset_index()
counts.columns = ["c_i_child","c_i_parent","counts"]
# Calcul des probas conditionnelles 'c_i_parent' sachant 'c_i_enfant' (et sachant pj = 0.9)
mat = []
for child_quantile in np.arange(nb_quantiles)+1:
subset = counts[counts.c_i_child == child_quantile]
mat += [distribution(subset, nb_quantiles)]
return np.array(mat)
# on lance les fonctions
y_child, y_parent = generate_incomes(n, pj)
res['y_child'] = y_child
res['y_parent'] = y_parent
sample = compute_quantiles(y_child, y_parent, nb_quantiles)
res['sample'] = sample
if taille_echantillon == None :
cd = conditional_distributions(sample, nb_quantiles)
else:
cd = np.round(conditional_distributions(sample, nb_quantiles) * taille_echantillon)
cd = np.array(cd, int)
res['cd'] = cd
# on retourne les éléments insérés dans le dico res
return res
# on vérifie les éléments renvoyés par la fonction
res = proba_cd(0.9, 10)
print(*res)
y_child y_parent sample distrib cd
# def de la fonction pour créer graphique en "stack bars"
def graph_dist_cond(p, cd, nb_quantiles, w=None, ec='white', pays=None, num_graph=None):
cumul = np.array([0] * nb_quantiles)
for i, child_quantile in enumerate(cd):
plt.bar(np.arange(nb_quantiles) + 1,
child_quantile,
bottom=cumul,
width=(w if w is not None else 0.95),
edgecolor=(ec if ec is not None else ""),
linewidth=1,
label = (str(i+1) + 'e' if nb_quantiles <= 20 else ''))
cumul = cumul + np.array(child_quantile)
if nb_quantiles == 100:
plt.xticks(np.arange(0,110,10))
#plt.axis([.5, nb_quantiles, 0, 1])
else:
plt.xticks(np.arange(nb_quantiles+1))
plt.axis([.5, nb_quantiles*1.3, 0, 1])
titre=("Pays \""+pays+"\" - " if pays is not None else "")+("Faible " if p>= 0.5 else "Forte ")+"mobilité intergénérationnelle"
plt.title(titre+ ' : p=' + str(p), fontsize=14)
if nb_quantiles <= 20:
plt.legend()
plt.xlabel('quantile parents', fontsize=12)
plt.ylabel('probabilité du quantile enfant', fontsize=12)
if num_graph is not None:
plt.savefig('data/exports/img_charts/'+str(num_graph)+'distributions_conditionelles_p_=_'+str(round(p,4))+("_pays_"+pays if pays is not None else "")+".png", dpi = 200)
res_faible_mob = proba_cd(0.9, 10)
cd_faible_mob = res_faible_mob['cd']
res_forte_mob = proba_cd(0.1, 10)
cd_forte_mob = res_forte_mob['cd']
plt.figure(figsize=(14,6))
plt.subplot(1, 2, 1)
graph_dist_cond(0.9, cd_faible_mob, 10)
plt.subplot(1, 2, 2)
graph_dist_cond(0.1, cd_forte_mob, 10)
plt.tight_layout(w_pad=2.5)
plt.savefig('data/exports/img_charts/10.distributions_condition_faible_et_forte_mobilite.png', dpi = 200)
plt.show();
# probabilité conditionnelle que le revenu parent appartienne à la classe c_i_parent sachant que le revenu enfant appartient à la classe c_i_enfant
# (pour un pays avec un indicateur de mobilité intergénérationnel égal à pj)
def proba_cond(c_i_parent, c_i_child, mat):
return mat[c_i_child-1, c_i_parent-1]
c_i_parent = 1
c_i_child = 1
p1=proba_cond(c_i_parent, c_i_child, cd_faible_mob)
p2=proba_cond(c_i_parent, c_i_child, cd_forte_mob)
resultat = [
["0.9 (donc faible mobilité intergénérationnelle)", p1, 0.9],
["0.1 (donc forte mobilité intergénérationnelle)", p2, 0.1]
]
for i,r in enumerate(resultat):
print(f" - Sachant que la classe de revenus d'un enfant est 1 et que le coef. d'élasticité est de {r[0]},")
print(f" alors la probabilité que la classe de revenu des parents soit aussi égale à 1 est de : P(c_i_parent = 1 | c_i_child = 1, pj = {r[2]}) = {r[1]}")
if i == 0:
print()
- Sachant que la classe de revenus d'un enfant est 1 et que le coef. d'élasticité est de 0.9 (donc faible mobilité intergénérationnelle), alors la probabilité que la classe de revenu des parents soit aussi égale à 1 est de : P(c_i_parent = 1 | c_i_child = 1, pj = 0.9) = 0.426 - Sachant que la classe de revenus d'un enfant est 1 et que le coef. d'élasticité est de 0.1 (donc forte mobilité intergénérationnelle), alors la probabilité que la classe de revenu des parents soit aussi égale à 1 est de : P(c_i_parent = 1 | c_i_child = 1, pj = 0.1) = 0.157
# dataframe avec "code_pays", "c_i_enfant" et "pj" (veiller à ordonner par code_pays puis par c_i_child)
dc_pc = df.copy()
dc_pc.columns=['code_pays', 'pays', 'annee', 'pop', 'Gj', 'gdp', 'income_avg', 'c_i_child', 'y_child', 'pj']
dc_pc = dc_pc[['code_pays', 'c_i_child', 'pj']]
dc_pc = dc_pc.sort_values(['code_pays', 'c_i_child'])
dc_pc = dc_pc.reset_index(drop=True)
# on liste les pays
pays = list(dc_pc['code_pays'])
l_pays = list(set(pays))
# on détermine les paramètre de départ
nb_quantiles = 100
dic_cd_parents_pays={}
# on boucle sur les pays
for pays in l_pays:
# on récupère la valeur de pj
pj = dc_pc.loc[dc_pc['code_pays'] == pays, 'pj'].values[0]
# on lance la fonction globale
res_data = proba_cd(pj, nb_quantiles)
# on récupère les distributions conditionnelles dans un dictionnaire avec comme clé le code_pays
dic_cd_parents_pays[pays] = res_data['cd']
# verif avec affichage des résultats pour la France
dic_cd_parents_pays["FRA"]
array([[0.053, 0.051, 0.035, ..., 0.001, 0.001, 0.002], [0.053, 0.036, 0.03 , ..., 0.001, 0.001, 0.001], [0.041, 0.032, 0.03 , ..., 0.001, 0.002, 0.001], ..., [0. , 0.001, 0.002, ..., 0.027, 0.024, 0.045], [0.001, 0.001, 0.001, ..., 0.038, 0.042, 0.047], [0. , 0.002, 0.001, ..., 0.043, 0.047, 0.065]])
# Nouvel échantillon de 500 générations
df1=df.copy()
df1.shape[0]*500
dfg = df1.append([df1]*499)
# Création du dataframe global dc
dc = dfg.copy()
dc.columns=['code_pays', 'pays', 'annee', 'pop', 'Gj', 'gdp', 'income_avg', 'c_i_child', 'y_child', 'pj']
# important d'ordonner le df comme on a ordonné les distributions conditionnelles : 'code_pays' puis 'c_i_child'
dc = dc.sort_values(['code_pays', 'c_i_child'])
dc = dc.reset_index(drop=True)
dc.shape
dc.head(3)
5750000
(5750000, 10)
code_pays | pays | annee | pop | Gj | gdp | income_avg | c_i_child | y_child | pj | |
---|---|---|---|---|---|---|---|---|---|---|
0 | ALB | Albanie | 2008 | 3002678.0 | 0.3046 | 7297.0 | 2994.829902 | 1 | 728.89795 | 0.815874 |
1 | ALB | Albanie | 2008 | 3002678.0 | 0.3046 | 7297.0 | 2994.829902 | 1 | 728.89795 | 0.815874 |
2 | ALB | Albanie | 2008 | 3002678.0 | 0.3046 | 7297.0 | 2994.829902 | 1 | 728.89795 | 0.815874 |
Nécessité de résoudre le problème lié aux valeurs décimales su nombre d'occurrences des centiles c_i_parent
c_i_child
), le calcul du nombre de centiles peut conduire à des valeurs décimales, plus précisément à des demi-centiles (2.5 centiles 'c_i_parent'=1 par exemple)Or on ne peut accepter que des valeurs entières
import random
from math import *
import copy
# résoudre problème d'arrondi
def solve_decimal(tab_x):
# distribution de c_i_parent
c=tab_x
# dictionnaires:
c_dic={}
c_dic_entier={}
for i in range(100):
# - avec les vraies valeurs
c_dic[i+1] = c[i]
# - avec seulement la partie entière
c_dic_entier[i+1] = int(c[i])
# somme des valeurs 'entieres'
entier = sum(int(x) for x in c)
# nombre de valeurs entières manquantes 'diff'
diff=500-entier
dec=[]
# on enregistre dans une liste les clés des valeurs décimales
for k,v in c_dic.items():
if v != 0:
if v%v != 1:
dec.append(k)
# choix aléatoires de 'diff' clés de valeurs décimales
random_dec = random.sample(dec, diff)
# on modifier les valeurs correspondantes dans c_dic_entier
for k in random_dec:
# ajout de 1 pour les valeurs random
c_dic_entier[k] = c_dic_entier[k] + 1
c=[]
# on reconstruit la liste de distribution de c_i_parent en incluant les nouvelles valeurs
for k, v in c_dic_entier.items():
c.append(v)
return c
# paramètres de départ
dic_c_i_parent={}
q_cip=[]
l_final=[]
dc = dc.sort_values(["code_pays", "c_i_child"])
# on boucle sur les pays
for pays in l_pays:
# on récupère le nom du pays
pays_name = dc.loc[dc['code_pays'] == pays, 'pays'].values[0]
# on récupère les distributions conditionnelles
cd = dic_cd_parents_pays[pays]
# initialisation de la liste qui contiendra les valeurs des centiles c_i_parent
list_c_i_parent_pays=[]
# on boucle sur les c_i_child : cd[i] (c_i_child+1 : cd[i])
for i, cic in enumerate(cd):
temp=[]
# pour chaque c_i_child, on récupère la distribution c_i_parent (sachant c_i_child)
for j, cip in enumerate(cic):
# effectif : 500 -> on cherche le nombre de fois où le quantile j+1 sera présent sachant c_i_child = i+1
# et on stocke la distribution de c_i_parent sachant c_i_child = i+1 dans une liste temp
# len(temp) = 100 => temp[j] = nb d'occurrences de "c_i_parent" == j+1
temp.append(int(500*cip))
# fonction solve_decimal pour corriger probleme d'arrondi
temp2=solve_decimal(temp)
# verif sum_quantile_parents
sum_quantile_parents = sum(x for x in temp2)
if sum_quantile_parents != 500:
print(f"Probleme somme effectif pour c_i_child {i+1}")
# on crée la liste de taille 500 qui correspond aux valeurs de dc["c_i_parent"] pour dc["c_i_child"] == i+1
for z,value in enumerate(temp2):
q_cip.extend([z+1]*value)
# on agrège les 100 listes pour chaque c_i_child (1 liste par quantile c_i_parents)
list_c_i_parent_pays.extend(q_cip)
# on réinitialse les listes
q_cip=[]
temp = []
temp2 = []
# on entre les valeurs de la colonne "c_i_parent" pour le pays 'code_pays == pays'
dc.loc[dc["code_pays"] == pays, "c_i_parent"]=list_c_i_parent_pays
list_c_i_parent_pays=[]
#affichage aléatoire de 5 éléments
dc.sample(5)
code_pays | pays | annee | pop | Gj | gdp | income_avg | c_i_child | y_child | pj | c_i_parent | |
---|---|---|---|---|---|---|---|---|---|---|---|
2186710 | HUN | Hongrie | 2008 | 9991867.0 | 0.2741 | 18004.0 | 6101.341229 | 74 | 7253.2144 | 0.400000 | 52.0 |
5044668 | SYR | République Arabe Syrienne | 2004 | 20664038.0 | 0.3576 | 4512.0 | 685.817495 | 90 | 1216.0874 | 0.500000 | 58.0 |
2707333 | KAZ | Kazakhstan | 2008 | 15862123.0 | 0.2673 | 10469.0 | 2239.149800 | 15 | 1252.8630 | 0.237995 | 58.0 |
2822359 | KGZ | Kirghizistan | 2008 | 5254979.0 | 0.3454 | 2043.0 | 1773.219217 | 45 | 1344.2498 | 0.352871 | 70.0 |
1405778 | ECU | Équateur | 2008 | 14535739.0 | 0.5099 | 7560.0 | 3383.741001 | 12 | 732.1931 | 1.029957 | 22.0 |
dc_fr = dc[dc['code_pays'] == 'FRA']
cd_fr = dic_cd_parents_pays['FRA']
plt.figure(figsize=(14,8))
graph_dist_cond(0.357105, cd_fr, 100, w=0.9, ec='white', pays="France", num_graph=11)
plt.tight_layout()
plt.show();
Verification de la cohérence des résultats en prenant un exemple :
Méthode de vérification :
# dataframe des données de la france
dc_fr = dc[dc['code_pays'] == 'FRA']
# distributions conditionnelles
cd_fr = dic_cd_parents_pays['FRA']
# liste des possibilités pour c_i_parent
c_par = np.arange(10,105,5).tolist()
# initialisation des listes pour dataframe
p_obs=[]
p_calc=[]
for i in c_par:
## proba observéee
##################
condition1 = dc_fr["c_i_child"] == 10
condition2 = dc_fr["c_i_parent"] == i
# nombre d'observations qui vérifient la double condition "c(i, parents)=i" et "c(i, enfants)=10"
cond = (condition1) & (condition2)
nb_obs_cond = dc_fr[cond].shape[0]
# nombre d'observations qui vérifient la condition "c(i, enfants)=10"
nb_ci_enf_10 = dc_fr[condition1].shape[0]
# calcul de la proba observée
#proba_obs = "{:.3f}".format(nb_obs_cond/nb_ci_enf_10)
proba_obs = round(nb_obs_cond/nb_ci_enf_10,3)
p_obs.append(proba_obs)
## proba conditionnelle
#######################
proba = proba_cond(i, 10, cd_fr)
proba_calc = round(proba,3)
#proba_calc = "{:.3f}".format(proba)
p_calc.append(proba_calc)
# df des résultats
df_verif = pd.DataFrame(list(zip(p_obs,p_calc)), columns = ['proba_obs','proba_calc'])
df_verif['diff'] = df_verif['proba_obs'] - df_verif['proba_calc']
df_verif["diff"] = df_verif["diff"].apply(lambda x: x if x>=0 else -x)
diff_max = df_verif['diff'].max()
df_verif
print(f"Différence maximale entre p_obs et p_calc : {diff_max}")
proba_obs | proba_calc | diff | |
---|---|---|---|
0 | 0.010 | 0.010 | 0.000 |
1 | 0.014 | 0.015 | 0.001 |
2 | 0.010 | 0.008 | 0.002 |
3 | 0.014 | 0.015 | 0.001 |
4 | 0.022 | 0.023 | 0.001 |
5 | 0.008 | 0.009 | 0.001 |
6 | 0.012 | 0.013 | 0.001 |
7 | 0.010 | 0.011 | 0.001 |
8 | 0.008 | 0.008 | 0.000 |
9 | 0.012 | 0.010 | 0.002 |
10 | 0.008 | 0.008 | 0.000 |
11 | 0.010 | 0.008 | 0.002 |
12 | 0.004 | 0.005 | 0.001 |
13 | 0.008 | 0.008 | 0.000 |
14 | 0.004 | 0.003 | 0.001 |
15 | 0.006 | 0.007 | 0.001 |
16 | 0.000 | 0.001 | 0.001 |
17 | 0.002 | 0.002 | 0.000 |
18 | 0.004 | 0.004 | 0.000 |
Différence maximale entre p_obs et p_calc : 0.002
Il existe des écarts entre les 2 séries mais de faibles valeurs (0.002 au maximum) -> cela s'explique par la distribution alétoire des valeurs décimales de centiles lors de la génération de l'échantillon
-> on considère donc nos résultats comme cohérents
dc.to_csv("data/exports/dc_anova.csv", header=True, index=False)
cp_elas_reel = pd.DataFrame(cp_communs)
cp_elas_reel.columns=['code_pays']
cp_elas_reel.to_csv("data/exports/cp_elas_reel.csv", header=True, index=False)
from fonctions_perso import duree_convert
# repère de fin de traitement du notebook
end_time_m4 = time.time()
duree_m4 = end_time_m4 - start_time_m4
duree = duree_convert(duree_m4)
print("Temps total d'exécution du notebook : "+str(duree))
Temps total d'exécution du notebook : 9min 55s