Déclaration / Exploitation de (très) nombreuses variables

a marqué ce sujet comme résolu.

Bonjour, je suis sur un script qui me pose soucis.

J'ai un fichier txt que je dois traiter :

  • Ce fichier fait plus de 10 000 lignes.
  • Chaque ligne est de taille variable et contient diverses informations dont des codes correspondants à des actes de rééducation. Il existe une liste d'actes de rééducation (plus ou moins 1 500 à la louche).

Mon soucis : j'aimerais faire des compteurs d'actes.

Je pourrais donc :

  • Créer des compteurs pour chaque acte et les incrémenter à chaque fois que j'en croise un dans le fichier txt :
1
2
3
4
5
6
7
8
9
# Déclaration / initalisation des variables
cpt_CSARR_1 = 0
cpt_CSARR_2 = 0
cpt_CSARR_n = 0

# Extraction des CSARR dans les lignes puis incrémentation des cpt quand je trouve un code dans le fichier
cpt_CSARR_1 =+ 1
cpt_CSARR_2 =+ 1
cpt_CSARR_1 =+ 1
  • Récupérer le 1er code croisé, tester si la variable cpt_CSARR correspondante existe :

Si OUI : j'incrémente le cpt correspondant

1
cpt_CSARR_X =+ 1

Si NON : j'initialise la variable et j'incrémente

1
2
cpt_CSARR_X = 0
cpt_CSARR_X =+ 1

ou pour gagner une ligne

1
cpt_CSARR_X = 1

Puis recommencer au code suivant

Synthèse :

  • Dans un cas je déclare en début de fichier mes 1.500 compteurs puis j'ai un test if pour chaque code rencontré afin d'incrémenter le cpt.

  • Dans un autre cas, j'ai des tests if qui déclare la variable et qui l'incrémente.

A savoir que cette liste de codes peut potentiellement évoluer tous les ans.

Une autre solution envisageable serait de déclarer ces compteurs dans un fichier txt, json, xml, pickle ou autre mais je ne vois pas trop comment procéder.

Ma grosse peur est la lenteur d'exécution du script : beaucoup de if, beaucoup de variables déclarées.

J'espère avoir été clair.

Avez-vous un(des) conseil(s) pour que je puisse avancer ? Merci d'avance :)

+0 -0

Je penses que c'est plus efficace de déclarer les compteurs en début de script non ? Tu ne peux pas déclarer les compteurs dans un fichier à coté et concaténer les deux fichiers ou importer le fichier qui comporte les noms des variables dans celui qui traite le document ?

Sinon pour la lenteur tu as testé ? Si ça ce trouve ce n'est pas si long que ça (enfin tout dépends de ce que tu appel long, de la machine, etc).

Je vais peut-être dire une bêtise mais tu ne peux pas convertir ce fichier texte en base de données et ainsi utiliser des requêtes sur cette bdd ? Je penses que ça serait bien plus rapide de passer par là !

+1 -4

Effectivement, se taper la déclaration de 1500 variables, ce serait dommage (et vraiment pas efficace)…

Je plussoie allègrement l'utilisation du Counter (c'est encore mieux qu'un dict, même si le dictionnaire est déjà un excellent réflexe). Décomposons le schmilblick.

Un Counter peut être construit en lui passant un itérable, comme une chaîne de caractères, une liste, un générateur, etc.. Lorsque c'est le cas, il va simplement compter les occurrences de chaque élément de l'itérable, et donc faire exactement ce que tu cherches à faire.

Supposons pour l'instant que tu aies écrit une fonction parse_codes(file_obj) qui prend un fichier ouvert en argument et te retourne une séquence itérable de ces fameux codes que tu cherches à extraire. Alors le compteur s'utilise comme ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from collections import Counter

FILE_PATH = "/chemin/vers/ton/fichier"

def parse_codes(file_obj):
    # on fera cette fonction plus tard
    raise NotImplemented

count = None
with open(FILE_PATH) as infile:
    count = Counter(parse_codes(infile))

Et c'est tout ! Si tu veux connaître le nombre d'occurrences de foobar, il suffit d'aller chercher count["foobar"].

Maintenant pour cette fonction parse_codes ne sachant pas à quoi ressemblent tes fichiers je vais faire les hypothèses suivantes :

  • ils sont très très gros donc il vaut mieux éviter de les charger tout entiers en mémoire,
  • ils contiennent un et un seul code par ligne,
  • pour la commodité on va dire que c'est le premier élément d'une séquence arbitrairement longue de champs séparés par des virgules.

Dans ces conditions voici une bonne fonction parse_codes :

1
2
3
4
def parse_codes(file_obj):
    for line in file_obj:
        code = line.split(',')[0]
        yield code

… et en fait cette fonction est tellement simple qu'on peut la remplacer par une bête expression génératrice :

1
2
3
4
5
6
7
8
from collections import Counter

FILE_PATH = "/chemin/vers/ton/fichier"
count = None
with open(FILE_PATH) as infile:
    count = Counter(
        line.split(',')[0] for line in infile
    )

Et voilà le travail. :)

+3 -0

Salut, désolé pour le temps de réponse mais je suis en vacances. Alors pour le fichier il fait plus de 10 000 lignes et la longueur de la ligne diffère en fonction de différents paramètres.

Voici une ligne : pour cet exemple en gras (016) qui correspond au nombre de codes dans la ligne et ensuite le reste en gras correspond aux codes :

M19XXXXXXXX9M090005965201506093 030109C0000 16062015 180119791443502160620158 252015011010011 52A Z501 G831 S0620 1111110401601 M7967 M9085 Z993 F0671 ANQ+171 27 01160620150101 PCQ+179 27 01160620150101 ZGQ+217 27 01160620150101 AGR+102 22 01160620150201 AZQ+131 22 01160620150201 AGR+102 22 01160620150201 CER+223 27 01170620150101 PCR+285 27 01170620150101 PER+223 27 01170620150101 AGR+102 22 01170620150201 AGR+102 22 01170620150201 CER+223 27 01190620150101 PCR+285 27 01190620150101 PER+223 27 01190620150101 AGR+102 22 01190620150201 AGR+102 22 01190620150201 17062015PCLB003-0001 01

Je peux donc avoir plusieurs codes par lignes, le fichier 2015 fait 6 344 ko pour 10 283 lignes Merci nohar pour ta réponse détaillée. Merci à tous pour vos propositions, j'étudierais ça à la fin des vacances :)

+0 -0

Bon, donc tu auras besoin d'une fonction parse_codes un peu plus couillue que celle que j'ai mise dans mon exemple, mais il reste parfaitement valable.

~6 Mo de fichier, c'est pas non plus la mort de le lire d'un coup, m'enfin je préfère quand même le lire ligne par ligne, c'est de toute façon conceptuellement plus propre.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

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