2016-03-14 1 views
5

Dans les pandas, je peux simplement utiliser pandas.io.parser.read_csv("file.csv", nrows=10000) pour obtenir les 10000 premières lignes d'un fichier CSV.Obtenir les 10000 dernières lignes d'un fichier CSV

Mais parce que mon fichier csv est énorme, et les dernières lignes sont plus pertinentes que les premières, je voudrais lire les 10000 dernières lignes. Cependant, ce n'est pas si simple, même si je connais la longueur du fichier, car si je saute les 990000 premières lignes d'un fichier csv de 1000000 à l'aide de pandas.io.parser.read_csv("file.csv", nrows=10000, skiprows=990000), la première ligne, qui contient l'en-tête du fichier, est également ignorée. (header=0 est appliqué après skiprows est appliqué, donc cela n'aide pas non plus.)

Comment obtenir les 10000 dernières lignes d'un fichier csv avec un en-tête dans la ligne 0, de préférence sans connaître la longueur du fichier dans les lignes ?

+0

Êtes-vous sur un système Linux ou OSX? Si oui, alors utiliser 'tail -n 10000 file> file2' sera probablement le plus simple ... – Carpetsmoker

+0

Si vous insistez sur l'utilisation de' Python', vous pouvez l'appeler sur subprocess.call () ': P – Mai

+0

@ Carpetsmoker mais il a également besoin d'un en-tête. Il devrait être comme 'head -n 1 file> file2; tail -n 10000 fichier >> file2' –

Répondre

5

Vous pouvez d'abord calculer votre taille du fichier avec:

size = sum(1 for l in open('file.csv')) 

Ensuite, utilisez skiprows avec range:

df = pd.read_csv('file.csv', skiprows=range(1, size - 10000)) 

EDIT

Comme mentionné @ivan_pozdeev avec cette solution vous besoin d'aller bien fichier deux fois. J'ai essayé de lire le fichier entier avec des pandas et ensuite j'utilise la méthode tail mais cette méthode est plus lente que suggérée.

Exemple dataframe:

pd.DataFrame(np.random.randn(1000000,3), columns=list('abc')).to_csv('file.csv') 

Timing

def f1(): 
    size = sum(1 for l in open('file.csv')) 
    return pd.read_csv('file.csv', skiprows=range(1, size - 10000)) 

def f2(): 
    return pd.read_csv('file.csv').tail(10000) 

In [10]: %timeit f1() 
1 loop, best of 3: 1.8 s per loop 

In [11]: %timeit f2() 
1 loop, best of 3: 1.94 s per loop 
+0

Note: ceci traverse deux fois le fichier entier. Je ne pense pas que je verrais (mieux) un meilleur moyen ... –

+0

@ivan_pozdeev Je pensais qu'avec 'pd.read_csv ('file.csv'). Tail (10000)' ça va être plus rapide mais à cause du timing c'est un peu plus lent. –

+2

Avec 'queue', je suppose, vous lisez d'abord toutes les données dans un' DataFrame', puis prenez une tranche. Non seulement cela est plus lent, mais vous risquez de manquer de mémoire. –

1

La seule façon de prendre exactement les dernières lignes N est as per Anton Protopopov, d'abord passer par l'ensemble du dossier, en comptant les lignes.

Mais pour la prochaine étape, les prendre, l'optimisation peut être (ce qui tail fait):

  • que vous allez, sauf décalages de lignes dans un tampon circulaire de longueur N. Puis à la fin, l'élément le plus ancien dans le tampon sera le décalage requis. Puis tout ce qu'il faut est un f.seek() sur l'objet de fichier selon Working with 10+GB dataset in Python Pandas.

Une façon beaucoup plus rapide qui ne comprend pas passer par l'ensemble du dossier serait de pas besoin d'un nombre exact de lignes: de ce que je peux voir, vous avez seulement besoin une grande quantité arbitraire. Ainsi, vous pouvez:

  • obtenir une estimation approximative du vous décalage besoin de chercher à (par exemple calculer/estimer la durée moyenne d'une ligne)
  • y chercher, puis à l'autre (ou précédent) saut de ligne

    Cela nécessite une précaution supplémentaire si vous pouvez avoir des données avec des sauts de ligne incorporés: dans ce cas, il n'y a pas de moyen infaillible pour détecter les guillemets qui s'ouvrent et qui sont fermés. Vous devez faire des hypothèses sur ce qui peut et ce qui ne peut pas être des citations à l'intérieur/à l'extérieur ...et même jusqu'à quel point chercher un devis pour savoir si le saut de ligne est intégré!

0

Vous pouvez tail de pandas géants, il renvoie des lignes dernières n

df.tail(10000) 
3

en utilisant le fichier exemple @Anton Protopopov. La lecture dans un bit partiel du fichier et l'en-tête dans des opérations séparées est BEAUCOUP moins cher que la lecture du fichier entier.

Il suffit de lire directement les lignes finales

In [22]: df = read_csv("file.csv", nrows=10000, skiprows=990001, header=None, index_col=0) 

In [23]: df 
Out[23]: 
       1   2   3 
0         
990000 -0.902507 -0.274718 1.155361 
990001 -0.591442 -0.318853 -0.089092 
990002 -1.461444 -0.070372 0.946964 
990003 0.608169 -0.076891 0.431654 
990004 1.149982 0.661430 0.456155 
...   ...  ...  ... 
999995 0.057719 0.370591 0.081722 
999996 0.157751 -1.204664 1.150288 
999997 -2.174867 -0.578116 0.647010 
999998 -0.668920 1.059817 -2.091019 
999999 -0.263830 -1.195737 -0.571498 

[10000 rows x 3 columns] 

assez rapide pour faire

In [24]: %timeit read_csv("file.csv", nrows=10000, skiprows=990001, header=None, index_col=0) 
1 loop, best of 3: 262 ms per loop 

Jolie pas cher pour déterminer la longueur du fichier a priori

In [25]: %timeit sum(1 for l in open('file.csv')) 
10 loops, best of 3: 104 ms per loop 

Lire en l'en-tête

In [26]: df.columns = read_csv('file.csv', header=0, nrows=1, index_col=0).columns 

In [27]: df 
Out[27]: 
       a   b   c 
0         
990000 -0.902507 -0.274718 1.155361 
990001 -0.591442 -0.318853 -0.089092 
990002 -1.461444 -0.070372 0.946964 
990003 0.608169 -0.076891 0.431654 
990004 1.149982 0.661430 0.456155 
...   ...  ...  ... 
999995 0.057719 0.370591 0.081722 
999996 0.157751 -1.204664 1.150288 
999997 -2.174867 -0.578116 0.647010 
999998 -0.668920 1.059817 -2.091019 
999999 -0.263830 -1.195737 -0.571498 

[10000 rows x 3 columns]