使用numpy/pandas在Python中读取CSV文件的最后N行

4
有没有一种快速的方法在Python中读取CSV文件的最后N行,使用`numpy`或`pandas`?
  1. 由于文件长度变化,我无法在 `numpy` 中使用 `skip_header` 或在 `pandas` 中使用 `skiprow`,我总是需要最后N行。
  2. 我知道我可以使用纯Python从文件的最后一行逐行读取,但这样会非常慢。如果必须这样做,我可以这样做,但使用`numpy`或`pandas`(本质上是使用C)更有效的方法将不胜感激。
3个回答

10

我尝试了两种方法,用一个只有10行的小测试文件 - 解析整个文件并选择最后N行,或加载所有行,但只解析最后N行:

In [1025]: timeit np.genfromtxt('stack38704949.txt',delimiter=',')[-5:]
1000 loops, best of 3: 741 µs per loop

In [1026]: %%timeit 
      ...: with open('stack38704949.txt','rb') as f:
      ...:      lines = f.readlines()
      ...: np.genfromtxt(lines[-5:],delimiter=',')

1000 loops, best of 3: 378 µs per loop

这被标记为Efficiently Read last 'n' rows of CSV into DataFrame的重复问题。那里接受的答案使用了

from collections import deque

并收集了该结构中的最后N行。它还使用StringIO将这些行提供给解析器,这是不必要的复杂性。genfromtxt从任何给定它行的地方获取输入,因此行的列表完全可以。

In [1031]: %%timeit 
      ...: with open('stack38704949.txt','rb') as f:
      ...:      lines = deque(f,5)
      ...: np.genfromtxt(lines,delimiter=',') 

1000 loops, best of 3: 382 µs per loop

readlines和切片操作基本相同。

deque可能在文件非常大且保留所有行变得昂贵时具有优势。我认为它并没有节省任何文件读取时间。每一行仍然必须逐个读取。

row_countskip_header方法的计时较慢;它需要两次读取文件。skip_header仍然需要逐行读取。

In [1046]: %%timeit 
      ...: with open('stack38704949.txt',"r") as f:
      ...:       ...:     reader = csv.reader(f,delimiter = ",")
      ...:       ...:     data = list(reader)
      ...:       ...:     row_count = len(data)
      ...: np.genfromtxt('stack38704949.txt',skip_header=row_count-5,delimiter=',')

The slowest run took 5.96 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 760 µs per loop

为了计算行数,我们不需要使用csv.reader,尽管它似乎不会花费太多额外时间。

In [1048]: %%timeit 
      ...: with open('stack38704949.txt',"r") as f:
      ...:    lines=f.readlines()
      ...:    row_count = len(data)
      ...: np.genfromtxt('stack38704949.txt',skip_header=row_count-5,delimiter=',')

1000 loops, best of 3: 736 µs per loop

3

选项1

您可以使用numpy.genfromtxt读取整个文件,将其作为numpy数组获取,并提取最后N行:

a = np.genfromtxt('filename', delimiter=',')
lastN = a[-N:]

选项2

你可以使用常规文件读取进行类似的操作:

with open('filename') as f:
    lastN = list(f)[-N:]

但是这一次,您将获得最后N行的列表,以字符串形式呈现。

选项3 - 无需将整个文件读入内存

我们使用一个最多包含N个项目的列表来保存每次迭代的最后N行:

lines = []
N = 10
with open('csv01.txt') as f:
    for line in f:
        lines.append(line)
        if len(lines) > 10:
            lines.pop(0)

一个真正的csv需要进行细微的更改:

import csv
...
with ...
    for line in csv.reader(f):
    ...

3

使用 pandasread_csv() 函数的 skiprows 参数,更难的是找到 csv 文件中的行数。以下是一个可能的解决方案:

with open('filename',"r") as f:
    reader = csv.reader(f,delimiter = ",")
    data = list(reader)
    row_count = len(data)

df = pd.read_csv('filename', skiprows = row_count - N)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接