<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Séance big data
Découverte de plusieurs façons de calculer des statistiques sur des fichiers volumineux.
Step1:  Les données
On récupère un fichier de la DAMIR. Le fichier une fois décompressé fait plus de quatre Go. Vous pouvez le télécharger directement depuis le site ou prendre une version de backup. Vous trouvez d'autres données intéressantes sur le sujet sur le projet SGMAP-AGD/DAMIR.
Step2:  Il est impossible de le charger en mémoire en entier. On regarde les premières lignes.
Step3:  On calcule le nombre de lignes 
Step4:  On peut aussi utiliser pandas.read_csv pour regarder les premières lignes.
Step5:  Répartition des dépenses selon l'âge
C'est la variable AGE_BEN_SNDS mais on ne peut toujours pas charger le fichier en mémoire.
Itérateur sur des dataframes
Il faut utiliser le paramètre iterator.
Step6:  Il faut calculer la distribution des âges pour chaque dataframe.
Step7:  Les versions de pandas ont quelques différences. Voici celle utilisées pour ce notebook.
Step8:  Difficile d'interpréter ce graphique sans le comparer à la pyramide des âges mais ce n'est pas l'objectif ici. Chaque statistique prend un peu de temps. Et si nous tirions un échantillon aléatoire à 1%.
Echantillon
Step9:  pickle
Le module pickle permet de sérialiser. Cette opération transforme le contenu d'un objet tel qu'il est en mémoire en une séquence d'octets qu'on peut alors enregistrer sur disque. Comme ce format de fichier est plus proche de la mémoire, il se charge beaucoup plus vite. Cela permet de gagner un peu de temps. L'inconvénient est que ce format n'est pas toujours compatible d'une version de python ou pandas à l'autre.
Step10:  SQLite3
Un échantillon fait disparaître les classes les moins représentées. On peut accélérer le traitement en passant par Sqlite et disponible via le module sqlite. Première étape 
Step11:  C'est un peu long mais le calcul de statistique est plus rapide par la suite.
Step12:  On peut aussi programmer des commandes magiques pour alléger la syntaxe.
Step13:  dask
dask fonctionne un peu comme pandas excepté que l'exécution des requêtes est différée. On utilise read_csv.
Step14:  Les trois lignes qui suivent sont très rapides.
Step15:  La suivante, beaucoup moins.
Step16:  C'est plus qu'avec SQLite3 mais dans cet exemple, dask relit le fichier à chaque calcul car il ne stocke pas un dataframe dans un format intermédiaire plus efficace tel que parquet. dask propose des idées pour optimiser les calculs Dask DataFrame Performance Tips.
Grandes matrices
Les dataframes acceptent un type différent pour chaque colonne. Si toutes les colonnes sont numériques et de même types, on peut s'orienter vers d'autres solutions.
Zarr
zarr permet de manipuler des matrices qui ne tiennent pas en mémoire de la même façon que numpy. Les données sont compressés et parfois stockées sur disque. Ce module masque beaucoup de détails en proposant une interface connue.
<ASSISTANT_TASK:>
Python Code:
from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline
Explanation: Séance big data
Découverte de plusieurs façons de calculer des statistiques sur des fichiers volumineux.
End of explanation
import os
filename = "bigdata/A201612_small.csv"
# pour travailler avec un fichier plus gros (4 Go)
# filename = "bigdata/A201612.csv"
xlsfile = "bigdata/Lexique_open-DAMIR.xls"
if not os.path.exists(filename):
    from pyensae.datasource import download_data
    if not os.path.exists("bigdata"):
        os.mkdir("bigdata")
    filenamegz = filename.replace(".csv", ".csv.gz")
    download_data(os.path.split(filenamegz)[-1], whereTo=".")
    download_data(os.path.split(xlsfile)[-1], whereTo="bigdata")
    if not os.path.exists(filename):
        filename = os.path.split(filename)[-1]
os.stat(filename).st_size / 2**30
Explanation: Les données
On récupère un fichier de la DAMIR. Le fichier une fois décompressé fait plus de quatre Go. Vous pouvez le télécharger directement depuis le site ou prendre une version de backup. Vous trouvez d'autres données intéressantes sur le sujet sur le projet SGMAP-AGD/DAMIR.
End of explanation
with open(filename, "r") as f:
    for i, line in enumerate(f):
        print(line.strip("\r\n"))
        if i >= 5:
            break
Explanation: Il est impossible de le charger en mémoire en entier. On regarde les premières lignes.
End of explanation
with open(filename, "r") as f:
    nb = 0
    for line in f:
        nb += 1
nb
Explanation: On calcule le nombre de lignes :
End of explanation
import time
import pandas
begin = time.perf_counter()
df = pandas.read_csv(filename, sep=";", nrows=100)
print(time.perf_counter() - begin)
df.head()
df.head().T
variables = pandas.read_excel(xlsfile, skiprows=2)
cols = variables.columns[:2]
variables[cols].dropna()
Explanation: On peut aussi utiliser pandas.read_csv pour regarder les premières lignes.
End of explanation
dfs = []
for i, df in enumerate(pandas.read_csv(filename, 
            sep=";", iterator=True, chunksize=10000)):
    dfs.append(df)
    if i >= 5:
        break        
