Versionner le résultat d'un calcul

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Le titre n'est pas très explicite donc je m'empresse de vous exposer le problème. Je souhaite prévoir la production laitière d'un troupeau de vaches. Je dispose de données extraites du robot de traite de mon oncle :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Vache  Prod(L)  Cons(kg)  Jour  Jour-dans-la-lactation  Lactation
3505            01/01/2014      
3133    13,17   4,5 01/01/2014  121 3
3541            01/01/2014      
3514            01/01/2014      
1           01/01/2014      
3504    22,78   4,7 01/01/2014  82  1
4997    16,16   5,8 01/01/2014  158 1
3166    21,16   4,6 01/01/2014  252 2
...

Après nettoyage, ces données sont insérées dans une base SQlite :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
CREATE TABLE IF NOT EXISTS CrudeData(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    cow INTEGER NOT NULL,
    date DATE NOT NULL,
    prod REAL NOT NULL, -- L
    cons REAL NOT NULL, -- kg
    lact INTEGER NOT NULL,
    day INTEGER NOT NULL,
    UNIQUE (cow, date)
);

Je vais à présent devoir effectuer des calculs sur ces données : moyennes mobiles, régressions linéaires… Pour cela, je les charge dans un dictionnaire :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "dates"): ["2014-01-01", ...],
            ("crude", "days"): [1, 2, ...],
            ("crude", "prods"): [20.4, 22.0, ...],
            ("crude", "cons"): [11.2, 10.8, ...]
        },
        ("lact", 2): {...}
    },
    ("cow", 4156): {...}
}

Puis, au fil des calculs, le dictionnaire évolue :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "dates"): ["2014-01-01", "2014-01-03", "2014-01-03" ...],
            ("crude", "days"): [1, 2, 3, ...],
            ("crude", "prods"): [20.4, 22.0, 23.1 ...],
            ("crude", "cons"): [11.2, 10.8, 12.3, ...],
            ("ma", "dates", 1): ["2014-01-03", ...],
            ("ma", "days", 1): [3, ...],
            ("ma", "prods", 1): [(20.4 + 22.0 + 23.1)/(2*1 + 1)],
            ("ma", "cons", 1): [(11.2 + 10.8 + 12.3)/(2*1 + 1)]
        },
        ("lact", 2): {...}
    },
    ("cow", 4156): {...}
}

Note : "ma" pour moving averaging et "1" pour le nombre de valeurs à prendre de chaque côté de celle centrale.

Seulement, ce dictionnaire va partir en fumée à la fin de l'exécution de mon programme, alors que je souhaiterais conserver les résultats durement acquis pour pouvoir les utiliser une prochaine fois sans devoir les recalculer. Du coup, j'instaure un système de cache : je sérialise le résultat avec pickle et le stocke dans un fichier. La fois suivante, au moment de faire le calcul, je regarde si le fichier existe et, le cas échéant, j'en charge le résultat.

Seulement, c'était sans compter la mise à jour de la base. Effectivement, les données brutes ayant été acquises vers novembre 2014, certaines lactations de certaines vaches ont été coupées avant la fin. J'aimerais donc, quand je compléterai ma base avec des données plus récentes, que les calculs pour ces lactations soient refaits, en prenant en compte les données ajoutées. Mais, comme la lactation existait lorsque j'ai commencé mes calculs, un fichier lui a été dédié en cache, que mon programme chargera alors que les données d'entrée auront changé. Par exemple :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# On démarre une série d'analyses
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "days"): [1, 2, 3, 4, ..., 105],
            ...

# Moyenne mobile et mise en cache
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "days"): [1, 2, 3, 4, ..., 105],
            ("ma", "days", 2): [3, 4, ..., 103],
            ...

# Mise à jour de la base
# On démarre une série d'analyses
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "days"): [1, 2, 3, 4, ..., 214],
            ...

# Moyenne mobile, en cache
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "days"): [1, 2, 3, 4, ..., 214],
            ("ma", "days", 2): [3, 4, ..., 103],
            ...

# Alors qu'il aurait fallu
{
    ("cow", 1): {
        ("lact", 1): {
            ("crude", "days"): [1, 2, 3, 4, ..., 214],
            ("ma", "days", 2): [3, 4, ..., 212],
            ...

Je pensais alors conserver une trace des arguments avec lesquels les calculs sont effectués, et stocker ça en base :

1
2
key  args  val
"cow-14-lact-1-linreg-prods-X-80"  A  B

En A, j'aurais un hash de mes arguments sérialisés (a priori, je n'ai pas besoin d'être en mesure de pouvoir les retrouver, i.e. de "déhasher" puis désérialiser) et en B, j'aurais le résultat du calcul, sérialisé avec pickle.

Plusieurs questions se posent alors :

  • Est-ce une approche correcte ?
  • Sachant qu'il n'a pas besoin d'être lisible par un humain, le champ key gagnerait-il à contenir des hash plutôt que des chaînes ?
  • Le contenu du champ val serait-il mieux dans un fichier (la base de données ne permettrait de stocker uniquement la clé du calcul et ses arguments) ?

Merci !

Édité par Vayel

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte