Objectif : récupérer la distribution du salaire en fonction de différentes variables socio-démographiques
Application : récupération de la distribution en fonction de l'âge et du sexe
Méthode : On étudie dans un premier temps une modalité d'une variable ( la modalité "homme" de la variable "sexe") afin d'acquérir une automitisation du traitement sur d'autres variables
Résultat : Le souci de ce script c'est qu'il ne peut tourner que sur un ordi ayant accès aux données ERFS-fpr. Pour pouvoir utiliser la distribution aléatoire générée, nous exportons un nombre ad-hoc de salaires simulés, pensé en fonction de la taille de la population mère qu'on recherche.
In [1]:
%pylab inline
import pandas as pd
import numpy as np
import tables
import mpld3
import json
In [2]:
from scipy.stats import norm
from sklearn.neighbors import KernelDensity
import statsmodels.api as sm
import seaborn as sns
from Tools import *
from kde_2d_weighted import gaussian_kde
In [3]:
individu = get_individu_simplified(get_individu('output/erfs_fpr_2012.h5'))
In [4]:
# On se concentre sur les individus actifs
activite = individu[individu.acteu6 == 1]
In [5]:
salaire = get_salaire(activite, 'sexe')
salaire.size()
# Sexe : 1 si homme
# 2 si femme
Out[5]:
In [6]:
max_salaire = 400000
print(len(salaire.get_group(1)[salaire.get_group(1) > max_salaire]) / 26158.0)
# justification de ne pas prendre ne compte les plus riches pour une meilleure approximation
In [7]:
plt.hist(salaire.get_group(1)[(salaire.get_group(1) > 0) &(salaire.get_group(1) < max_salaire)], bins = 300, normed = True, facecolor='red')
plt.show()
print("Nombre d'observations", len(salaire.get_group(1)[(salaire.get_group(1) > 0) &(salaire.get_group(1) < max_salaire)]))
# On choisit délibérement de ne pas prendre les salaires égaux à zero pour attribuer un salaire (salaire égal à zero dû notamment aux indépendants actifs)
In [8]:
plt.hist(salaire.get_group(1)[(salaire.get_group(1) > 0) &(salaire.get_group(1) < max_salaire)], bins = 300, weights = get_weights(activite[(activite.salaires_i > 0) & (activite.salaires_i < max_salaire)], 'sexe').get_group(1), normed = True, facecolor='red')
plt.hist(salaire.get_group(1)[(salaire.get_group(1) > 0) & (salaire.get_group(1) < max_salaire)], bins = 300,normed = True, facecolor='green', alpha = 0.4)
plt.show()
# on abandonne l'utilisation des poids pour simplifier la démarche
In [9]:
X = np.array(salaire.get_group(1)[(salaire.get_group(1) > 0) & (salaire.get_group(1) < max_salaire)])
X_plot = np.linspace(0, max_salaire, 10000)[:, np.newaxis]
In [10]:
bw = sm.nonparametric.bandwidths.bw_scott(X)
bw
Out[10]:
In [11]:
# Présentation de la démarche : exemple avec une kde gaussienne
kde = KernelDensity(kernel='gaussian', bandwidth=bw).fit(X.reshape(-1,1))
log_dens = kde.score_samples(X_plot)
plt.plot(X_plot[:, 0], np.exp(log_dens))
Out[11]:
In [12]:
fig, ax = plt.subplots(figsize=(10,5))
ax.hist(X, bins = 300, histtype= 'stepfilled', fc='black', alpha=0.2, normed= True,
label='input distribution')
for kernel in ['gaussian', 'tophat', 'epanechnikov']:
kde = KernelDensity(kernel=kernel, bandwidth=bw).fit(X.reshape(-1,1))
log_dens = kde.score_samples(X_plot)
ax.plot(X_plot[:, 0], np.exp(log_dens), '-',
label="kernel = '{0}'".format(kernel))
ax.legend(loc='upper right', prop={'size':10})
mpld3.display()
# En utlisant le zoom, on se rend compte que le kernel Tophat est légèrement mieux
# notamment sur les valeurs proches de 0
Out[12]:
In [13]:
kde_tophat = KernelDensity(kernel='tophat', bandwidth=bw).fit(X.reshape(-1,1))
plt.hist(kde_tophat.sample(10000), bins = 300, normed = True)
plt.show()
In [ ]:
# Salaire des femmes
Y = np.array(salaire.get_group(2)[(salaire.get_group(2) > 0) & (salaire.get_group(2) < max_salaire)])
In [17]:
# Distribution du salaire des hommes
pd.Series(X).describe()
Out[17]:
In [18]:
# Distribution du salaire des femmes
pd.Series(Y).describe()
Out[18]:
In [14]:
bw = sm.nonparametric.bandwidths.bw_scott(Y)
print(bw)
print("Nombre d'observations", len(Y))
In [15]:
def compare_kde(data, data_plot, bw, title = ''):
'''
Creer un graphique de comparaison entre les kernels
'''
fig, ax = plt.subplots(figsize=(6,3))
ax.hist(data, bins = 300, histtype= 'stepfilled', fc='black', alpha=0.2, normed= True,
label='input distribution')
for kernel in ['gaussian', 'tophat']:
kde = KernelDensity(kernel=kernel, bandwidth=bw).fit(data.reshape(-1,1))
log_dens = kde.score_samples(data_plot)
ax.plot(data_plot[:, 0], np.exp(log_dens), '-',
label="kernel = '{0}'".format(kernel))
ax.legend(loc='upper right', prop={'size':7})
ax.set_title(title)
compare_kde(Y, X_plot, bw)
mpld3.display()
Out[15]:
In [16]:
kde_tophat = KernelDensity(kernel='tophat', bandwidth=bw).fit(Y.reshape(-1,1))
plt.hist(kde_tophat.sample(10000), bins = 300, normed = True)
plt.show()
In [36]:
# Chercher les catégories les moins représentées afin de gonfler leur effectif pour limiter l'overfitting
# Pas d'automatisation
a = activite.groupby(('age')).size()
a.sort_values()[:40]
Out[36]:
In [82]:
activite.loc[activite['sexe'] == 1, 'sexe'] = 'homme'
activite.loc[activite['sexe'] == 2, 'sexe'] = 'femme'
In [83]:
# Regroupement selon la variable âge
activite['age_pivot'] = activite['age']
activite.loc[activite.age <= 23, 'age_pivot'] = '<23'
activite.loc[activite.age >= 60, 'age_pivot'] = '>60'
In [84]:
salaire = get_salaire(activite, ['sexe', 'age_pivot'])
In [85]:
salaire_filtre = {}
for filtre in salaire.groups.keys():
condition = (salaire.get_group(filtre) > 0) &(salaire.get_group(filtre) < max_salaire)
salaire_filtre['{0}'.format(filtre)] = np.array(salaire.get_group(filtre)[condition])
In [86]:
kde_sample = {}
kde_plot = {}
for filtre in salaire_filtre.keys():
X = salaire_filtre[filtre]
bw = sm.nonparametric.bandwidths.bw_scott(X)
kde = KernelDensity(kernel='tophat', bandwidth=bw).fit(X.reshape(-1,1))
# Tirage d'un échantillon : taille définie en fonction de la taille de la population simulée
kde_sample['{0}'.format(filtre)] = [float(x) for x in kde.sample(10000)]
compare_kde(X, X_plot, bw, filtre)
In [87]:
with open('salaire_sexe_age.json', 'w') as fp:
json.dump(kde_sample, fp)