我正在用python编写一个程序,对电影评论做一个unigram(以及最终的bigram等)分析。目标是创建要提供给libsvm的特征向量。我的特征向量中有50,000个奇怪的独特单词(这对我来说似乎相当大,但我相对肯定我是对的)。
我正在使用python字典实现作为哈希表,以便在我遇到它们时跟踪新单词,但是我注意到在处理前1000个奇数文档后出现了巨大的减速。如果我使用几个较小的散列表/字典,或者它会是相同/更差的话,我会有更好的效率(考虑到自然语言的分布)吗?
更多信息:
数据被分成1500个左右的文件,每个500字。每个文档中有100到300个唯一单词(相对于所有以前的文档)。
我目前的代码:
#processes each individual file, tok == filename, v == predefined class
def processtok(tok, v):
#n is the number of unique words so far,
#reference is the mapping reference in case I want to add new data later
#hash is the hashtable
#statlist is the massive feature vector I'm trying to build
global n
global reference
global hash
global statlist
cin=open(tok, 'r')
statlist=[0]*43990
statlist[0] = v
lines = cin.readlines()
for l in lines:
line = l.split(" ")
for word in line:
if word in hash.keys():
if statlist[hash[word]] == 0:
statlist[hash[word]] = 1
else:
hash[word]=n
n+=1
ref.write('['+str(word)+','+str(n)+']'+'\n')
statlist[hash[word]] = 1
cin.close()
return statlist
还要记住,我的输入数据大约为6mb,输出数据大约为300mb。我对这需要多长时间感到震惊,我觉得它不应该在运行时如此剧烈地减速。
减速:前50个文件大约需要5秒钟,最后50个文档大约需要5分钟。
答案 0 :(得分:5)
@ThatGuy做了修复,但实际上并没有告诉你:
减速的主要原因是
行 if word in hash.keys():
到目前为止费力地列出了所有密钥,然后费力地搜索该列表中的“word”。所花费的时间与键的数量成比例,即到目前为止发现的唯一字的数量。这就是它快速启动并变得越来越慢的原因。
你所需要的只是if word in hash:
,其中99.9999999%的案件需要的时间与钥匙的数量无关 - 这是获得字典的主要原因之一。
对statlist[hash[word]]
的态度也无济于事。顺便说一下,statlist=[0]*43990
中的固定大小需要解释。
更多问题
问题A:(1)您的代码在发布时遇到缩进失真,或者(2)hash
永远不会被该函数更新。很简单,如果word
不在hash
,即这是你第一次看到它,绝对没有任何反应。不执行hash[word] = n
语句(更新hash
的唯一代码)。所以hash
中不会有任何词语。
看起来这个代码块需要向左移动4列,以便它与外部if
对齐:
else:
hash[word]=n
ref.write('['+str(word)+','+str(n)+']'+'\n')
statlist[hash[word]] = 1
问题B:根本没有代码可以更新n
(据称到目前为止唯一字的数量)。
我强烈建议您尽可能多地接受@ThatGuy和我所做的那些建议,删除所有global
内容,修改代码,查看显着的几个打印语句点,并运行它说2个文件,每个3行,每个约4个字。确保它正常工作。然后在你的大数据集上运行它(打印被抑制)。在任何情况下,您可能希望定期发布统计数据(如文档数,行数,单词数,唯一单词数,已用时间等)。
另一个问题
问题C:我在评论@ ThatGuy的答案时提到了这一点,他同意我的意见,但你没有提到接受它:>>> line = "foo bar foo\n"
>>> line.split(" ")
['foo', 'bar', 'foo\n']
>>> line.split()
['foo', 'bar', 'foo']
>>>
您使用.split(“”)会导致虚假的“字词”并扭曲您的统计信息,包括您拥有的唯一字数。您可能会发现需要更改该硬编码的幻数。
我再说一遍:没有代码在功能中更新n
。即使为每个文档更新hash[word] = n
,执行n
似乎也很奇怪。
答案 1 :(得分:0)
我不认为Python的词典与你的减速有任何关系。特别是当你说条目大约是100时。我希望你指的是插入和重写,它们都是字典中的O(1)。问题可能是您在创建字典时没有使用iterators
(或一次加载一个键,值对),而是在内存中加载整个单词。在这种情况下,减速是由于内存消耗。
答案 2 :(得分:0)
我认为你在这里遇到了一些问题。大多数情况下,我不确定你要用statlist完成什么。在我看来,它似乎是你的字典的可怜副本。找到所有单词后创建它。
以下是我对你想要的猜测:
def processtok(tok, v):
global n
global reference
global hash
cin=open(tok, 'rb')
for l in cin:
line = l.split(" ")
for word in line:
if word in hash:
hash[word] += 1
else:
hash[word] = 1
n += 1
ref.write('['+str(word)+','+str(n)+']'+'\n')
cin.close()
return hash
注意,这意味着您不再需要“n”,因为您可以通过执行len(n)来发现它。