Différentes façons de lire la dernière ligne d'un fichier csv en Python

Sous Linux, il existe une commande appelée «tail» qui vous permet d'obtenir la ligne «n» à la fin du fichier. C'est assez pratique donc je veux pouvoir faire la même chose avec Python. Je voudrais créer une fonction qui récupère n lignes à la fin du fichier avec tail (file_name, n) en utilisant plusieurs approches.

Pour la dernière approche, allez sur le site it-swarm.dev Trouvez efficacement la dernière ligne du fichier texte -Je me réfère à la page swarm.dev/ja/python/ Trouver efficacement la dernière ligne du fichier texte / 940298444 /).

Fichier à utiliser

Le fichier à lire pourrait être un fichier texte, mais cette fois j'utiliserai le fichier csv. Le nom du fichier est «test.csv». Le contenu est un résumé du prix du Bitcoin en 86400 lignes (une journée) par seconde.

test.csv


date,price,size
1588258800,933239.0,3.91528007
1588258801,933103.0,3.91169431
1588258802,932838.0,2.91
1588258803,933217.0,0.5089811

(Omission)

1588345195,955028.0,0.0
1588345196,954959.0,0.05553
1588345197,954984.0,1.85356
1588345198,955389.0,10.91445135
1588345199,955224.0,3.61106

Bien que cela n'ait rien à voir avec le sujet principal, si vous expliquez chaque élément pour le moment, les unités de date, de prix et de taille sont UnixTime, YEN, BTC. La première ligne signifie qu'au moment «1588258800», c'est-à-dire à 0:00:00 le 1er mai, il y avait des pièces de «3.915280007» achetées et vendues pour «933239.0» yens.

Lisez docilement depuis le début

Premièrement, utilisez la fonction intégrée ʻopen () `pour obtenir l'objet fichier, lire toutes les lignes depuis le début et afficher uniquement les n dernières lignes. Si n est 0 ou un entier négatif, des résultats étranges seront obtenus, il est donc en fait nécessaire d'effectuer un traitement limité aux nombres naturels, mais c'est important pour la visibilité.

python


def tail(fn, n):
    #Ouvrez le fichier et récupérez toutes les lignes dans une liste
    with open(fn, 'r') as f:
        #Lire une ligne.La première ligne est l'en-tête, alors supprimez le résultat
        f.readline()

        #Lire toutes les lignes
        lines = f.readlines()
    
    #Renvoie seulement n lignes de l'arrière
    return lines[-n:]

#résultat
file_name = 'test.csv'
tail(file_name, 3)
# ['1588345197,954984.0,1.85356\n',
#  '1588345198,955389.0,10.91445135\n',
#  '1588345199,955224.0,3.61106\n']

S'il s'agit d'un fichier texte, vous pouvez le laisser tel quel, mais rendez-le un peu plus facile à utiliser pour les fichiers csv.

python


def tail(fn, n):
    #Ouvrez le fichier et récupérez toutes les lignes dans une liste
    with open(fn, 'r') as f:
        f.readline()
        lines = f.readlines()

    #Renvoie une chaîne après en avoir fait un tableau.Au fait str->Conversion de type en float
    return [list(map(float ,line.strip().split(','))) for line in lines[-n:]]

#résultat
tail(file_name, 3)
# [[1588345197.0, 954984.0, 1.85356],
#  [1588345198.0, 955389.0, 10.91445135],
#  [1588345199.0, 955224.0, 3.61106]]

La seule chose qui a changé est la ligne return, mais comme les fonctions sont encombrées et difficiles à comprendre, je vais l'expliquer en un mot. Le traitement suivant est effectué pour chaque ligne.

  1. Supprimez le code de saut de ligne avec strip () '1588345197,954984.0,1.85356\n' -> '1588345197,954984.0,1.85356'

  2. Convertissez les chaînes en tableaux séparés par des virgules avec split () '1588345197,954984.0,1.85356' -> ['1588345197', '954984.0', '1.85356']

  3. Convertissez chaque élément du tableau d'une chaîne en un type float avec map () ['1588345197', '954984.0', '1.85356'] -> [1588345197.0, 954984.0, 1.85356]

Utilisez le module csv

Puisque le module csv convertit automatiquement chaque ligne en un tableau, ce sera un peu plus lent, mais cela peut être décrit de manière plus concise.

python


import csv

def tail_csv(fn, n):
    with open(fn) as f:
        #Convertir l'objet fichier en lecteur csv
        reader = csv.reader(f)
        #Jeter l'en-tête
        next(reader)
        #Lire toutes les lignes
        rows = [row for row in reader]

    #Flotter uniquement les n dernières lignes et retourner
    return [list(map(float, row)) for row in rows[-n:]]

Utilisez le module pandas

Puisque les pandas ont une fonction de queue, il est étonnamment facile à écrire.

python


import pandas as pd

def tail_pd(fn, n):
    df = pd.read_csv(fn)
    return df.tail(n).values.tolist()

Puisque les pandas traitent des tableaux numpy, il est converti en une liste à la fin avec tolist (). Ce n'est pas nécessaire si le tableau numpy peut être utilisé.

Mesurer le temps d'exécution pour chaque motif

ʻIpython a une commande pratique appelée timeit`, alors comparons-la avec le nombre de boucles défini sur 100.

