Je souhaite créer un dictionnaire avec la colonne 1 en tant que clé et colonne 2 en tant que valeur pour toutes les lignes dans entréeFile em> où les premières colonnes se produisent dans Vals em>. Quelques éléments dans Vals em> ne se produisent pas dans le fichier, ces valeurs doivent être enregistrées dans une nouvelle liste. Je peux utiliser jusqu'à 20 threads pour accélérer ce processus. P> Quel est le moyen le plus rapide d'y parvenir? P> Mon meilleur essai jusqu'à présent: P> [1]
3 Réponses :
Ce n'est pas terriblement efficace de mémoire (pour un fichier de 300 millions de lignes pouvant poser un problème). Je ne peux pas penser à un moyen de sauvegarder les valeurs non trouvées dans une compréhension, sauf en enregistrant toutes les valeurs (ou en lisant le fichier deux fois). Je ne pense pas que les threads aideront beaucoup, car le fichier d'E / S sera probablement le goulot d'étranglement de la performance. Je suppose qu'un onglet est le caractère de délimitation dans le fichier. (Vous n'avez pas dit, mais l'exemple de données semble avoir un onglet.)
vals = [1,2,594592888] with open(self.inputfile,'r') as i_file: all_vals = { int(t[0]):int(t[1]) for t in ( line.strip().split('\t') for line in i_file ) } newDict = { t[0]:t[1] for t in filter(lambda t: t[0] in vals, all_vals.items()) } notFound = list(set(all_vals.keys()).difference(newDict.keys()))
Les goulots d'étranglement io sont précisément le genre de situation où le threading aide à Python.
Cette méthode est en effet une mémoire inefficace (plus de 30 g), cela n'a causé aucun problème. Toujours Grep est beaucoup plus rapide ...
Si je vous comprends correctement, vous ne voulez pas de ligne de fichier qui ne correspond pas à vous Vals code>
Puisque vous parlez d'énormes fichiers et un nombre assez petit de valeurs recherchées, j'irais quelque chose comme:
split -l 1000000 filename
Je vois ... uhm ... je vais enquêter sur elle et modifier ma réponse. Cependant, j'ai déjà édité cela suggérant un moyen facile d'utiliser votre CPU multiple
Vous avez clarifié dans un commentaire que chaque clé se produit au plus une fois dans les données. Il découle de cela et du fait qu'il n'y a que 1000 clés que la quantité de travail effectuée dans Python est triviale; Presque tout votre temps est passé à attendre la sortie de Vous pouvez accélérer les choses en optimisant votre regex. Par exemple, au lieu de p> , vous pouvez utiliser: p> de sorte que l'ancre ne doit pas être assortie séparément pour chaque alternative. Je vois une amélioration de 15% sur les données de test (10 millions de lignes, 25 clés) avec ce changement. P> Une optimisation supplémentaire consiste à unifier les préfixes courants dans l'alternance: à ce point un tel est grep code>. Qui va bien; Votre stratégie de délégation de la ligne d'extraction à une utilité spécialisée reste sonore. Mais cela signifie que les gains de performance doivent être trouvés sur le côté de l'extraction de ligne.
266 \ | 801 \ | 810 code> peut être remplacé par l'équivalent
266 \ \ | 8 \ (01 \ | 10 \) code>. La réécriture de la réégalité de 25 clés de cette manière donne près d'une vitesse de 50% sur les données de test. P>
grep code> commence à afficher ses limites. Il semble que c'est la CPU-liée:
iostat code> révèle que chaque amélioration successive de la regex augmente le nombre de demandes IO par seconde, tandis que GREP est en cours d'exécution. Et réexécuter
grep code> avec un cache de page chauffé et l'option
- mmap code> ne pas accélérer les choses (car elle serait probablement si le fichier io était un goulot d'étranglement). Une vitesse supérieure nécessite donc probablement une utilité avec un moteur de regex plus rapide. P>
AG code> (source ici ), dont la mise en œuvre de la regex effectue également une optimisation automatique, vous n'avez donc pas besoin de faire beaucoup de main-d'œuvre. Bien que je n'ai pas pu obtenir
grep code> pour traiter les données de test en moins de ~ 12s sur ma machine,
AG code> se termine dans ~ 0.5S pour toutes les variantes de regex décrit ci-dessus. p> p>
Comment ressemble votre commande AG? J'ai installé AG, lorsque vous utilisez exactement la même regex que dans Grep, AG ne trouvez rien pendant que grep fait ... j'ai utilisé Grep "^ (266 \ | 801 \ 0. 810) [[: espace:]]" File.txt and: AG "^ (266 \ | 801 \ | 810) [[[: espace:]]" File.txt
AG code> utilise la syntaxe PCRE pour des expressions régulières, vous ne devez donc pas échapper à l'opérateur de l'alternatif (le
| code>). En outre, je ne sais pas si cela prend en charge les classes de caractère nommées; Vous devrez peut-être remplacer
[[: espace]] code> avec
\ s code>. BTW, pour
grep code> Vous devez également échapper aux parenthèses.
Pouvez-vous fournir un échantillon des fichiers d'entrée et la sortie souhaitée? Juste pour faire clairement les choses.
Essayez peut-être d'utiliser la commande Open (File, R) de Python et voyez si cela vous donne un coup de pouce.
@ Sshashank124 C'était mon premier essai, mais cette approche est beaucoup plus rapide ...
@Jeanrjc a ajouté un exemple
@ Sshashak124, Grep est un code optimisé incroyablement bien puiser, l'utiliser pour filtrer les lignes d'intérêt diminuera un peu sur la charge de Python (en supposant qu'une petite partie des lignes dans le fichier d'intérêt). Il a également un avantage supplémentaire de courir dans son propre fil.
@MarkRansom était une faute de frappe, résolue
Si
VAL code> se trouve sur plusieurs lignes dans votre fichier TSV, vous écrasez les hits antérieurs et finissez par stocker uniquement le succès le plus récent. Cela ne ressemble pas à ce que vous voulez (aller par "un dictionnaire avec la colonne 1 en tant que clé et colonne 2 en tant que valeur pour toutes les lignes dans l'entrée de l'entrée où les premières colonnes se produisent dans les vals").
@ALP Je ne l'ai pas mentionné, mais les valeurs de la colonne 1 sont commandées et uniques. Votre solution rend la commande grep comme ceci: grep "\ | val1 \ | val2" file.txt au lieu de grep "VAL1 \ | VAL1 \ | VAL1 | TTXT
@Alp, je changerais le
pour code> en boucle à une jointure avec un générateur:
cmd + = "\\ |" .join ("^" + val + "[[[: Espace:] ] "Pour Val in Vals) Code> Ensuite, laissez le
Vals [0] code>.
@MarkRansom Juste dans le processus d'écriture qui! Merci @JetSe: le point crucial est que si vous incluez
val [0] code> sans l'ancre et la classe de caractères d'espace, vous pourriez obtenir un faux coup.
Combien de temps le
grep code> prend-il seul pour traiter le fichier, sans python impliqué? Combien de temps faut-il juste pour copier le fichier à NULL? Ce sera votre limite inférieure.
@MarkRansom presque tout le temps est passé dans
grep code>. Étant donné que chaque clé ne se produit qu'une seule fois dans les données et il n'y a que 1000 d'entre eux, la quantité de travail effectuée à Python est triviale.
La vraie question est donc de savoir s'il y a un moyen d'améliorer sur
grep code>, raison pour laquelle je vous ai demandé de le comparer à une copie simple. Grep est bien optimisé, mais je ne sais pas à quel point c'est efficace avec une expression aussi compliquée. Il est important que vous faites la comparaison pour vous assurer que le fichier n'est pas dans le cache du système d'exploitation ou produira des temps trop optimistes.