3

我正在尝试在 .txt 文件的语料库上运行 word2vec(在 gensim 中实现的跳过语法模型,默认窗口大小为 5)。我使用的迭代器看起来像这样:

class Corpus(object):
    """Iterator for feeding sentences to word2vec"""
    def __init__(self, dirname):
        self.dirname = dirname

    def __iter__(self):

        word_tokenizer = TreebankWordTokenizer()
        sent_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
        text = ''

        for root, dirs, files in os.walk(self.dirname):

            for file in files:

                if file.endswith(".txt"):

                    file_path = os.path.join(root, file)


                    with open(file_path, 'r') as f:

                         text = f.read().decode('utf-8')
                         sentences = sent_tokenizer.tokenize(text)

                         for sent in sentences:
                             yield word_tokenizer.tokenize(sent)

在这里,我使用 nltk 包中的 punkt 分词器(它使用无监督算法来检测句子边界)将文本拆分为句子。但是,当我将其替换为一个简单的line.split()即仅将每个句子视为一行并拆分单词时,我得到的时间效率比使用 nltk 解析器快 1.5 倍。'with open' 中的代码如下所示:

                 with open(file_path, 'r') as f:
                    for line in f:
                    line.decode('utf-8')
                    yield line.split()

我的问题是,对于 word2vec 算法来说,输入实际句子的句子有多重要(我试图用 punkt tokenizer 做的事情)?算法中的每个单词是否足以接收位于一行上的周围单词的上下文(在跨多行的句子的情况下,这些单词可能不一定是实际句子)而不是单词的上下文这个词在一个句子中可能有好几行。此外,窗口大小在其中起到什么样的作用。例如,当窗口大小设置为 5 时,Sentences 迭代器产生的句子大小是否不再起作用?那么只有窗口大小会决定上下文词吗?在那种情况下,我应该只使用line.split()而不是尝试使用 punkt 标记器检测实际的句子边界吗?

我希望我能够充分描述这个问题,我非常感谢任何关于此的意见、指示或帮助。

4

1 回答 1

4

window 只是上下文窗口。如果window设置为 5,则当前单词w周围 10 个单词将被视为上下文单词。根据原始 word2vec 代码,单词仅在句子中存在的上下文上进行训练。如果单词 + 上下文单词超出了句子边界,那么其余的上下文单词将被简单地忽略(近似值)。

例如:考虑句子:I am a boy 如果当前单词是boy并且window是 2 那么我们可以观察到没有正确的上下文。在这种情况下,代码将取向量的平均值,am并将a其视为boy(参考 word2vec 的 CBOW 模型)的上下文。

对于第二个疑问,我使用了没有句子边界的文本语料库,但 word2vec 仍然可以。(在维基百科语料库中对此进行了测试)

希望这能解决您的疑问。

于 2017-01-31T10:01:11.663 回答