如何在 Python 中对大文本文件流进行过滤和排序
Posted
技术标签:
【中文标题】如何在 Python 中对大文本文件流进行过滤和排序【英文标题】:How to filter and sort stream of large text file in Python 【发布时间】:2017-02-22 17:16:23 【问题描述】:我有一个包含三个逗号分隔值的大文本文件 (>1GB),我想将它们分块读入 Pandas DataFrame。下面是 DataFrame 的一个示例:
我想在读入这个文件时过滤它并输出一个“干净”的版本。我遇到的一个问题是一些时间戳是无序的,但问题通常是非常局部的(通常一个刻度在之前或下方的几个插槽中是无序的)。有没有办法进行本地化的“滑动窗口”排序?
另外,由于我对 Python 还很陌生,并且正在学习 I/O 方法,因此我不确定用于过滤大型数据文件的最佳类/方法。文本IO基础?
【问题讨论】:
【参考方案1】:这是一个非常有趣的问题,因为数据大到无法轻易放入内存。
首先,关于 I/O:如果是 CSV,我会使用标准库 csv.reader()
对象,就像这样(我假设是 Python 3):
with open('big.csv', newline='') as f:
for row in csv.reader(f):
...
然后我可能会在collections.deque(maxlen=WINDOW_SIZE)
实例中保留一个滑动窗口,根据您的描述,窗口大小可能设置为 20。将第一行WINDOW_SIZE
读入双端队列,然后进入主读取循环,输出双端队列中最左边的项(行),然后追加当前行。
附加每一行后,如果当前行的时间戳在前一行的时间戳之前(window[-2]
),则对双端队列进行排序。您不能直接对双端队列进行排序,但可以执行以下操作:
window = collections.deque(sorted(window), maxlen=WINDOW_SIZE)
Python 的 Timsort 算法可以有效地处理已排序的运行,因此这应该非常快(线性时间)。
如果窗口大小和乱序行数很小(听起来可能如此),我相信整体算法将是 O(N),其中 N 是数据中的行数文件,所以线性时间。
更新:我编写了一些演示代码来生成这样的文件,然后使用上述技术对其进行排序——参见this Gist,在 Python 3.5 上进行了测试。它比 sort
在相同数据上的实用程序快得多,并且在大约 N = 1,000,000 之后也比 Python 的 sorted()
函数快得多。顺便说一句,生成演示 CSV 的函数比排序代码慢得多。 :-) 我对各种 N 的结果计时 process_sliding()
(绝对看起来是线性的):
作为参考,这是我的process_sliding()
版本的代码:
def process_sliding(in_filename, out_filename, window_size=20):
with (open(in_filename, newline='') as fin,
open(out_filename, 'w', newline='') as fout):
reader = csv.reader(fin)
writer = csv.writer(fout)
first_window = sorted(next(reader) for _ in range(window_size))
window = collections.deque(first_window, maxlen=window_size)
for row in reader:
writer.writerow(window.popleft())
window.append(row)
if row[0] < window[-2][0]:
window = collections.deque(sorted(window), maxlen=window_size)
for row in window:
writer.writerow(row)
【讨论】:
我会使用 iteetools.islice 来获取大量数据 @Copperfield 你能说得更具体点吗?如果您的意思是在获取first_window
块时,我考虑过这一点,但我认为避免导入并使用更基本的内置函数通常更清晰、更简单。
是的,我的意思是first_window
。此外,您当前的方式有抛出 StopIteration 异常的风险,也许对于这个用例来说这不是问题,但为什么要留下一个容易避免的问题呢?以上是关于如何在 Python 中对大文本文件流进行过滤和排序的主要内容,如果未能解决你的问题,请参考以下文章
如何从python中的文本文档中删除所有标点符号和其他符号?