我有两个文本文件,都由大约700000行组成。
第二个文件包含对第一个文件中对应行的语句的响应。
我需要计算fisher对匹配行中出现的每个词对的准确分数。
例如,如果文件中的n行是
how are you
和
fine thanx
然后我需要计算费舍尔的分数(how,fine),(how,thanx),(are,fine),(are,thanx),(you,fine),(you,thanx)。
为了计算fisher的准确分数,我使用collections模块的计数器来计算每个单词的出现次数,以及它们在两个文件中的共同出现次数,如
with open("finalsrc.txt") as f1, open("finaltgt.txt") as f2:
for line1, line2 in itertools.izip(f1, f2):
words1 = list(set(list(find_words(line1))))
words2 = list(set(list(find_words(line2))))
counts1.update(words1)
counts2.update(words2)
counts_pair.update(list(set(list(itertools.product(words1, words2)))))
然后我使用scipy模块计算每对的fisher精确分数
from scipy import stats
def calculateFisher(s, t):
sa = counts1[s]
ta = counts2[t]
st = counts_pair[s, t]
snt = sa - st
nst = ta - st
nsnt = n - sa - ta + st
oddsratio, pvalue = stats.fisher_exact([[st, snt], [nst, nsnt]])
return pvalue
对于小的文本文件来说,这样做又快又好,
但是由于我的文件每个包含700000行,我认为计数器太大,无法快速检索值,这变得非常慢。
(假设每个句子有10个单词,则计数对将有(10^2)*700000=7000000个条目。)
完成文件中所有单词对的计算需要几十天的时间。
对此,明智的解决方法是什么?
我非常感谢你的帮助。
最佳答案
您到底是如何调用calculateFisher
函数的?你的counts_pair
不会有7000万个条目:很多词对会被多次看到,因此7000万是它们的计数之和,而不是键的数目。你应该只计算那些同时出现的对的精确测试,找到它们的最佳位置是counts_pair
但这意味着您可以对它进行迭代;如果您这样做了,就不必在counts_pair
中查找任何内容:
for (s, t), count in counts_pair.iteritems():
sa = counts1[s]
ta = counts2[t]
st = count
# Continue with Fisher's exact calculation
为了清楚起见,我已经把
calculate_fisher
函数分解了;我希望您能明白这一点。所以如果查字典会让你慢下来,这会帮你省下很多。如果没有,…做些分析,让我们知道到底发生了什么。但要注意的是,只要在一本大词典中查找关键字,就不应该让事情拖得太慢。但是,如果您的程序必须将其大部分数据交换到磁盘上,“快速检索值”将很困难。你的电脑里有足够的内存同时容纳三个计数器吗?第一个循环是否在合理的时间内完成所以找到瓶颈,你会知道更多需要修理的东西。
编辑:从你的评论听起来,你是在计算费舍尔的确切分数一遍又一遍在随后的一个步骤的文本处理为什么这么做?把你的程序分成两个步骤:首先,按照我描述的计算所有单词对的分数把每一对都写下来,然后在你计算的时候把分数写进一个文件里。完成后,使用一个单独的脚本将它们读回(现在,内存中除了这本大字典pairs&fisher的精确分数外,没有其他内容),然后重写。不管怎样,你都应该这样做:如果你花了十天的时间才拿到分数(而你仍然没有告诉我们什么是慢的,为什么),那就开始吧,十天之后你将永远拥有它们,可以随时使用。
我做了一个快速的实验,一个拥有一百万个
((word, word), count)
元组的python进程只需要300mb(在os x上,但是windows上的数据结构应该差不多相同)。如果你有1000万个不同的字对,你可以预期它需要大约2.5GB的内存。我怀疑你会有这么多的词对(但是检查!)如果你有4GB的内存,而且你没有做任何你没有告诉我们的错误,你应该没事的否则,YMMV。