python - 如何在 Python 中随机播放磁盘上的文本文件

标签 python text-files bigdata shuffle

我正在处理一个大约 12*10^6 行的文本文件,该文件存储在我的硬盘上。 文件结构为:

data|data|data|...|data\n
data|data|data|...|data\n
data|data|data|...|data\n
...
data|data|data|...|data\n

没有标题,也没有唯一标识行的 id。

因为我想将它用于机器学习目的,所以我需要确保文本文件中没有可能影响随机学习的顺序。

通常我将此类文件上传到内存中,然后在将它们重写到磁盘之前将它们洗牌。不幸的是这次不可能,因为文件的大小,所以我必须直接在磁盘上管理洗牌(假设我没有磁盘空间问题)。关于如何使用 Python 有效地(以尽可能低的复杂性,即写入磁盘)管理此类任务有什么想法吗?

最佳答案

除了其中一个之外,所有这些想法都使用 O(N) 内存——但是如果您使用 array.arraynumpy.ndarray 我们谈论的是 N*4字节,明显小于整个文件。 (为简单起见,我将使用普通列表;如果您需要帮助转换为更紧凑的类型,我也可以展示。)


使用临时数据库和索引列表:

with contextlib.closing(dbm.open('temp.db', 'n')) as db:
    with open(path) as f:
        for i, line in enumerate(f):
            db[str(i)] = line
    linecount = i
    shuffled = random.shuffle(range(linecount))
    with open(path + '.shuffled', 'w') as f:
        for i in shuffled:
            f.write(db[str(i)])
os.remove('temp.db')

这是 2N 单行磁盘操作和 2N 单 dbm-key 磁盘操作,应该是 2NlogN 单磁盘磁盘操作等效操作,因此总复杂度为 O(NlogN)。


如果你使用像 sqlite3 这样的关系数据库而不是 dbm,你甚至不需要索引列表,因为你可以这样做:

SELECT * FROM Lines ORDER BY RANDOM()

这与上面的时间复杂度相同,空间复杂度是 O(1) 而不是 O(N)——理论上。实际上,您需要一个 RDBMS,它可以一次从 100M 的行集中为您提供一行,而无需在任何一侧存储这 100M。


另一种选择,不使用临时数据库——理论上 O(N**2),但实际上如果你碰巧有足够的内存让行缓存有用,可能会更快:

with open(path) as f:
    linecount = sum(1 for _ in f)
shuffled = random.shuffle(range(linecount))
with open(path + '.shuffled', 'w') as f:
    for i in shuffled:
        f.write(linecache.getline(path, i))

最后,通过将索引列表的大小加倍,我们可以消除临时磁盘存储。但在实践中,这可能会慢很多,因为您正在执行更多的随机访问读取,而驱动器几乎不擅长这些读取。

with open(path) as f:
    linestarts = [f.tell() for line in f]
    lineranges = zip(linestarts, linestarts[1:] + [f.tell()])
    shuffled = random.shuffle(lineranges)
    with open(path + '.shuffled', 'w') as f1:
        for start, stop in shuffled:
            f.seek(start)
            f1.write(f.read(stop-start))

关于python - 如何在 Python 中随机播放磁盘上的文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19304279/

相关文章:

python - __lt__ 而不是 __cmp__

python - Scipy griddata 在循环/内存泄漏中不起作用

python - Pandas,如果名称超过 20 个字符,则删除重复的名称行

c++ - 使用相对路径读取文本文件

utf-8 - 使用 Inno Setup 创建无 BOM 的 UTF8 文件(Unicode 版本)

java - 平衡器无法在HDFS HA中工作

hadoop - 只能复制到 0 个节点而不是 minReplication (=1)。有 2 个数据节点正在运行,并且没有节点被排除在此操作中

python - 使用 Django REST 框架进行序列化/反序列化的不同序列化器

c++ - 处理大文本文件

design-patterns - 监听事件、将事件分组并批量提交的最佳实践是什么?