<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érialisation, pickle, COVID
Ce notebook aborde les sujets évoqués dans le titre.
Step1:  Sérialisation and pickle
La sérialisation consiste à rassembler tous les informations qu'on souhaite conserver dans un seul bloc contigü. Parmi les formats utilisées, on distingue les formats qu'on peut lire (json, csv, ...) et ceux qui ne peuvent être interprétés qu'avec le même logiciel ou langage qui les a produits.
La sérialisation est plus efficace quand le fichier produit n'est pas lisible car l'information est stockée telle qu'elle est dans la mémoire. Elle est plus facile à restaurer.
On crée un dataframe aléatoire et on écrire et lit sous différents formats.
Step2:  Format csv
Step3:  La lecture est plus rapide que l'écriture. C'est souvent le cas avec les disques SSD, la lecture est plus rapide que l'écriture.
Format pickle
Le format pickle n'est pas à proprement parler un format, python implémente un mécanisme pour sérialiser tout objet python, cela revient à rassembler tous les fragments de mémoires que cet objet occupe en un seul bloc qu'on écrit ensuite sur le disque, on qu'on envoie à une autre ordinateur connecté à internet.
Step4:  La lecture est l'écriture sont très rapides car ce qui est écrit ou lu est directement ce qu'il y a en mémoire. En contrepartie, ces informations ne peuvent être relus que depuis python et souvent depuis la même version de python.
Modèle épidémiologique (SIRD)
Etrangement, il n'était pas possible d'accéder aux données de l'épidémie le jour du TD car le site data.gouv.fr était inacessible suite à une panne chez OVH.
$\frac{dS}{dt} = - \beta \frac{S I}{N}$
$\frac{dI}{dt} = \frac{\beta S I}{N} - \mu I - \nu I$
$\frac{dD}{dt} = \nu I$
$\frac{dR}{dt} = \mu I$
Comme les vraies données sont inaccessibles, on s'intéresse à des données simulées.
Simulation
Step5:  Visualisation
Step6:  Estimation des paramètres
Une fois qu'on a des données, on peut essayer de retrouver la paramètres de la simulation. Mais auparavant, on simule des données un peu plus bruitées en changeant les paramètres du modèle tous les jours.
Step7:  Première idée
On calcule les paramètres chaque jour à partir de la définition du modèle.
Step8:  On pourrait imaginer que les paramètres cherchés soient égaux à la moyenne des valeurs obtenues pour chaque jour. Encore faudrait-il le prouver ou trouver un contre exemple.
Seconde idée 
<ASSISTANT_TASK:>
Python Code:
from jyquickhelper import add_notebook_menu
add_notebook_menu()
%load_ext pyensae
Explanation: Sérialisation, pickle, COVID
Ce notebook aborde les sujets évoqués dans le titre.
End of explanation
import pandas
import numpy
mat = numpy.random.randn(10000, 50)
df = pandas.DataFrame(mat)
df.shape
df.size
for c in range(1, 51):
    df["t%d" % c] = ["a" * c for i in range(df.shape[0])]
df.head(n=2)
df.shape
df.size
Explanation: Sérialisation and pickle
La sérialisation consiste à rassembler tous les informations qu'on souhaite conserver dans un seul bloc contigü. Parmi les formats utilisées, on distingue les formats qu'on peut lire (json, csv, ...) et ceux qui ne peuvent être interprétés qu'avec le même logiciel ou langage qui les a produits.
La sérialisation est plus efficace quand le fichier produit n'est pas lisible car l'information est stockée telle qu'elle est dans la mémoire. Elle est plus facile à restaurer.
On crée un dataframe aléatoire et on écrire et lit sous différents formats.
End of explanation
%timeit df.to_csv('df.csv')
%head df.csv -n 2
%timeit df2 = pandas.read_csv('df.csv')
Explanation: Format csv
End of explanation
import pickle
def pickle_obj(name, obj):
    with open(name, 'wb') as f:
        pickle.dump(obj, f)
%timeit pickle_obj("df.pickle", df)
def load_pickle(name):
    with open(name, 'rb') as f:
        return pickle.load(f)
    
%timeit df = load_pickle('df.pickle')
Explanation: La lecture est plus rapide que l'écriture. C'est souvent le cas avec les disques SSD, la lecture est plus rapide que l'écriture.
Format pickle
Le format pickle n'est pas à proprement parler un format, python implémente un mécanisme pour sérialiser tout objet python, cela revient à rassembler tous les fragments de mémoires que cet objet occupe en un seul bloc qu'on écrit ensuite sur le disque, on qu'on envoie à une autre ordinateur connecté à internet.
End of explanation
def iteration(S, I, R, D, beta, mu, nu, N):
    dR = I * mu
    dD = I * nu
    dS = - S * I * beta / N
    dI = -dS - dR - dD
    return S + dS, I + dI, R + dR, D + dD
iteration(10, 1, 0, 0, 0.1, 0.1, 0.1, 11)
def simulation(n_iter, S, I, R, D, beta, mu, nu):
    sim = numpy.zeros((n_iter + 1, 4))
    sim[0, :] = numpy.array([S, I, R, D]).ravel()
    N = S + I + R + D
    for i in range(n_iter):
        S, I, R, D = iteration(S, I, R, D, beta, mu, nu, N)
        sim[i + 1, :] = numpy.array([S, I, R, D]).ravel()
    return sim
