Je veux parcourir chaque ligne d'un fichier entier. Une façon de procéder consiste à lire l'intégralité du fichier, à l'enregistrer dans une liste, puis à parcourir la ligne d'intérêt. Cette méthode utilise beaucoup de mémoire, donc je cherche une alternative.
Mon code jusqu'à présent:
for each_line in fileinput.input(input_file):
do_something(each_line)
for each_line_again in fileinput.input(input_file):
do_something(each_line_again)
L' exécution de ce code donne un message d'erreur: device active
.
Aucune suggestion?
Le but est de calculer la similitude des chaînes par paire, ce qui signifie que pour chaque ligne du fichier, je veux calculer la distance Levenshtein avec toutes les autres lignes.
Réponses:
La façon correcte et entièrement Pythonique de lire un fichier est la suivante:
L'
with
instruction gère l'ouverture et la fermeture du fichier, y compris si une exception est déclenchée dans le bloc interne. Lefor line in f
traite l'objet fichierf
comme un itérable, qui utilise automatiquement les E / S tamponnées et la gestion de la mémoire pour que vous n'ayez pas à vous soucier des gros fichiers.la source
for line in f:
marche? Je veux dire, comment itérer sur un objet fichier est-il possible?__iter__
, qui lui indique quoi faire. Les objets fichier définissent cette méthode spéciale pour renvoyer un itérateur sur les lignes. (En gros.)Deux moyens efficaces de mémoire dans l'ordre classé (le premier est le meilleur) -
with
- pris en charge à partir de python 2.5 et supérieuryield
si vous voulez vraiment contrôler la quantité de lecture1. utilisation de
with
with
est le moyen pythonique agréable et efficace de lire de gros fichiers. avantages - 1) l'objet fichier est automatiquement fermé après avoir quitté lewith
bloc d'exécution. 2) gestion des exceptions à l'intérieur duwith
bloc. 3) lafor
boucle de mémoire parcourt lef
fichier objet ligne par ligne. en interne, il fait des E / S tamponnées (optimisées pour les opérations d'E / S coûteuses) et la gestion de la mémoire.2. utilisation de
yield
Parfois, on peut souhaiter un contrôle plus fin sur la quantité à lire à chaque itération. Dans ce cas, utilisez iter & yield . Notez qu'avec cette méthode, il faut explicitement fermer le fichier à la fin.
Pièges et par souci d'exhaustivité - les méthodes ci-dessous ne sont pas aussi bonnes ou pas aussi élégantes pour lire des fichiers volumineux, mais veuillez lire pour obtenir une compréhension globale.
En Python, la façon la plus courante de lire les lignes d'un fichier est de procéder comme suit:
Lorsque cela est fait, cependant, la
readlines()
fonction (il en va de même pour laread()
fonction) charge tout le fichier en mémoire, puis itère dessus. Une approche légèrement meilleure (les deux premières méthodes mentionnées sont les meilleures) pour les fichiers volumineux consiste à utiliser lefileinput
module, comme suit:l'
fileinput.input()
appel lit les lignes de façon séquentielle, mais ne les garde pas en mémoire après qu'elles ont été lues ou même simplement ceci, carfile
en python est itérable.Références
la source
for line in open(...).readlines(): <do stuff>
. Pourquoi voudrais-tu?! Vous venez de perdre tous les avantages de l'intelligent IO de l'itérateur tamponné de Python sans aucun avantage.readlines
et en expliquant pourquoi ce n'est pas une bonne chose à faire (car il lit le fichier en mémoire), puis en expliquant ce que fait lefileinput
module et pourquoi vous pourrait vouloir l'utiliser par-dessus les autres méthodes, expliquant ensuite comment la segmentation du fichier améliore l'IO et donnant un exemple de la fonction de segmentation (mais en mentionnant que Python le fait déjà pour vous, vous n'avez donc pas besoin de le faire). Mais donner cinq façons de résoudre un problème simple, dont quatre sont erronées dans ce cas, n'est pas bon.Pour supprimer les retours à la ligne:
Avec le soutien de saut de ligne universel toutes les lignes de fichiers texte sembleront terminé avec
'\n'
, quelles que soient les terminateurs dans le fichier,'\r'
,'\n'
ou'\r\n'
.EDIT - Pour spécifier la prise en charge universelle de la nouvelle ligne:
open(file_path, mode='rU')
- requis [merci @Dave ]open(file_path, mode='rU')
- facultatifopen(file_path, newline=None)
- facultatifLe
newline
paramètre est uniquement pris en charge dans Python 3 et par défaut àNone
. Lemode
paramètre par défaut est'r'
dans tous les cas. LeU
est dépréciée en Python 3. En Python 2 sous Windows un autre mécanisme semble traduire\r\n
à\n
.Documents:
Pour conserver les terminateurs de ligne natifs:
Le mode binaire peut toujours analyser le fichier en lignes avec
in
. Chaque ligne aura les terminateurs qu'elle contient dans le fichier.Merci à @katrielalex de » réponse , Python open () doc, et ipython expériences.
la source
open(file_path, 'rU')
activer les sauts de ligne universels.c'est une façon possible de lire un fichier en python:
il n'alloue pas de liste complète. Il parcourt les lignes.
la source
with open(input_file) as f:
. Cela vous permet d'économiserf.close()
et de vous assurer de ne pas oublier accidentellement de le fermer. Empêche les fuites de mémoire et tout, assez important lors de la lecture des fichiers.Un peu de contexte pour savoir d'où je viens. Les extraits de code sont à la fin.
Lorsque je le peux, je préfère utiliser un outil open source comme H2O pour effectuer des lectures de fichiers CSV parallèles de très haute performance, mais cet outil est limité dans l'ensemble de fonctionnalités. Je finis par écrire beaucoup de code pour créer des pipelines de science des données avant d'alimenter le cluster H2O pour l'apprentissage supervisé proprement dit.
J'ai lu des fichiers comme un ensemble de données HIGGS de 8 Go à partir du référentiel UCI et même des fichiers CSV de 40 Go à des fins de science des données beaucoup plus rapidement en ajoutant beaucoup de parallélisme avec l'objet pool et la fonction de carte de la bibliothèque de multitraitement. Par exemple, le clustering avec les recherches de voisins les plus proches et les algorithmes de clustering DBSCAN et Markov nécessitent une finesse de programmation parallèle pour contourner certains problèmes de mémoire et d'horloge murale très difficiles.
J'aime généralement diviser le fichier en plusieurs parties en utilisant d'abord les outils gnu, puis les masquer tous pour les trouver et les lire en parallèle dans le programme python. J'utilise couramment quelque chose comme plus de 1000 fichiers partiels. Faire ces astuces aide énormément avec la vitesse de traitement et les limites de mémoire.
Le fichier pandas dataframe.read_csv est un thread unique, vous pouvez donc faire ces astuces pour accélérer les pandas en exécutant une carte () pour une exécution parallèle. Vous pouvez utiliser htop pour voir qu'avec de vieux pandas séquentiels dataframe.read_csv, 100% de processeur sur un seul cœur est le véritable goulot d'étranglement dans pd.read_csv, pas le disque du tout.
Je dois ajouter que j'utilise un SSD sur un bus de carte vidéo rapide, pas un HD tournant sur le bus SATA6, plus 16 cœurs de processeur.
En outre, une autre technique que j'ai découverte fonctionne très bien dans certaines applications: le fichier CSV parallèle lit tout dans un fichier géant, en démarrant chaque travailleur à un décalage différent dans le fichier, plutôt que de pré-fractionner un gros fichier en plusieurs fichiers de pièce. Utilisez la recherche de fichier () et tell () de python dans chaque travailleur parallèle pour lire le gros fichier texte en bandes, à différents emplacements de début et de fin de décalage d'octet dans le gros fichier, le tout en même temps. Vous pouvez effectuer une recherche regex sur les octets et renvoyer le nombre de sauts de ligne. Il s'agit d'une somme partielle. Enfin, additionnez les sommes partielles pour obtenir la somme globale lorsque la fonction de carte revient une fois que les travailleurs ont terminé.
Voici quelques exemples de références utilisant l'astuce de décalage d'octets parallèles:
J'utilise 2 fichiers: HIGGS.csv fait 8 Go. Il provient du référentiel d'apprentissage automatique UCI. all_bin .csv fait 40,4 Go et provient de mon projet actuel. J'utilise 2 programmes: le programme GNU wc fourni avec Linux et le programme pur python fastread.py que j'ai développé.
C'est quelque 4,5 Go / s, ou 45 Go / s, la vitesse de slurping des fichiers. Ce n'est pas un disque dur qui tourne, mon ami. C'est en fait un SSD Samsung Pro 950.
Ci-dessous se trouve la référence de vitesse pour le même fichier compté par gnu wc, un programme compilé en C pur.
Ce qui est cool, c'est que vous pouvez voir que mon programme en python pur correspondait essentiellement à la vitesse du programme C compilé par gnu wc dans ce cas. Python est interprété mais C est compilé, c'est donc un exploit de vitesse assez intéressant, je pense que vous serez d'accord. Bien sûr, wc doit vraiment être changé en un programme parallèle, et alors il devrait vraiment battre les chaussettes de mon programme python. Mais tel qu'il est aujourd'hui, gnu wc n'est qu'un programme séquentiel. Vous faites ce que vous pouvez, et python peut faire du parallèle aujourd'hui. La compilation de Cython pourrait m'aider (pour une autre fois). Les fichiers mappés en mémoire n'ont pas encore été explorés.
Conclusion: La vitesse est bonne pour un programme en python pur par rapport à un programme C. Cependant, il n'est pas suffisant d'utiliser le programme python pur sur le programme C, au moins à des fins de comptage de lignes. Généralement, la technique peut être utilisée pour d'autres traitements de fichiers, donc ce code python est toujours bon.
Question: Est-ce que la compilation de l'expression régulière une seule fois et sa transmission à tous les employés améliorera la vitesse? Réponse: La pré-compilation Regex n'aide PAS dans cette application. Je suppose que la raison en est que les frais généraux de sérialisation et de création de processus pour tous les travailleurs sont dominants.
Encore une chose. La lecture de fichiers CSV parallèle aide-t-elle même? Le disque est-il le goulot d'étranglement ou est-ce le CPU? De nombreuses réponses dites les mieux notées sur stackoverflow contiennent la sagesse courante des développeurs selon laquelle vous n'avez besoin que d'un seul thread pour lire un fichier, le mieux que vous puissiez faire, disent-ils. Mais sont-ils sûrs?
Découvrons-le:
Oh oui, oui. La lecture de fichiers en parallèle fonctionne plutôt bien. Et bien voilà!
Ps. Dans le cas où certains d'entre vous voudraient savoir, que se passe-t-il si le balanceFactor était de 2 lors de l'utilisation d'un seul processus de travail? Eh bien, c'est horrible:
Parties clés du programme python fastread.py:
Le def pour PartitionDataToWorkers est juste du code séquentiel ordinaire. Je l'ai laissé de côté au cas où quelqu'un d'autre voudrait se familiariser avec la programmation parallèle. J'ai donné gratuitement les parties les plus difficiles: le code parallèle testé et fonctionnel, pour votre bénéfice d'apprentissage.
Merci à: Le projet open source H2O, par Arno et Cliff et le personnel H2O pour leurs excellents logiciels et vidéos pédagogiques, qui m'ont inspiré ce lecteur de décalage d'octets parallèle en python pur de haute performance comme indiqué ci-dessus. H2O fait la lecture de fichiers en parallèle en utilisant java, est appelable par les programmes python et R, et est incroyablement rapide, plus rapide que n'importe quoi sur la planète pour lire de gros fichiers CSV.
la source
Katrielalex a fourni le moyen d'ouvrir et de lire un fichier.
Cependant, la façon dont votre algorithme fonctionne, il lit le fichier entier pour chaque ligne du fichier. Cela signifie que la quantité globale de lecture d'un fichier - et de calcul de la distance Levenshtein - sera effectuée N * N si N est la quantité de lignes dans le fichier. Étant donné que vous êtes préoccupé par la taille du fichier et que vous ne souhaitez pas le conserver en mémoire, je suis préoccupé par le temps d'exécution quadratique résultant . Votre algorithme est dans la classe d'algorithmes O (n ^ 2) qui peut souvent être améliorée avec la spécialisation.
Je soupçonne que vous connaissez déjà le compromis entre la mémoire et l'exécution ici, mais vous voudrez peut-être rechercher s'il existe un moyen efficace de calculer plusieurs distances Levenshtein en parallèle. Si c'est le cas, il serait intéressant de partager votre solution ici.
Combien de lignes vos fichiers ont-ils, et sur quel type de machine (puissance mem & cpu) votre algorithme doit-il fonctionner, et quel est le temps d'exécution toléré?
Le code ressemblerait à:
Mais les questions sont de savoir comment stocker les distances (matrice?) Et pouvez-vous gagner un avantage à préparer, par exemple, la ligne extérieure pour le traitement, ou à mettre en cache certains résultats intermédiaires pour la réutilisation.
la source
Si vous voulez, par exemple, vérifier une ligne spécifique pour une longueur supérieure à 10, travaillez avec ce que vous avez déjà disponible.
la source
Dans la documentation python pour fileinput .input ():
de plus, la définition de la fonction est:
lire entre les lignes, cela me dit que cela
files
peut être une liste afin que vous puissiez avoir quelque chose comme:Voir ici pour plus d'informations
la source
Je recommande fortement de ne pas utiliser le chargement de fichier par défaut car il est horriblement lent. Vous devriez regarder dans les fonctions numpy et les fonctions IOpro (par exemple numpy.loadtxt ()).
http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html
https://store.continuum.io/cshop/iopro/
Ensuite, vous pouvez diviser votre opération par paire en morceaux:
Il est presque toujours beaucoup plus rapide de charger des données en morceaux et de faire ensuite des opérations matricielles dessus que de le faire élément par élément !!
la source
Besoin de lire fréquemment un gros fichier à partir de la dernière lecture de position?
J'ai créé un script utilisé pour couper un fichier Apache access.log plusieurs fois par jour. J'ai donc dû placer un curseur de position sur la dernière ligne analysée lors de la dernière exécution . À cette fin, j'ai utilisé
file.seek()
et desfile.seek()
méthodes qui permettent le stockage du curseur dans un fichier.Mon code:
la source
La meilleure façon de lire un fichier volumineux, ligne par ligne, est d'utiliser la fonction d' énumération python
la source