import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
# Lecture du fichier de données aggrégées
df = pd.read_csv("../data/data_aggregate_PDL.csv")
def computePercentage(cols, colref):
#calcul un pourcentage en prenant l'effectif d'une somme de colonnes vis-à-vis d'un valeur de référence
return(df[cols].sum(axis = 1) /df[colref])
#Traitement des colonnes
def findCols(df, s):
#retourne une liste des colonnes contenant la chaine de caractères
l = []
for col in df.columns:
if s in col:
l.append(col)
#print(col)
return(l)
cols = findCols(df, 'NIV_')
def findEtudeNCols(df, etude, s):
#Parmi les données insee, utilise le prefix de nom de colonne pour effectuer une recherche de colonnes uniqueent dans ce subset
#retourne une liste des colonnes contenant la chaine de caractères
l = []
for col in df.columns:
if col.split("_")[0] == etude:
if s in col:
l.append(col)
#print(col)
return(l)
cols = findEtudeNCols(df, 'POP2', 'NA38AZ')
#Proportion de chomeurs dans la population
df['p_chom'] = (df['P17_CHOM1564']/df['P17_POP'])
#Pourcentage de personnes de plus de 65 ans
cols = findCols(df, 'POP5_SEXE1_AGEQ65065') + findCols(df, 'POP5_SEXE2_AGEQ65065')
df['p_65+'] = computePercentage(cols, 'P17_POP')
#Pourcentage de 15-29 ans
cols = findCols(df, 'ACT2A_AGEQ65015_SEXE') + findCols(df, 'ACT2A_AGEQ65020_SEXE') + findCols(df, 'ACT2A_AGEQ65025_SEXE')
df['p_15_29'] = computePercentage(cols, 'P17_POP')
#Calcul le nombre de ménages par commune
cols = findCols(df, 'MEN1_NPERC')
df['nb_menages'] = df[cols].sum(axis = 1)
#Pourcentage de ménage à 1 personne
cols = findCols(df, 'MEN1_NPERC1')
df['p_foyer1pers'] = computePercentage(cols, 'nb_menages')
#Calcul le nombre de familles par commune
cols = findCols(df, 'MEN1_NPERC')
df['nb_familles'] = df[cols].sum(axis = 1)
#Pourcentage de famille mono parentales
cols = findCols(df, 'MEN1_NPERC1')
df['p_fammono'] = computePercentage(cols, 'nb_familles')
#Nbe de personnes dans l'ech
cols = findCols(df, 'FOR2_AGEQ650')
df['nb_catdipl'] = df[cols].sum(axis = 1)
# Pourcentage de pas ou faiblement diplomés
cols = findCols(df, 'DIPL_19A') + findCols(df, 'DIPL_19B') + findCols(df, 'DIPL_19C')
filters = ['AGEQ65015'] #filtre personnes de moins de 20 ans
cols = [s for s in cols if not any(xs in s for xs in filters)]
df['p_faible_dipl'] = computePercentage(cols, 'nb_catdipl')
#Pourcentage de personnes de plus de 75 ans
df['MEN3'] = df[findCols(df, 'AGEQ80_14')].sum(axis=1)
cols = findCols(df, 'AGEQ80_14075') + findCols(df, 'AGEQ80_14080')
df['p_75+'] = computePercentage(cols, 'MEN3')
#Pourcentage de personnes de plus de 65-74 ans
cols = findCols(df, 'AGEQ80_14060') + findCols(df, 'AGEQ80_14065') + findCols(df, 'AGEQ80_14070')
df['p_60_74'] = computePercentage(cols, 'MEN3')
# Proportion de personnes de plus de 20 ans sans diplome
cols = findCols(df, 'DIPL_19')[2:] # POur ne garder queles plus de 20 ans
df['DIPL_20+'] = df[cols].sum(axis=1)
cols = findCols(df, 'DIPL_19A')
df['p_0dipl'] = computePercentage(cols, 'DIPL_20+')
df['p_0dipl']
# Proportion de personnes de plus de 20 ans avec un faible diplome
cols = findCols(df, 'DIPL_19B') + findCols(df, 'DIPL_19C')
df['p_faibldipl'] = computePercentage(cols, 'DIPL_20+')
#Calcul des catégories socioprofessionnelles
colsRef = findEtudeNCols(df, 'POP6', 'CS1_8')
cols = findEtudeNCols(df, 'POP6', 'CS1_86')
df['p_ouv'] = round(df[cols].sum(axis=1)/df[colsRef].sum(axis=1), 4)
cols = findEtudeNCols(df, 'POP6', 'CS1_85')
df['p_empl'] = round(df[cols].sum(axis=1)/df[colsRef].sum(axis=1), 4)
cols = findEtudeNCols(df, 'POP6', 'CS1_82')
df['p_ind'] = round(df[cols].sum(axis=1)/df[colsRef].sum(axis=1), 4)
# Données caf
#Proportion de personnes
df['p_TR50'] = df['PRES_TR50PFRB'] /df['P17_POP']
df['p_TR100'] = df['PRES_TR100PFRB'] /df['P17_POP']
#Proportion ouvrier/agri
cols = findCols(df, 'POP6_CS1_8')
df['POP6CS1_20+'] = df[cols].sum(axis=1)
cols = findCols(df, 'CS1_81') + findCols(df, 'CS1_86')
df['p_ouvragri'] = computePercentage(cols, 'POP6CS1_20+')
#Proportion indépendants
cols = findCols(df, 'CS1_82')
df['p_indé'] = computePercentage(cols, 'POP6CS1_20+')
#COrrection data
df.at[735,'p_ind'] = 0.15
cols
est une liste de listes contenant pour chaque item:
cols = [['p_75+', '+', 'Score +75 ans', 3],
['p_60_74', '+', 'Score 60-74 ans', 2],
['p_15_29', '+', 'Score 15-29ans', 2],
['p_0dipl', '+', 'Score aucun diplome', 3],
['p_faibldipl', '+', 'Score faible diplôme', 2],
['MED17', '-', 'Score revenus\nmedian faible', 1],
['p_foyer1pers', '+', 'Score familles\nmonoparentales\n& foyer 1 pers', 2],
['p_ind', '+', 'Score d\'independants', 1],
['p_empl', '+', 'Score d\'employés', 1],
['p_ouv', '+', 'Score d\'ouvriers', 3]]
def computeScoreWithNA(df, cols):
#Retourne un df de scores de précarité de plusieurs colonnes, peut comporter des colonnes avec NAs
# coldic: dictionnaire de avec orientation
# Les valeurs manquantes ne sont pas prise en compte dans le calcul de normalisation et moyenne du score global
dfT = pd.DataFrame(df.CODGEO)
for col in cols:
variable = col[0]
#df[col] = df.loc[:,col].fillna(df.loc[:,col].mean()) # Rempalce les valeurs manquantes par la moyenne de région
orientation = col[1]
#print(variable, orientation)
vals = df[variable]
if orientation == '-':
dfT[variable + '_score'] = round(((((vals.mean()- vals) / vals.mean()) +1)*100), 1)
elif orientation == '+':
dfT[variable + '_score'] = round(((((vals - vals.mean()) / vals.mean()) +1)*100), 1)
dfT[variable + '_score'] = dfT[variable + '_score']
#display(dfT)
return(dfT)
dfS = computeScoreWithNA(df, cols)
# Gestion des valeurs manquante pour l'indicateur de revenu median
dfS['MED17_score'] = dfS['MED17_score'].fillna(dfS['MED17_score'].median())
#Normalisation des colonnes de scores sur 0-100
def norm(s):
#normalisation d'une serie sur 0-100
s = 100 * (s - s.min()) / (s.max() - s.min())
s = round(s, 1)
return(s)
for col in dfS:
if '_score' in col:
dfS[col + '_norm'] = norm(dfS[col])
# Ne garde que les colonnes normalisées
for col in dfS.columns:
if col.endswith('_score'):
dfS = dfS.drop(col, axis=1)
#Calcul d'un score de précarité sur 0-100 avec facteurs de pondération
coef_sum = 0
dfS['score'] = 0
for col in cols:
coef = int(col[3])
coef_sum += coef
dfS['score'] += dfS[col[0] + '_score_norm'] * coef
dfS= dfS
dfS['score'] = round(dfS['score']/coef_sum, 1)
dfS.at[820,'score'] = dfS['score'].mean()
s = dfS['score']
s = 100 * (s - s.min()) / (s.max() - s.min())
s = round(s, 1)
dfS['score'] = s
# AJout de données sur la commune
dfS['CODGEO'] = dfS['CODGEO'].astype(int)
dfS['Commune'] = df['LIBGEO_x']
dfS['Département'] = df['DEP_x'].astype(int)
#dfS['Dynamique Démographique'] = df['Dynamique Démographique BV']
dfS['Environnement Démographique'] = df['Environnement Démographique'].str.replace(" en croissance démographique", "")
# Réorganisation ordre des colonnes
dfS = dfS[['CODGEO', 'Commune', 'Département',
'Environnement Démographique', 'score', 'p_60_74_score_norm', 'p_75+_score_norm',
'p_15_29_score_norm', 'p_0dipl_score_norm', 'p_faibldipl_score_norm',
'MED17_score_norm', 'p_foyer1pers_score_norm', 'p_ind_score_norm', 'p_empl_score_norm','p_ouv_score_norm'
]]
# Renommage colonnes
for col in dfS.columns:
if "_score_norm" in col:
newcolname = col.replace("_score_norm", "")
newcolname = newcolname.replace("p_", "")
newcolname = newcolname.replace("MED17", "revmed")
newcolname = newcolname.replace('foyer1pers', 'foyer1')
newcolname = 'score_' + newcolname
dfS = dfS.rename(columns={col: newcolname})
dfS.columns
def exportDatatable(df, filename):
""" export un data en datable jquery"""
dfH = df.to_html(index=False,escape=False)
dfH=dfH.replace('<th>','<th class = "th-sm" style="text-align: left">').replace('border="1"','id="example"').replace('class="dataframe"','class="display"')
msgxx ='''
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.min.css"/>
<script>
$(document).ready(function() {
$('#example').DataTable( {
"pageLength": 50,
"language": {"url": "https://cdn.datatables.net/plug-ins/1.10.24/i18n/French.json"}
} );
} );</script>
'''
dfH = msgxx + dfH
dfH=dfH.replace('<th>','<th class = "th-sm"')
f= open(filename, 'w+')
f.write(dfH)
f.close()
#exportDatatable(df, 'ftth_table.html')
exportDatatable(dfS, './tables/scores.html')
#dfS.to_html('./tables/scores.html', index=False)
dfS.to_csv('./scores.csv', sep='\t', index=False)
#Export d'une table pour chaque département
for dep in [44,49,53,72,85]:
dfD = dfS[dfS['Département'] == dep]
dfD = dfD.drop('Département', axis=1)
exportDatatable(dfD, './tables/scores_' + str(dep) + '.html')
exportDatatable(dfS, './tables/scores2.html')
# Histogramme de distribution du score pondéré
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
dfS['score'].hist(bins=35, ax=ax)
fig.savefig('./figures/hist_score.png')
d = dfS.iloc[:,5:].describe().T[['mean', 'std', '25%','50%','75%']].round(1)
d.columns
dicR = {'mean': 'moyenne', 'std':'écart type'}
d =d.rename(columns=dicR).T
display(d)
print(d.to_markdown())
len(cols)
fig, axs = plt.subplots(ncols=5, figsize=(18, 4))
fig.subplots_adjust(left=0.042,right=0.981,hspace=0.35, wspace=0.2)
#fig.suptitle("Proposez-vous des initiations et/ou des formations au numérique ?\n")
i=0
for col in cols[:5]:
newcol = col[0].replace('p_', 'score_')
if col[0] == 'MED17':
newcol = 'score_revmed'
if col[0] == 'p_foyer1pers':
newcol = 'score_foyer1'
dfS[newcol].plot(kind='hist', subplots=True, ax=axs[i], bins=20, ylim =[0,350])#, color=['C3', 'C0', 'C2', 'C4'], yticks =range(0,61,10), ylim =[0,35], fontsize=16, rot=45)
axs[i].set_title(col[2].replace('Score ','Score\n'), fontsize=12)
i+=1
plt.savefig('./figures/hist_scores1.png')
fig, axs = plt.subplots(ncols=5, figsize=(18, 4))
fig.subplots_adjust(left=0.042,right=0.981,hspace=0.35, wspace=0.2)
i=0
for col in cols[5:]:
newcol = col[0].replace('p_', 'score_')
if col[0] == 'MED17':
newcol = 'score_revmed'
if col[0] == 'p_foyer1pers':
newcol = 'score_foyer1'
dfS[newcol].plot(kind='hist', subplots=True, ax=axs[i], bins=20, ylim =[0,350])#, color=['C3', 'C0', 'C2', 'C4'], yticks =range(0,61,10), ylim =[0,35], fontsize=16, rot=45)
axs[i].set_title(col[2].replace('Score ','Score\n'), fontsize=12)
i+=1
plt.savefig('./figures/hist_scores2.png')
d = dfS.groupby(["Département"])['Commune'].count()
s = dfS.groupby(["Département"])['score'].mean()
sup = pd.Series([6809,7172,5175,6206,6720] , index =[44, 49, 53, 72, 85], name='superficie km²')
dens = pd.Series(d/sup*100, name='Communes/100km²')
d = pd.concat([d, s, sup, dens], axis=1).round(1)
print(d.to_markdown())
display(d)
# ANalyse par département
d = dfS.groupby(["Département"])['score', 'score_60_74', 'score_75+', 'score_15_29', 'score_0dipl', 'score_faibldipl', 'score_revmed', 'score_foyer1', 'score_ind', 'score_empl', 'score_ouv'].mean().round(1)
display(d)
print(d.to_markdown())
d = dfS.groupby(["Environnement Démographique"])['score', 'score_60_74', 'score_75+', 'score_15_29', 'score_0dipl', 'score_faibldipl', 'score_revmed', 'score_foyer1', 'score_ind', 'score_empl', 'score_ouv'].mean().round(1)
display(d)
print(d.to_markdown())
d = dfS.groupby(["Environnement Démographique", "Département"])['score', 'score_60_74', 'score_75+', 'score_15_29', 'score_0dipl', 'score_faibldipl', 'score_revmed', 'score_foyer1', 'score_ind', 'score_empl', 'score_ouv'].mean().round(1)
display(d)
print(d.to_markdown())
Réalise la cartographie d'un indicteur ou d'une données stats. Permet d'avoir un regard critique sur ces données.
import folium
import geopandas as gpd
def choroplethInsee(m, variable):
#
filename = '../data/Contourgeocode/a_com2020_PDL_geojson.json'
geodf = gpd.read_file(filename)
geodf['codgeo'] = geodf['codgeo'].astype('int')
folium.Choropleth(
geo_data=geodf,
name='score précarité numérique',
data=dfS,
columns=['CODGEO', variable],
key_on='feature.properties.codgeo',
fill_color='RdYlBu_r',
fill_opacity=0.8,
line_opacity=0.2,
legend_name='DYN SetC',
smooth_factor=0
).add_to(m)
dfT=dfS[['CODGEO', variable]]
geodfT=geodf.merge(dfT, left_on='codgeo', right_on='CODGEO')
style_function = lambda x: {'fillColor': '#ffffff', 'color':'#000000', 'fillOpacity': 0.1, 'weight': 0.1}
highlight_function = lambda x: {'fillColor': '#000000', 'color':'#000000', 'fillOpacity': 0.50, 'weight': 0.1}
tooltips = folium.features.GeoJson(
geodfT,
style_function=style_function,
control=False,
highlight_function=highlight_function,
tooltip=folium.features.GeoJsonTooltip(
fields=['libgeo', variable],
aliases=['',variable + ":"],
style=("background-color: white; color: #333333; font-family: arial; font-size: 12px; padding: 10px;")
)
)
m.add_child(tooltips)
m.keep_in_front(tooltips)
folium.LayerControl().add_to(m)
return(m)
m = folium.Map(location=[47.4791129516, -0.814151724722], zoom_start=8, tiles='OpenStreetMap', max_bounds=True)
dfS['MED17'] = df['MED17']
m = choroplethInsee(m, 'MED17')
m