dfs[0].head()
Explanation: Répartition des dépenses selon l'âge
C'est la variable AGE_BEN_SNDS mais on ne peut toujours pas charger le fichier en mémoire.
Itérateur sur des dataframes
Il faut utiliser le paramètre iterator.
End of explanation
from datetime import datetime
ages = []
for i, df in enumerate(pandas.read_csv(filename, 
                    sep=";", iterator=True, chunksize=10000)):
    sub = df[["AGE_BEN_SNDS", "PRS_REM_MNT"]].copy()
    gr = sub.groupby("AGE_BEN_SNDS").sum()
    ages.append(gr)
    if len(ages) % 100 == 0:
        print(datetime.now(), len(ages), "lignes", 10000 * len(ages))
Explanation: Il faut calculer la distribution des âges pour chaque dataframe.
End of explanation
pandas.__version__
age = pandas.concat(ages)
agg = age.groupby("AGE_BEN_SNDS").sum()
agg.plot(kind="bar");
Explanation: Les versions de pandas ont quelques différences. Voici celle utilisées pour ce notebook.
End of explanation
ech = []
for i, df in enumerate(pandas.read_csv(filename, 
                    sep=";", iterator=True, chunksize=10000)):
    sub = df.sample(frac=0.01)
    ech.append(sub)
    if len(ech) % 100 == 0:
        print(datetime.now(), len(ech), "lignes", 10000 * len(ech))
echantillon = pandas.concat(ech)
echantillon.shape
echantillon[["AGE_BEN_SNDS", "PRS_REM_MNT"]] \
        .groupby("AGE_BEN_SNDS").sum().plot(kind="bar");
Explanation: Difficile d'interpréter ce graphique sans le comparer à la pyramide des âges mais ce n'est pas l'objectif ici. Chaque statistique prend un peu de temps. Et si nous tirions un échantillon aléatoire à 1%.
Echantillon
End of explanation
echantillon.to_csv("echantillon.csv", sep=";", index=False)
import os
os.stat("echantillon.csv").st_size / 2**20
begin = time.perf_counter()
ech2 = pandas.read_csv("echantillon.csv", sep=";")
print(time.perf_counter()-begin)
ech2.shape
echantillon.to_pickle("echantillon.pickle")
begin = time.perf_counter()
ech3 = pandas.read_pickle("echantillon.pickle")
print(time.perf_counter()-begin)
Explanation: pickle
Le module pickle permet de sérialiser. Cette opération transforme le contenu d'un objet tel qu'il est en mémoire en une séquence d'octets qu'on peut alors enregistrer sur disque. Comme ce format de fichier est plus proche de la mémoire, il se charge beaucoup plus vite. Cela permet de gagner un peu de temps. L'inconvénient est que ce format n'est pas toujours compatible d'une version de python ou pandas à l'autre.
End of explanation
import sqlite3
cnx = sqlite3.connect('damir2.db3')
for i, df in enumerate(pandas.read_csv(filename, 
            sep=";", iterator=True, chunksize=100000)):
    df.to_sql(con=cnx, name="damir", if_exists="replace" if i == 0 else "append")
    if (i+1) % 10 == 0:
        print(datetime.now(), (i+1) * 100000, "lignes")
print("done")
Explanation: SQLite3
Un échantillon fait disparaître les classes les moins représentées. On peut accélérer le traitement en passant par Sqlite et disponible via le module sqlite. Première étape : créer la base.
End of explanation
import time
begin = time.perf_counter()
dfage = pandas.read_sql(
    'select AGE_BEN_SNDS, count(*) from damir group by AGE_BEN_SNDS', cnx)
print("time", time.perf_counter() - begin)
dfage
Explanation: C'est un peu long mais le calcul de statistique est plus rapide par la suite.
End of explanation
%load_ext pyensae
%SQL_connect damir.db3
%SQL_tables
%%SQL
SELECT * FROM damir LIMIT 5
%lsmagic
Explanation: On peut aussi programmer des commandes magiques pour alléger la syntaxe.
End of explanation
import dask.dataframe
dfdk = dask.dataframe.read_csv(filename, sep=";")
dfdk.head(n=2)
Explanation: dask
dask fonctionne un peu comme pandas excepté que l'exécution des requêtes est différée. On utilise read_csv.
End of explanation
import dask
dask.__version__
dfdk2 = dfdk[["AGE_BEN_SNDS", "PRS_REM_MNT"]]
grdk = dfdk2.groupby("AGE_BEN_SNDS").sum()
Explanation: Les trois lignes qui suivent sont très rapides.
End of explanation
begin = time.perf_counter()
res = grdk.compute()
print(time.perf_counter() - begin)
ech4 = dfdk.sample(frac=0.01)
dfech = ech4.compute()
type(dfech)
res
Explanation: La suivante, beaucoup moins.
End of explanation
import zarr
z = zarr.zeros((10000, 10000), chunks=(1000, 1000), dtype='i4')
z
z[4,5]
Explanation: C'est plus qu'avec SQLite3 mais dans cet exemple, dask relit le fichier à chaque calcul car il ne stocke pas un dataframe dans un format intermédiaire plus efficace tel que parquet. dask propose des idées pour optimiser les calculs Dask DataFrame Performance Tips.
Grandes matrices
Les dataframes acceptent un type différent pour chaque colonne. Si toutes les colonnes sont numériques et de même types, on peut s'orienter vers d'autres solutions.
Zarr
zarr permet de manipuler des matrices qui ne tiennent pas en mémoire de la même façon que numpy. Les données sont compressés et parfois stockées sur disque. Ce module masque beaucoup de détails en proposant une interface connue.
End of explanation
<END_TASK>