timeit -n100 tail('test.csv', 3)
18.8 ms ± 175 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

timeit -n100 tail_csv('test.csv', 3)
67 ms ± 822 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

timeit -n100 tail_pd('test.csv', 3)
30.4 ms ± 2.45 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

Il s'est avéré qu'il était rapide à lire tel quel sans utiliser aucun module. Cospa semble être le meilleur car pandas est la simplicité du code et la vitesse est raisonnable. Étant donné que le module csv convertit volontairement d'une chaîne de caractères en un tableau jusqu'aux lignes non utilisées, les résultats sont extrêmement médiocres.

Si vous lisez le fichier par derrière, ce sera un moment

Toutes les approches jusqu'à présent lisent toutes les lignes après tout, mais comme je ne veux que les dernières lignes, s'il y a un moyen de lire le fichier depuis le dos, la lecture devrait être terminée en un instant. Reportez-vous à la page [Trouvez efficacement la dernière ligne du fichier texte](https://www.it-swarm.dev/ja/python/ Trouvez efficacement la dernière ligne du fichier texte / 940298444 /) fait. Lisez environ 100 octets à partir du verso dans l'ordre, et si un code de saut de ligne est trouvé, la chaîne de caractères après cela est la dernière ligne. Seule la dernière ligne se trouve dans la page, mais pour exécuter la commande tail Vous devez trouver la ligne n à l'arrière, alors ne réglez que là-bas.

Tout d'abord, à titre de connaissance préliminaire, nous expliquerons comment faire fonctionner le pointeur de fichier. Il y a trois fonctions à utiliser: f.tell (), f.read (size), et f.seek (offset, whence). f.tell () retourne la position actuellement pointée par le pointeur. f.read (size) renvoie le contenu lu size octets à partir de la position actuelle. Le pointeur se déplace vers la position de lecture. Il ne peut être avancé que dans le sens positif. f.seek (offset, whence) est une fonction qui déplace la position du pointeur. L'argument «whence» représente la position. L'une des valeurs «0, 1, 2» est entrée. «0» est le début du fichier, «1» est la position actuelle du pointeur et «2» est la fin du fichier. Veux dire. Entrez un entier pour ʻoffset. Contrairement à read, vous pouvez passer une valeur négative, donc par exemple, f.seek (-15, 1)` renvoie la position actuelle du pointeur de 15 au début.

Nous allons le mettre en œuvre sur cette base.

python


#Utiliser une division qui peut utiliser des expressions régulières
import re

def tail_b(fn, n=None):
    #Si n n'est pas donné, seule la dernière ligne est renvoyée seule
    if n is None:
        n = 1
        is_list = False
    #n est un nombre naturel
    elif type(n) != int or n < 1:
        raise ValueError('n has to be a positive integer')
    #Lorsque n est donné, n lignes sont renvoyées ensemble dans une liste.
    else:
        is_list = True

    # 128 *Lire n octets à la fois
    chunk_size = 64 * n

    # seek()Se comporte de manière inattendue sauf en mode binaire'rb'Spécifier
    with open(fn, 'rb') as f:
        #Première ligne pour trouver la position la plus à gauche à l'exclusion de l'en-tête(Ligne d'en-tête)Je lis
        f.readline()
        #Le tout premier code de saut de ligne se trouve à l'extrémité gauche(Fin lors de la lecture à partir de la fin du fichier)À
        # -1 est'\n'1 octet
        left_end = f.tell() - 1
        
        #Fin de fichier(2)1 octet en arrière de. read(1)À lire
        f.seek(-1, 2)
        
        #Il y a souvent des lignes vides et des blancs à la fin du fichier
        #Position du dernier caractère du fichier les excluant(Extrémité droite)Trouver
        while True:
            if f.read(1).strip() != b'':
                #Extrémité droite
                right_end = f.tell()
                break
            #Fais un pas, alors fais deux pas vers le bas
            f.seek(-2, 1)
        
        #Nombre d'octets non lus à gauche
        unread = right_end - left_end
        
        #Nombre de lignes lues.Si cela devient n ou plus, cela signifie que n lignes ont été lues.
        num_lines = 0

        #Variables de connexion des chaînes d'octets lues
        line = b''
        while True:
            #Le nombre d'octets non lus est un morceau_Quand il devient plus petit que la taille,Fraction de morceau_Taille
            if unread < chunk_size:
                chunk_size = f.tell() - left_end
            
            #Morceau de votre emplacement actuel_Se déplacer vers le haut du fichier par taille
            f.seek(-chunk_size, 1)
            
            #Lisez seulement autant que vous bougez
            chunk = f.read(chunk_size)

            #Relier
            line = chunk + line

            #Depuis que j'ai recommencé avec read, chunk encore au début_déplacement de taille
            f.seek(-chunk_size, 1)
            
            #Mettre à jour le nombre d'octets non lus
            unread -= chunk_size

            #Si un code de saut de ligne est inclus
            if b'\n' in chunk:
                #Num autant que le nombre de codes de saut de ligne_Compter les lignes
                num_lines += chunk.count(b'\n')

                #Lire plus de n lignes,Ou lorsque le nombre d'octets non lus atteint 0, un signal de fin
                if num_lines >= n or not unread:
                    #Dernier code de saut de ligne trouvé
                    leftmost_blank = re.search(rb'\r?\n', line)

                    #Pas besoin de la pièce avant le dernier code de saut de ligne trouvé
                    line = line[leftmost_blank.end():]

                    #Convertir une chaîne d'octets en chaîne
                    line = line.decode()

                    #Code de saut de ligne'\r\n'Ou\n'Convertir en un tableau séparé par
                    lines = re.split(r'\r?\n', line)

                    #Enfin sortez n morceaux de l'arrière,Convertir en type float et retourner
                    result = [list(map(float, line.split(','))) for line in lines[-n:]]

                    #Si n n'est pas spécifié, la dernière ligne est renvoyée seule.
                    if not is_list:
                        return result[-1]
                    else:
                        return result

L'explication est donnée dans les notes. Faisons la mesure principale du temps.

timeit -n100 tail_b(fn, 3)
87.8 µs ± 3.74 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Le meilleur temps à ce jour a été la première approche, qui était de "18,8 ms ± 175 µs". Cela signifie que le temps d'exécution est d'environ "0,5%", soit "200" fois, mais 86400 lignes depuis le début. Il est naturel qu'il y ait une grande différence car c'est la différence entre lire tout ou lire quelques lignes au verso.

en conclusion

J'ai introduit quatre modèles, mais il semble y avoir une autre façon d'exécuter la commande tail du système en utilisant le module subprocess. C'est une méthode dépendante de l'environnement, donc je l'ai omise cette fois. La méthode la plus recommandée que j'ai introduite est celle qui peut être écrite sur deux lignes en utilisant pandas. Python est un langage qui maîtrise comment vous pouvez vous amuser en utilisant le code de quelqu'un d'autre.

En ce qui concerne la méthode de lecture à partir de l'arrière du fichier, il est recommandé de l'utiliser lorsque vous avez besoin de vitesse ou lorsque le nombre de lignes et de caractères est ridiculement grand et que la lecture du fichier prend trop de temps depuis le début. De plus, cela n'a aucun sens d'utiliser 64 pour déterminer taille_chunk. Il est probablement plus rapide de le définir à environ la longueur d'une ligne dans un fichier, mais la longueur de certains fichiers varie considérablement en fonction de la ligne. Par conséquent, je ne peux rien dire. Si vous avez affaire à un fichier qui contient quelques caractères sur une ligne courte, mais 10 000 caractères sur une longue ligne, vous devrez modifier dynamiquement chunk_size. Par exemple, si le nombre de lignes trouvées dans une recherche est bien inférieur à n, le prochain chunk_size est doublé et doublé. Il semble qu'il soit également efficace de déterminer le prochain chunk_size à partir du nombre de lignes qui ont été recherchées et de la longueur moyenne des lignes.

Recommended Posts

Différentes façons de lire la dernière ligne d'un fichier csv en Python
Google recherche la chaîne sur la dernière ligne du fichier en Python
Lisez le fichier ligne par ligne avec Python
Lisez le fichier ligne par ligne avec Python
[Python] Lire la ligne spécifiée dans le fichier
Lire la sortie standard d'un sous-processus ligne par ligne en Python
Comment lire un fichier CSV avec Python 2/3
Comment mettre un numéro de ligne au début d'un fichier CSV
[Python] Comment lire le fichier csv (méthode read_csv du module pandas)
J'ai fait un programme pour vérifier la taille d'un fichier avec Python
Modèle de script python pour lire le contenu du fichier
2 façons de lire tous les fichiers csv dans un dossier
Changer la destination de sortie standard en un fichier en Python
Différentes façons de calculer la similitude entre les données avec python
[Note] Importation de fichiers dans le répertoire parent en Python
Comment obtenir la dernière (dernière) valeur d'une liste en Python
Comment déterminer l'existence d'un élément sélénium en Python
Comment vérifier la taille de la mémoire d'une variable en Python
Comment vérifier la taille de la mémoire d'un dictionnaire en Python
Lisez le fichier en Python avec un chemin relatif depuis le programme
Différentes façons de créer un tableau de nombres de 1 à 10 en Python.
[Python] Compréhension de liste Différentes façons de créer une liste
Lire un fichier contenant des lignes brouillées en Python
Récupérer l'appelant d'une fonction en Python
Comment créer un fichier JSON en Python
Copiez la liste en Python
Sortie sous la forme d'un tableau python
Lire ligne par ligne à partir d'un fichier avec Python
Comment lire des fichiers dans différents répertoires
Évaluation de la vitesse de sortie du fichier CSV en Python
Lire le fichier csv Python
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python
Python --Lisez les données d'un fichier de données numériques et recherchez la ligne de régression multiple.
[Python] Analyser le dossier, y compris les sous-dossiers → Exporter la liste des fichiers au format CSV
Dessinez une ligne de pliage / diagramme de dispersion avec python matplotlib pour fichier CSV (2 colonnes)
Je veux obtenir le nom du fichier, le numéro de ligne et le nom de la fonction dans Python 3.4
Comment obtenir une liste de fichiers dans le même répertoire avec python
Analyser une chaîne JSON écrite dans un fichier en Python
Diverses méthodes pour extraire les colonnes du tableau NumPy
Comment obtenir le nombre de chiffres en Python
J'ai essayé de toucher un fichier CSV avec Python
Lisez le fichier csv et affichez-le dans le navigateur
Un mémorandum pour exécuter un script python dans un fichier bat
Lisez le fichier xml en vous référant au didacticiel Python
Je veux échantillonner au hasard un fichier avec Python
Script Python qui crée un fichier JSON à partir d'un fichier CSV
Afficher le résultat de sortie de sklearn.metrics.classification_report sous forme de fichier CSV
Un mémorandum sur la mise en œuvre des recommandations en Python
Comment lire un csv contenant uniquement des entiers en Python
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Note Python: Le mystère de l'attribution d'une variable à une variable
Que signifie le dernier () dans une fonction en Python?
J'ai créé un script pour vérifier si l'anglais est entré dans la position spécifiée du fichier JSON en Python.
Comment afficher la date de modification d'un fichier en langage C jusqu'à nanosecondes
Comment identifier l'élément avec le plus petit nombre de caractères dans une liste Python?
[Ansible] Exemple de playbook qui ajoute une chaîne de caractères à la première ligne du fichier
Une note qui implémente une tâche en Python qui charge un fichier GCS dans BigQuery
Notez que la méthode de publication des modules sur PyPI a changé de différentes manières.