Groupement de données à partir d'un CSV sur python
Résolu/Fermé- Groupement de données à partir d'un CSV sur python
- Creer un groupe whatsapp a partir d'un autre groupe - Guide
- Annuaire portable gratuit a partir d'un nom ✓ - Forum Mobile
- Python est introuvable. exúcutez sans argument pour procúder ó l - Forum Python
- Exemple base de données access à télécharger gratuit - Forum Access
3 réponses
Modifié le 17 janv. 2023 à 19:48
Bonjour,
Réponse courte : fais comme dit yg_be dans #5 ce qui ressemble au final à ceci :
dispatch.py
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import csv from io import StringIO def dispatch_csv(input_data: iter, key_columns: tuple, delimiter: str = ";"): map_group_file = dict() reader = csv.reader(input_data, delimiter=delimiter) for row in reader: print(row) group = tuple(row[i] for i in key_columns) f_out = map_group_file.get(group) if f_out is None: filename = "_".join(group) + ".csv" map_group_file[group] = f_out = open(filename, "w") if f_out: print(delimiter.join(row), file=f_out) for f_out in map_group_file.values(): f_out.close() key_columns = (2,) # La colonne 3 sert de clé # Avec un fichier d'entrée CSV #with open("test.csv") as f_in: # dispatch_csv(f_in, key_columns, ";") # Avec une chaîne de caractères input_csv = """74a6a0a2a;info1;Groupe1 e2646926e;info2;Groupe2 7d72c9d9e;info3;Groupe1 568t12d55;info4;Groupe1 t47110dr5;info5;Groupe2""" dispatch_csv(StringIO(input_csv), key_columns, delimiter=";")
Exemple :
(mando@silk) (~) $ python3 dispatch.py
(mando@silk) (~) $ cat Groupe1.csv
74a6a0a2a;info1;Groupe1
7d72c9d9e;info3;Groupe1
568t12d55;info4;Groupe1
(mando@silk) (~) $ cat Groupe2.csv
e2646926e;info2;Groupe2
t47110dr5;info5;Groupe2
Réponse détaillée
Tout d'abord pas besoin de ML et de K-means. J'invite d'ailleurs à toujours réfléchir avant d'envisager du ML car ce sont des algorithmes souvent très énergivores, pas toujours adaptés, et souvent appliqués sur des cas d'usages qui n'en ont pas le besoin (c'est ton cas).
Pour traiter ton problème, il y a plusieurs manières de faire :
Concernant la lecture du fichier, tu peux :
- lire le fichier ligne par ligne, faire un split sur le séparateur du csv (voir #3)
- utiliser le module csv (voir #4)
- utiliser pandas.read_csv (mais ça c'est dans les grands jours, pandas c'est l'artillerie lourde)
Concernant la formation des groupes (sous réserve qu'on veuille en faire, voir plus bas) :
- utiliser un dictionnaire si la donnée dans la colonne est hashable (c'est le cas des entiers et des chaînes de caractères). Si tu considères plusieurs colonnes pour former tes agrégat, tu peux rassembler les valeurs impliquées dans un tuple (mais pas dans une liste un ou un set car ils ne sont pas hashable)
- utiliser pandas.groupby (mais ça c'est dans les grands jours, pandas c'est l'artillerie lourde, mince je l'ai déjà dit)
Concernant l'écriture des csv deux stratégies :
- Sans agrégat : on lit chaque ligne et on les dispatche vers le bon fichier en fonction de la colonne (ou les colonnes) permettant de déterminer le groupe.
- écrire les différents fichiers en les ouvrant / fermant chaque fois que le besoin s'en fait sentir. Ce n'est pas terrible comme le souligne à juste titre yg_be dans #5.
- écrire les différents fichiers en les ouvrant de manière opportuniste, sans les fermer (ce qui impose d'utiliser open sans "with", car le contextmanager correspondant ferme le descripteur de fichier quand on quitte le with) pendant toute le traitement du fichier, et les fermer tous une fois le fichier d'entrée complètement lu
- Avec agrégat :
- Une fois les agrégats constitués après avoir lu le fichier d'entrée intégralement, créer un fichier par agrégat en y écrivant les valeurs concernées
La méthode d'yg_be reste la meilleure pour de gros volume de données, car elle évite de maintenir une structure d'agrégat en mémoire pendant la lecture du fichier. En terme d'entrée sortie elle minimise les ouvertures / fermetures de fichier. Elle force en contrepartie à maintenir un dictionnaire qui à chaque identifiant d'agrégat associe un descripteur de fichier.
Bonne chance
17 janv. 2023 à 15:45
bonjour,
Quels moyens as-tu envisagé?
Bonjour,
A vrai dire, je m'étais dit que ça allait être facile, alors j'avais déjà commencé à coder quelques lignes. Mon idée était de récupérer les valeurs en colonne 3 et de créer un groupe lorsque la valeur n'a pas encore été vue.
Par exemple, si je reprends l'exemple :
74a6a0a2a;info1;Groupe1
e2646926e;info2;Groupe2
7d72c9d9e;info3;Groupe1
568t12d55;info4;Groupe1
t47110dr5;info5;Groupe2
Sur la première ligne, je créé un fichier .csv avec la ligne correspondante, ensuite je créé un deuxième fichier .csv pour la deuxième ligne car la valeur de la 3ème colonne ne correspond pas avec la première et ainsi de suite.
Je pense que cela peut fonctionner, mais je me posais quand-même la question de, est-ce que c'est vraiment la meilleure solution ?
Ensuite, je sais que je peux utiliser des algorithmes de ML pour faire ceci, mais même chose est-ce vraiment la bonne manière de faire ? (j'ai déjà utilisé k-means et rcf dans d'autres projets)
A savoir que le fichier CSV ne fera pas 5 lignes mais plutôt 500.
Salut, un dictionnaire convient à faire cela.
.
En partant de ton texte.
.
text = ''' 74a6a0a2a;info1;Groupe1 e2646926e;info2;Groupe2 7d72c9d9e;info3;Groupe1 568t12d55;info4;Groupe1 t47110dr5;info5;Groupe2 ''' groups = {} for line in text.strip().splitlines(): rows = line.split(';') try: groups[rows[2]].append(tuple(rows[0:2])) except KeyError: groups[rows[2]] = [(tuple(rows[0:2]))] from pprint import pprint pprint(groups)
.
Il te faut l'adapter à la lecture de ton csv, ce qui n'est pas bien difficile.
Puis ensuite, il te faudra écrire tes nouveaux csv avec pour nom de fichier, les clés du dict, et pour contenu les valeurs. Cela ne devrait pas être très difficile à réaliser.
Merci pour votre réponse, de mon côté j'avais fait ceci qui fonctionne :
with open('test.csv') as f: reader = csv.reader(f,delimiter=';') value_observed = [] for rows in reader: if rows: tag = rows[9] if tag not in value_observed: value_observed.append(tag) with open(tag + '.csv', 'w') as f: writer = csv.writer(f, delimiter=';') writer.writerow(rows) else: with open(tag + '.csv', 'a') as f: writer = csv.writer(f, delimiter=';') writer.writerow(rows)
Mais je vais étudier votre réponse :)
17 janv. 2023 à 17:13
Le désavantage de ton approche, c'est que tu ouvres et refermes à chaque fois un de tes fichiers de destination. Il serait préférable, pour chaque tag, de mémoriser, par exemple dans un dictionaire, le writer associé.
Un détails, ta variable "rows" mémorise une seule ligne, pourquoi pas "row".
17 janv. 2023 à 17:44
Ok, je vois !
Merci pour ces explications
18 janv. 2023 à 08:23
Bonjour,
Super intéressant, merci cela m'a beaucoup apporté !
C'est d'ailleurs ce type de réflexion que j'aimerais avoir, afin de pouvoir comparer chaque possibilité avec les avantages/inconvénients.
18 janv. 2023 à 17:49
Merci pour ce retour très positif. As-tu d'autres questions liées au sujet initial, ou pouvons nous basculer ce sujet en résolu ?
19 janv. 2023 à 09:10
C'est tout bon pour moi :)