【问题标题】:Python halts while iteratively processing my 1GB csv filePython 在迭代处理我的 1GB csv 文件时停止
【发布时间】:2010-01-06 01:39:33
【问题描述】:

我有两个文件:

  1. metadata.csv:包含一个 ID,后跟供应商名称、文件名等
  2. hashes.csv:包含一个 ID,后跟一个哈希 ID 本质上是一种外键,将文件元数据与其哈希相关联。

我编写此脚本是为了快速提取与特定供应商相关的所有哈希值。它在处理完 hashes.csv 之前就崩溃了

stored_ids = []

# this file is about 1 MB
entries = csv.reader(open(options.entries, "rb"))

for row in entries:
  # row[2] is the vendor
  if row[2] == options.vendor:
    # row[0] is the ID
    stored_ids.append(row[0])

# this file is 1 GB
hashes = open(options.hashes, "rb")

# I iteratively read the file here,
# just in case the csv module doesn't do this.
for line in hashes:

  # not sure if stored_ids contains strings or ints here...
  # this probably isn't the problem though
  if line.split(",")[0] in stored_ids:

    # if its one of the IDs we're looking for, print the file and hash to STDOUT
    print "%s,%s" % (line.split(",")[2], line.split(",")[4])

hashes.close()

此脚本在停止之前通过 hashes.csv 获取大约 2000 个条目。我究竟做错了什么?我以为我正在逐行处理它。

ps。 csv 文件是流行的 HashKeeper 格式,我正在解析的文件是 NSRL 哈希集。 http://www.nsrl.nist.gov/Downloads.htm#converter

更新:下面的工作解决方案。感谢所有评论的人!

entries = csv.reader(open(options.entries, "rb"))   
stored_ids = dict((row[0],1) for row in entries if row[2] == options.vendor)

hashes = csv.reader(open(options.hashes, "rb"))
matches = dict((row[2], row[4]) for row in hashes if row[0] in stored_ids)

for k, v in matches.iteritems():
    print "%s,%s" % (k, v)

【问题讨论】:

  • 停止是什么意思?它中途停止了吗?挂起?有任何错误信息吗?
  • 没有错误信息。它只打印我们大约 2000 行的输出并停止。此时 CPU 使用率相当高,python 进程约为 45%。我没有收到索引错误。

标签: python memory csv large-files


【解决方案1】:

“胡扯”并不是一个特别好的描述。它有什么作用?它交换吗?填满所有内存?还是只是吃CPU而不做任何事情?

不过,作为开始,请使用字典而不是 stored_ids 的列表。在字典中搜索通常在 O(1) 时间内完成,而在列表中搜索是 O(n)。

编辑:这是一个微不足道的微基准:

$ python -m timeit -s "l=range(1000000)" "1000001 in l"
10 loops, best of 3: 71.1 msec per loop
$ python -m timeit -s "s=set(range(1000000))" "1000001 in s"
10000000 loops, best of 3: 0.174 usec per loop

如您所见,集合(具有与 dict 相同的性能特征)在 100 万个整数中的搜索速度比类似列表快 10000 倍(远小于 1 微秒,而每次查找几乎 100 毫秒) .考虑到对 1GB 文件的每一行都进行了这样的查找,并且您了解问题的严重程度。

【讨论】:

  • 我会玩弄它,但我认为这不是问题所在。我应该将stored_ids中的项目转换为整数,这样它至少可以更有效地搜索......
  • 这是完全错误的。从 O(n) 容器切换到 O(1) 容器比尝试微优化比较操作要高效得多。我将在上面的答案中添加一个基准。
【解决方案2】:

此代码将在任何没有至少 4 个逗号的行上消失;例如,它会死在一条空行上。如果您确定不想使用 csv 阅读器,那么至少在 line.split(',')[4] 上捕获 IndexError

【讨论】:

  • 该过程在 4 个不同数据集的几乎完全相同的输出行处停止,让我相信情况并非如此。不过,我会添加适当的错误捕获并报告回来。
【解决方案3】:

请解释一下停止是什么意思?它挂起还是退出?有没有错误回溯?

a) 它会在任何没有“,”的行上失败

>>> 'hmmm'.split(",")[2]
Traceback (most recent call last):
  File "<string>", line 1, in <string>
IndexError: list index out of range

b) 你为什么要多次拆分线路,而不是这样做

tokens = line.split(",")

if len(tokens) >=5 and tokens[0] in stored_ids:
    print "%s,%s" % (tokens[2], tokens[4])

c) 创建一个stored_ids 的字典,所以stored_id 中的tokens[0] 会很快

d) 将你的内部代码包装在 try/exept 中,看看是否有任何错误

e) 你是在命令行还是某个 IDE 上运行它?

【讨论】:

  • a) 没问题 b) 因为我很懒。我会改变它。 c) 会做 d) 没有,但我会再次尝试 e) Win32 上的 Python 2.6.4
【解决方案4】:

在数组中搜索需要 O(n),所以请改用 dict

stored_ids = dict((row[0],1) for row in entries if row[2] == options.vendor)

或使用集合

a=set(row[0] for row in entries if row[2] == options.vendor)
b=set(line.split(",")[0] for line in hashes)
c=a.intersection(b)

c 中,您只会找到哈希和 csv 的字符串

【讨论】:

  • 哈哈!我从未在 Python 中使用过集合。我喜欢。明天当我再次面对我的代码时,我会尝试一下。
猜你喜欢
  • 2019-01-17
  • 2015-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 2020-09-28
  • 1970-01-01
相关资源
最近更新 更多