0

我正在用 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 分钟。

4

3 回答 3

5

@ThatGuy 已经修复,但实际上并没有告诉你这个:

你减速的主要原因是线路

if word in hash.keys():

到目前为止,它费力地列出了所有键,然后费力地在该列表中搜索“单词”。花费的时间与键的数量成正比,即到目前为止找到的唯一词的数量。这就是为什么它开始很快,然后变得越来越慢。

您所需要的只是if word in hash:在 99.9999999% 的情况下需要时间,而与键的数量无关——这是拥有 dict 的主要原因之一。

胡闹statlist[hash[word]]也无济于事。顺便说一下,statlist=[0]*43990需要解释的固定大小。

更多问题

问题 A:要么(1)您的代码在发布时出现缩进失真,要么(2)hash该函数永远不会更新。很简单,如果word不在hashie 中,即这是您第一次看到它,那么绝对不会发生任何事情。该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是针对每个文档进行更新。

于 2011-02-21T05:29:29.887 回答
0

我认为 Python 的 Dictionary 与您在这里的减速没有任何关系。尤其是当您说条目大约为 100 时。我希望您指的是插入和检索,它们在字典中都是 O(1)。问题可能是您iterators在创建字典时没有使用(或一次加载一个键、值对)并且您将整个单词加载到内存中。在这种情况下,减速是由于内存消耗。

于 2011-02-21T03:33:33.263 回答
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) 来发现这一点。

于 2011-02-21T04:31:50.243 回答