2010-02-17 9 views
2

Désolé pour le titre très général mais je vais essayer d'être aussi précis que possible.fusion de dictionnaires en python

Je travaille sur une application d'exploration de texte. J'ai un grand nombre de paires de valeurs clés de la forme ((mot, corpus) -> occurence_count) (tout est un entier) que je stocke dans plusieurs dictionnaires python (tuple-> int). Ces valeurs sont réparties sur plusieurs fichiers sur le disque (je les ai décapés). Pour avoir une idée des données, j'ai besoin d'agréger ces dictionnaires Fondamentalement, je dois trouver un moyen de trouver toutes les occurrences d'une clé particulière dans tous les dictionnaires, et les additionner pour obtenir un nombre total.

Si je charge plus d'un dictionnaire à la fois, je manque de mémoire, ce qui explique pourquoi j'ai dû les séparer en premier lieu. Quand j'ai essayé, j'ai rencontré des problèmes de performance. J'essaie actuellement de stocker les valeurs dans une base de données (mysql), en traitant plusieurs dictionnaires à la fois, puisque mysql fournit un verrouillage au niveau des lignes, ce qui est à la fois bon (puisque cela signifie que je peux paralléliser cette opération) les requêtes d'insertion)

Quelles sont mes options ici? Est-ce une bonne idée d'écrire un dictionnaire basé sur un disque partiel pour que je puisse traiter les dicts un à la fois? Avec une stratégie de remplacement LRU? Y at-il quelque chose que je suis complètement inconscient?

Merci!

+0

Définir "grand nombre". "Je n'ai plus de mémoire". Vraiment? Sans détails comme le nombre d'éléments dans le dictionnaire, je trouve cela difficile à comprendre. "Quand j'ai essayé, j'ai rencontré des problèmes de performance". Essayé quoi? –

+0

Quand vous dites "tout est un entier", voulez-vous dire que le mot et le corpus sont des entiers d'un mot et d'un corpus? Le mot ids est-il cohérent à travers les corpus? – forefinger

+0

merci à tous! J'ai redéfini un peu le problème pour le résoudre. – fsm

Répondre

0

Quelque chose comme ça, si je comprends bien votre question

from collections import defaultdict 
import pickle 

result = defaultdict(int) 
for fn in filenames: 
    data_dict = pickle.load(open(fn)) 
    for k,count in data_dict.items(): 
     word,corpus = k 
     result[k]+=count 
2

Un type dictionnaire sur disque existe - voir le module shelve. Les clés dans une étagère doivent être des chaînes, mais vous pouvez simplement utiliser str sur vos tuples pour obtenir des clés de chaînes équivalentes; De plus, je lis votre Q comme signifiant que vous voulez seulement word comme clé, donc c'est encore plus facile (soit str - soit, pour les vocabulaires < 4Go, un struct.pack - ça ira). Un bon moteur relationnel (surtout PostgreSQL) vous sera utile, mais le traitement d'un dictionnaire à la fois pour agréger chaque occurrence de mot sur tous les corpus en un objet shelf devrait aussi être OK (pas tout à fait aussi rapide, mais plus simple à coder , puisqu'une shelf est si semblable à dict à l'exception de la contrainte de type sur les clés [[et une mise en garde pour les valeurs mutables, mais comme vos valeurs sont int s qui ne doivent pas vous concerner).

0
  1. Si je comprends bien votre question correctement et vous avez ids entier pour les mots et corpora, alors vous pouvez gagner un peu de performance en passant d'un dict à une liste, ou mieux encore, un tableau numpy. Cela peut être ennuyeux!

    Fondamentalement, vous devez remplacer le tuple par un seul entier, que nous pouvons appeler le newid. Vous voulez que tous les newids correspondent à un mot, une paire de corpus, donc je compterais les mots dans chaque corpus, et aurais, pour chaque corpus, un newid de départ. Le newid de (mot, corpus) sera alors word + start_newid [corpus]. Si je vous ai mal compris et que vous n'avez pas ces identifiants, alors je pense que ce conseil peut toujours être utile, mais vous devrez manipuler vos données pour les mettre dans le format ints.

  2. Une autre chose que vous pouvez essayer est de rechigner les données.

    Disons que vous ne pouvez contenir que 1.1 de ces monstres en mémoire. Ensuite, vous pouvez en charger un et créer un dict ou un tableau plus petit qui ne correspond qu'aux 10 premiers% de paires (mot, corpus).Vous pouvez parcourir la dictée chargée, et faire face à ceux qui sont dans les 10 premiers%. Lorsque vous avez terminé, vous pouvez écrire le résultat sur le disque et faire une autre passe pour le second 10%. Cela nécessitera 10 passes, mais cela pourrait être OK pour vous. Si vous avez choisi votre segment précédent en fonction de ce qui rentrerait dans la mémoire, alors vous devrez casser vos anciens dits de moitié de façon arbitraire afin de pouvoir en garder un en mémoire tout en maintenant le résultat dict/array.

Questions connexes