<jupyter_start><jupyter_text>2A.data - DataFrame et Graphes - correctionOpérations standards sur les dataframes ([pandas](http://pandas.pydata.org/)) et les matrices ([numpy](http://www.numpy.org/)). Graphiques avec [matplotlib](https://matplotlib.org/)).<jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt
from jyquickhelper import add_notebook_menu
add_notebook_menu()<jupyter_output><empty_output><jupyter_text>Exercice 1 : créer un fichier Excel    On souhaite récupérer les données [donnees_enquete_2003_television.txt](http://www.xavierdupre.fr/enseignement/complements/donnees_enquete_2003_television.txt) (source : [INSEE](http://www.insee.fr/fr/themes/detail.asp?ref_id=fd-hdv03&page=fichiers_detail/HDV03/telechargement.htm)).* ``POIDSLOG`` : Pondération individuelle relative* ``POIDSF`` : Variable de pondération individuelle* ``cLT1FREQ`` : Nombre d'heures en moyenne passées à regarder la télévision * ``cLT2FREQ`` : Unité de temps utilisée pour compter le nombre d'heures passées à regarder la télévision, cette unité est représentée par les quatre valeurs suivantes    * 0 : non concerné    * 1 : jour    * 2 : semaine    * 3 : mois     Ensuite, on veut :1. Supprimer les colonnes vides2. Obtenir les valeurs distinctes  pour la colonne ``cLT2FREQ``3. Modifier la matrice pour enlever les lignes pour lesquelles l'unité de temps (cLT2FREQ) n'est pas renseignée ou égale à zéro.4. Sauver le résultat au format Excel.Vous aurez peut-être besoin des fonctions suivantes :* [numpy.isnan](http://docs.scipy.org/doc/numpy/reference/generated/numpy.isnan.html)* [DataFrame.apply](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html)* [DataFrame.fillna](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.fillna.html) ou [DataFrame.isnull](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.isnull.html)* [DataFrame.copy](http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.copy.html)<jupyter_code>import pandas
from ensae_teaching_cs.data import donnees_enquete_2003_television
df = pandas.read_csv(donnees_enquete_2003_television(), sep="\t", engine="python")
df.head()<jupyter_output><empty_output><jupyter_text>On enlève les colonnes vides :<jupyter_code>df = df [[ c for c in df.columns if "Unnamed" not in c]]
df.head()
notnull = df [ ~df.cLT2FREQ.isnull() ]  # équivalent )  df [ df.cLT2FREQ.notnull() ] 
print(len(df),len(notnull))
notnull.tail()
notnull.to_excel("data.xlsx")  # question 4<jupyter_output><empty_output><jupyter_text>Pour lancer Excel, vous pouvez juste écrire ceci :<jupyter_code>%system "data.xlsx"<jupyter_output><empty_output><jupyter_text>Vous devriez voir quelque chose comme ceci :<jupyter_code>from IPython.display import Image
Image("td10exc.png")<jupyter_output><empty_output><jupyter_text>Questions* **Que changerait l'ajout du paramètre ``how='outer'`` dans ce cas ?*** **On cherche à joindre deux tables A,B qui ont chacune trois clés distinctes : $c_1, c_2, c_3$. Il y a respectivement dans chaque table $A_i$ et $B_i$ lignes pour la clé $c_i$. Combien la table finale issue de la fusion des deux tables contiendra-t-elle de lignes ?** L'ajout du paramètres ``how='outer'`` ne changerait rien dans ce cas car les deux tables fusionnées contiennent exactement les mêmes clés.Le nombre de lignes obtenus serait $\sum_{i=1}^{3} A_i B_i$. Il y a trois clés, chaque ligne de la table A doit être associée à toutes les lignes de la table B partageant la même clé. Exercice 2 : lambda fonctionEcrire une lambda fonction qui prend deux paramètres et qui est équivalente à la fonction suivante :<jupyter_code>def delta(x,y):
    return max(x,y)- min(x,y)
delta = lambda x,y : max(x,y)- min(x,y)
delta(4,5)
import random 
df["select"]= df.apply( lambda row : random.randint(1,10), axis=1) 
echantillon = df [ df["select"] ==1 ]
echantillon.shape, df.shape<jupyter_output><empty_output><jupyter_text>Exercice 3 : moyennes par groupes    Toujours avec le même jeu de données ([marathon.txt](http://www.xavierdupre.fr/enseignement/complements/marathon.txt)), on veut ajouter une ligne à la fin du tableau croisé dynamique contenant la moyenne en secondes des temps des marathons pour chaque ville.<jupyter_code>from ensae_teaching_cs.data import marathon
import pandas
df = pandas.read_csv(marathon(), sep="\t", names=["ville", "annee", "temps","secondes"])
df.head()<jupyter_output><empty_output><jupyter_text>La solution requiert trois étapes.1. Pour avoir la moyenne par villes, il faut grouper les lignes associées à la même villes.2. Ensuite, il faut introduire ces moyennes dans la table initiale : on fusionne.3. On effectue le même pivot que dans l'énoncé.<jupyter_code># étape 1
# par défaut, la méthode groupby utilise la clé de group comme index
# pour ne pas le faire, il faut préciser as_index = False
gr = df[["ville","secondes"]].groupby("ville", as_index=False).mean()
gr.head()
# étape 2 - on ajoute une colonne
tout = df.merge( gr, on="ville")
tout.head()
# étape 3
piv = tout.pivot("annee","ville","secondes_x")
piv.tail()<jupyter_output><empty_output><jupyter_text>A partir de là, on ne voit pas trop comment s'en sortir. Voici ce que je propose :1. On effectue un pivot sur la petite matrice des moyennes.2. On ajoute ce second pivot avec le premier (celui de l'énoncé).<jupyter_code>gr["annee"] = "moyenne"
pivmean = gr.pivot("annee","ville","secondes")
pivmean
piv = df.pivot("annee","ville","secondes")
pandas.concat( [ piv, pivmean ]).tail()<jupyter_output><empty_output><jupyter_text>En résumé, cela donne (j'ajoute aussi le nombre de marathons courus) :<jupyter_code>import pandas, urllib.request
from ensae_teaching_cs.data import marathon
df = pandas.read_csv(marathon(filename=True), 
                     sep="\t", names=["ville", "annee", "temps","secondes"])
piv = df.pivot("annee","ville","secondes")
gr = df[["ville","secondes"]].groupby("ville", as_index=False).mean()
gr["annee"] = "moyenne"
pivmean = gr.pivot("annee","ville","secondes")

pandas.concat([piv, pivmean]).tail()<jupyter_output><empty_output><jupyter_text>Exercice 4 : écart entre les mariés1. En ajoutant une colonne et en utilisant l'opération [group by](http://pandas.pydata.org/pandas-docs/stable/groupby.html), on veut obtenir la distribution du nombre de mariages en fonction de l'écart entre les mariés. Au besoin, on changera le type d'une colone ou deux.2. On veut tracer un nuage de points avec en abscisse l'âge du mari, en ordonnée, l'âge de la femme. Il faudra peut-être jeter un coup d'oeil sur la documentation de la méthode [plot](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.plot.html).<jupyter_code>import urllib.request
import zipfile
import http.client

def download_and_save(name, root_url):
    try:
        response = urllib.request.urlopen(root_url+name)
    except (TimeoutError, urllib.request.URLError, http.client.BadStatusLine):
        # back up plan
        root_url = "http://www.xavierdupre.fr/enseignement/complements/"
        response = urllib.request.urlopen(root_url+name)
    with open(name, "wb") as outfile:
        outfile.write(response.read())

def unzip(name):
    with zipfile.ZipFile(name, "r") as z:
        z.extractall(".")

filenames = ["etatcivil2012_mar2012_dbase.zip", 
             "etatcivil2012_nais2012_dbase.zip",
             "etatcivil2012_dec2012_dbase.zip", ]
root_url = 'http://telechargement.insee.fr/fichiersdetail/etatcivil2012/dbase/'

for filename in filenames:
    download_and_save(filename, root_url)
    unzip(filename)
    print("Download of {}: DONE!".format(filename))
import pandas
try:
    from dbfread_ import DBF
    use_dbfread = True
except ImportError as e :
    use_dbfread = False
    
if use_dbfread:
    print("use of dbfread")
    def dBase2df(dbase_filename):
        table = DBF(dbase_filename, load=True, encoding="cp437")
        return pandas.DataFrame(table.records)

    df = dBase2df('mar2012.dbf')
else :
    print("use of zipped version")
    import pyensae.datasource
    data = pyensae.datasource.download_data("mar2012.zip")
    df = pandas.read_csv(data[0], sep="\t", encoding="utf8", low_memory=False)  
    
print(df.shape, df.columns)
df.head()
df["ageH"] = df.apply (lambda r:  2014 - int(r["ANAISH"]), axis=1)
df["ageF"] = df.apply (lambda r:  2014 - int(r["ANAISF"]), axis=1)
df.head()
df.plot(x="ageH",y="ageF", kind="scatter")
df.plot(x="ageH",y="ageF", kind="hexbin")<jupyter_output><empty_output><jupyter_text>Exercice 5 : graphe de la distribution avec pandasLe module ``pandas`` propose un panel de graphiques standard faciles à obtenir. On souhaite représenter la distribution sous forme d'histogramme. A vous de choisir le meilleure graphique depuis la page [Visualization](http://pandas.pydata.org/pandas-docs/stable/visualization.html).<jupyter_code>df["ANAISH"] = df.apply (lambda r:  int(r["ANAISH"]), axis=1)
df["ANAISF"] = df.apply (lambda r:  int(r["ANAISF"]), axis=1)
df["differenceHF"] = df.ANAISH - df.ANAISF
df["nb"] = 1
dist = df[["nb","differenceHF"]].groupby("differenceHF", as_index=False).count()
df["differenceHF"].hist(figsize=(16,6), bins=50)<jupyter_output><empty_output><jupyter_text>Exercice 6 : distribution des mariages par jour    On veut obtenir un graphe qui contient l'histogramme de la distribution du nombre de mariages par jour de la semaine et d'ajouter une seconde courbe correspond avec un second axe à la répartition cumulée.<jupyter_code>df["nb"] = 1
dissem = df[["JSEMAINE","nb"]].groupby("JSEMAINE",as_index=False).sum()
total = dissem["nb"].sum()
repsem = dissem.cumsum() 
repsem["nb"] /= total

ax = dissem["nb"].plot(kind="bar")
repsem["nb"].plot(ax=ax, secondary_y=True)
ax.set_title("distribution des mariages par jour de la semaine")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12879484820607176, 'fraction_numerical': 0.01308392108760094, 'mean_word_length': 5.44532279314888, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 1, 'lorem ipsum': 0, 'www.': 5, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '156952', 'license': 'MIT', 'n_tokens_mistral': 3619, 'n_tokens_neox': 3522, 'n_words': 881, 'path': '_doc/notebooks/td2a/td2a_correction_session_1.ipynb', 'repo_name': 'sdpython/ensae_teaching_cs', 'size': '9783'}