Traiter de très gros CSV en python

accélérer le traitement

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous,

J’avais une question "théorique" sur Python (et non sur un bout de code particulier) pour un mini-projet que je dois faire pour dépanner un ami :

Il cherche à filtrer un CSV de base d’adresse mail en supprimant toutes les occurrences d’adresses "pourries" que nous connaissons .

Pour ça il a deux CSV : sa base et un CSV énorme qui liste toutes les adresses "pourries"

Le but est de tous les jours prendre le fichier d’adresse et de le purger de toutes les adresses du CSV de liste pourries(environ 600 000 lignes) .

C’est pour ça que je demande votre aide dans la logique car j’ai fait un truc fonctionnel mais qui je pense pourrait être optimisé.

En gros je charge le CSV pourri dans une liste (après tout c’est un CSV à une seule colonne) et ensuite je parse le CSV de base avec pour chaque ligne un test pour savoir si l’adresse est dans ma liste. Si non j’inscrit la ligne complète dans un nouveau CSV.

Est-ce qu(’il y aurait une manière plus "propre" et surtout plus efficace en terme de temps de traitement de faire ça ?

Merci :)

Salut,

Ça dépend de la taille de ce que tu appelles énorme : est-ce que ça tient sans problème en mémoire ? Sinon, il faudra t’orienter vers une base de données.

Ce qui peut être intéressant, aussi, c’est d’utiliser une approche probabiliste type filtre de Bloom pour éviter trop de requêtes sur la grosse liste. Tu peux savoir avec certitude qu’un élément n’est pas dans la liste. Et tu peux facilement éliminer les faux positifs en vérifiant pour chaque cas indiqué.

Ba est-ce que ça tiens en mémoire je sais pas . Je sais que la "grosse" liste ferra au fur et a mesure du temps entre 600 000 et 1 000 000 d’adresse mail . Faut passer par une BDD pour un volume de ce type ?

Pour l’autre solution je vais chercher sur internet voir si ça peut aider :)

Ça n’est pas une autre solution, c’est complémentaire. Ça évite des requêtes à tout bout de champ (tu ne les conserves qu’en cas de doute).

Un million d’adresses ce n’est pas énorme. Je crois que le grand maximum pour la longueur d’une adresse email, c’est 320 octets. Donc ça doit prendre quelques centaines de Mo en mémoire, grand maximum (c’est déjà beaucoup, mais ça tient largement sur les architectures actuelles).

Salut,

1 million d’adresses, c’est rien du tout. Si la base rentre aussi en mémoire, tu fais deux set et il reste plus qu’à faire la soustraction entre les deux. Si la base rentre pas en mémoire, fait la même chose par morceaux. Tu n’auras pas plus rapide en Python natif.

+4 -0

D’après ce que tu dis dans ton premier post, je suis plus inquiet par le coût en temps que par le coût en espace.

Je te conseille plutôt d’utiliser un dictionnaire (table de hashage) ou bien un set pour avoir de meilleurs performances.

Avec un dictionnaire, le coût mémoire devrait être amoindri en plus.

D’après ce que tu dis dans ton premier post, je suis plus inquiet par le coût en temps que par le coût en espace.

Même pas, ce code :

1
2
3
4
import random
a = set(random.randrange(10000000) for _ in range(1000000))
b = set(range(1000000))
c = a - b

s’exécute en 1.5 secondes sur ma machine, dont une seconde dépensée à générer le million de nombres aléatoires.

Clairement, ce qui va limiter les performances, ce n’est pas la soustraction ni la création des set mais la lecture en elle-même des fichiers. Et dans tous les cas, pour une tâche ponctuelle (une fois par jour si j’ai bien compris), ce ne sera pas critique du tout.

+0 -0

C’est pour ça que j’utilise des set à la place des listes, parce que c’est fait pour ça. Il n’y a rien dans l’énoncé du problème qui l’interdise.

+0 -0

Merci pour l’idée des set . Jamais utilisé çà et c’est justement pour ca que je venais poser la question : je sais résoudre le problème mais de manière "crade" et je voulais savoir s’il n’y avait pas plus propre (en plus ça me ferra apprendre un truc !)

Sur Stackoverflow j’ai aussi vu beaucoup de gens recommander Panda et importer le CSV dans un tableau panda pour aller plus vite que de lire le csv ligne par ligne et l’importer avec le module csv . Ca vous parait une autre bonne solution ?

Ce n’est pas une autre solution, c’est une autre partie de la solution. Le lecteur pandas est en effet rapide (à condition de jouer un peu avec les options), donc lire le csv avec pandas puis utiliser des set semble une bonne solution.

+0 -0

Je profite du sujet pour revenir sur mon problème que j’ai visiblement résolu mais finalement c’est pas l’import qui a pris un temps monstre mais la comparaison.

Du coup j’ai importé chaque CSV dans une liste (et pas un set) car sur Stackoverflow yavait pas mal de poste expliquant que "les comprhension de liste ca deboite ca va trop vite tout ca tout ca"

DU coup je me retrouve a comparer mes deux listes dans une toisième liste avec un code du style:

liste_propre=[item for item in base if item not in spam]

Mon script marche et tout mais ma question c’est : la génération de cette liste à pris 3h30 pour comparer une liste d’1millions d’éléments et une liste de 850 000 éléments . Ça vous parait normal ou pas (alors que l’import cracra à pris genre 1min30)?

Me suis-je fait flouer par Stackoverflow (parceque du coup jetai parti sur les set mais les multiples post disant de faire le contraire m’ont poussé vers l’autre solution)?

+0 -0

Du coup j’ai importé chaque CSV dans une liste (et pas un set) car sur Stackoverflow yavait pas mal de poste expliquant que "les comprhension de liste ca deboite ca va trop vite tout ca tout ca"

Bah aussi, si tu ne fais pas ce qu’on te dit… :-° Les set sont construits pour résoudre le problème que tu as. Quelque chose me dit que les postes de StackOverflow qui conseillaient d’utiliser des listes n’étaient pas sur le même genre de question. Au pire, tu avais toujours la doc pour être sûr

+0 -0

yavait pas mal de poste expliquant que "les comprhension de liste ca deboite ca va trop vite tout ca tout ca"

alliocha1805

Si ce n’est que ça tu as aussi les ensembles en intension, c’est comme pour les listes, mais avec des ensembles.

Mais je ne vois pas en quoi une liste en intension irait plus vite qu’une autre liste.

En vérité, les différents types sont essentiellement optimisés pour les opérations naturelles qu’ils peuvent subir. Par exemple, pour un ensemble, il s’agit des tests d’appartenance, les unions etc. Pour une liste, il s’agit plutôt du parcours séquentiel, de l’ajout en fin de liste, etc.

L’implémentation de python est plutôt bien faite, et les structures des données concrètes permettent d’obtenir les performances attendues. Autrement dit, sans vouloir m’avancer trop, je suis convaincu que les sets python ressemblent plus en interne à une hashmap qu’à un array.

Autrement dit, sans vouloir m’avancer trop, je suis convaincu que les sets python ressemblent plus en interne à une hashmap qu’à un array.

Aabu

Les sets sont des hashmaps, en effet. C’est pour ça que les éléments d’un set doivent être hashables.

+2 -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