我正在尝试计算文本文件中字符串的出现次数。 文本文件看起来像这样,每个文件大约200MB。
String1 30
String2 100
String3 23
String1 5
.....
我想将计数保存到字典中。
count = {}
for filename in os.listdir(path):
if(filename.endswith("idx")):
continue
print filename
f = open(os.path.join(path, filename))
for line in f:
(s, cnt) = line[:-1].split("\t")
if(s not in count):
try:
count[s] = 0
except MemoryError:
print(len(count))
exit()
count[s] += int(cnt)
f.close()
print(len(count))
我在count[s] = 0
遇到内存错误,
但我的电脑里还有更多的可用内存
我该如何解决这个问题?
谢谢!
更新:
我在这里复制了实际的代码。
我的python版本是2.4.3,并且该机器运行linux并且具有大约48G内存,但它仅消耗不到5G。代码在len(count)=44739243
停止。
UPDATE2: 字符串可以重复(不是唯一的字符串),所以我想要添加字符串的所有计数。我想要的操作只是读取每个字符串的计数。每个文件大约有10M行,我有30多个文件。我预计这个数字还不到1000亿。
UPDATE3: 操作系统是linux 2.6.18。
答案 0 :(得分:4)
cPython 2.4可能会出现大内存分配问题,即使在x64上也是如此:
$ python2.4 -c "'a' * (2**31-1)"
Traceback (most recent call last):
File "<string>", line 1, in ?
MemoryError
$ python2.5 -c "'a' * (2**31-1)"
$
更新到最近的python解释器(如cPython 2.7)以解决这些问题,并确保安装64位版本的解释器。
如果字符串具有非平凡的大小(即长于示例中的&lt; 10字节),您可能还想简单地存储它们的哈希值,甚至使用概率(但更有效)存储,如{ {3}}。要存储它们的哈希值,请用
替换文件处理循环import hashlib
# ...
for line in f:
s, cnt = line[:-1].split("\t")
idx = hashlib.md5(s).digest()
count[idx] = count.get(idx, 0) + int(cnt)
# ...
答案 1 :(得分:1)
如果你要做的只是计算唯一字符串的数量,你可以通过散列每个字符串来大大减少你的内存占用:
(s, cnt) = line[:-1].split("\t")
s = hash(s)
答案 2 :(得分:1)
我不确定为什么会发生这种崩溃。你的字符串估计平均大小有多长?如果它们有点冗长,你应该考虑对它们进行散列,如已经建议的那样。缺点是,您放弃了列出唯一键的选项,只需检查数据中是否包含字符串。
关于已经达到5 GB的内存限制,可能与你过时的python版本有关。如果您可以选择更新,请获取2.7。相同的语法(加上一些额外的),没有问题。好吧,我甚至不知道下面的代码是否仍然与2.4兼容,也许你必须再次发出with语句,至少这是你在2.7中编写它的方式。
您的版本的主要区别是手动运行垃圾收集。另外,你可以提高python使用的内存限制。正如你所提到的,它只使用了一小部分实际内存,所以万一有一些奇怪的默认设置禁止它变大,试试这个:
MEMORY_MB_MAX = 30000
import gc
import os
import resource
from collections import defaultdict
resource.setrlimit(resource.RLIMIT_AS, (MEMORY_MB_MAX * 1048576L, -1L))
count = defaultdict(int)
for filename in os.listdir(path):
if(filename.endswith("idx")):
continue
print filename
with open(os.path.join(path, filename)) as f:
for line in f:
s, cnt = line[:-1].split("\t")
count[s] += int(cnt)
print(len(count))
gc.collect()
除此之外,我没有理解你的行s, cnt = line[:-1].split("\t")
,尤其是[:-1]
。如果文件看起来像你注意到的那样,那么这将删除你的数字的最后数字。这是故意的吗?