simulation(2, 10, 1, 0, 0, 0.1, 0.1, 0.1)
Explanation: La lecture est l'écriture sont très rapides car ce qui est écrit ou lu est directement ce qu'il y a en mémoire. En contrepartie, ces informations ne peuvent être relus que depuis python et souvent depuis la même version de python.
Modèle épidémiologique (SIRD)
Etrangement, il n'était pas possible d'accéder aux données de l'épidémie le jour du TD car le site data.gouv.fr était inacessible suite à une panne chez OVH.
$\frac{dS}{dt} = - \beta \frac{S I}{N}$
$\frac{dI}{dt} = \frac{\beta S I}{N} - \mu I - \nu I$
$\frac{dD}{dt} = \nu I$
$\frac{dR}{dt} = \mu I$
Comme les vraies données sont inaccessibles, on s'intéresse à des données simulées.
Simulation
End of explanation
%matplotlib inline
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1, figsize=(10, 2))
sim = simulation(20, 10, 0.5, 0, 0, 1.2, 0.2, 0.1)
df = pandas.DataFrame(sim, columns=['S', 'I', 'R', 'D'])
df.plot(ax=ax);
Explanation: Visualisation
End of explanation
def simulation_bruitee(n_iter, S, I, R, D, beta, mu, nu):
    sim = numpy.zeros((n_iter + 1, 4))
    sim[0, :] = numpy.array([S, I, R, D]).ravel()
    N = S + I + R + D
    for i in range(n_iter):
        b = numpy.random.randn(1) * beta / 5 + beta
        m = numpy.random.randn(1) * mu / 5 + mu
        n = numpy.random.randn(1) * nu / 5 + nu
        S, I, R, D = iteration(S, I, R, D, b, m, n, N)
        sim[i + 1, :] = numpy.array([S, I, R, D]).ravel()
    return sim
simulation_bruitee(2, 10, 1, 0, 0, 0.1, 0.1, 0.1)
fig, ax = plt.subplots(1, 1, figsize=(10, 2))
sim_bruit = simulation_bruitee(20, 10, 0.5, 0, 0, 1.2, 0.2, 0.1)
df = pandas.DataFrame(sim_bruit, columns=['S', 'I', 'R', 'D'])
df.plot(ax=ax);
Explanation: Estimation des paramètres
Une fois qu'on a des données, on peut essayer de retrouver la paramètres de la simulation. Mais auparavant, on simule des données un peu plus bruitées en changeant les paramètres du modèle tous les jours.
End of explanation
def estimation_coefficient(sim):
    N = sim.sum(axis=1)
    diff = sim[1:] - sim[:-1]
    mu = diff[:, 2] / sim[:-1, 1]
    nu = diff[:, 3] / sim[:-1, 1]
    beta = - diff[:, 0] / (sim[:-1, 1] * sim[:-1, 0]) * N[:-1]
    return dict(beta=beta, mu=mu, nu=nu)
df = pandas.DataFrame(estimation_coefficient(sim_bruit))
df.head(n=1)
df.plot(figsize=(10,2));
Explanation: Première idée
On calcule les paramètres chaque jour à partir de la définition du modèle.
End of explanation
def distance_sim(obs, sim):
    return ((obs - sim) ** 2).sum() / obs.size
distance_sim(sim, sim_bruit)
def optimisation(obs):
    est = estimation_coefficient(obs)
    b0 = est['beta'].mean()
    m0 = est['mu'].mean()
    n0 = est['nu'].mean()
    n_iter = obs.shape[0] - 1
    S, I, R, D = obs[0]
    beta, mu, nu = b0, m0, n0
    distance = distance_sim(obs, simulation(n_iter, S, I, R, D, b0, m0, n0))
    distance0 = distance
    for i in range(0, 100):
        b = numpy.random.randn(1) * b0 / 5 + b0
        m = numpy.random.randn(1) * m0 / 5 + m0
        n = numpy.random.randn(1) * n0 / 5 + n0      
        sim = simulation(n_iter, S, I, R, D, b, m, n)
        d = distance_sim(obs, sim)
        if distance is None or d < distance:
            distance = d
            beta, mu, nu = b, m, n
    return dict(b0=b0, mu0=m0, nu0=n0, beta=beta, mu=mu, nu=nu,
                distance=distance, distance0=distance0)
optimisation(sim_bruit)
Explanation: On pourrait imaginer que les paramètres cherchés soient égaux à la moyenne des valeurs obtenues pour chaque jour. Encore faudrait-il le prouver ou trouver un contre exemple.
Seconde idée : problèmes d'optimisation
On cherche à transformer le problème d'estimation en un problème d'optimisation de telle sorte que les paramètres en sont la solution. L'idée de simuler en fonction d'un jeu de paramètres puis de calculer une distance entre cette simulation et les données observées.
Le problème de cette solution est qu'il faut essayer plein de valeur, au hasard pour faire simple. Donc on se sert de la fonction précédente comme point de départ et on tire des valeurs tout autour.
End of explanation
<END_TASK>