【问题标题】:Create a N-gram model for custom vocabulary为自定义词汇创建 N-gram 模型
【发布时间】:2019-05-14 01:02:17
【问题描述】:

我想创建一个不适用于“英语单词”的 N-Gram 模型。我有一个自定义词汇表,如下所示:

词汇 = [ [0.364, 0.227, 0.376], [0.875, 0.785, 0.376], .... ]

我想说的是,我的词汇表中的每个元素都需要被 N-Gram 模型视为一个“单词”。我的训练数据集将包含一些与我的词汇表格式完全相同的数字,如下所示:

training_data = [ [0.344, 0.219, 0.374], [0.846, 0.776, 0.376], .... ]

注意:在我想展示的示例中,训练的“单词”(3 个数字的列表)与我词汇表中的“单词”并不完全相同,但它们会非常关闭。

现在,我的问题是,我可以构建一个可以使用训练数据进行训练的 N-Gram 模型吗?然后,使用该模型来预测新“单词”出现的概率。

我正在使用 python,可以使用“nltk”库找到很多 N-Gram 示例。但问题是在大多数情况下使用“英文单词”。由于我对 N-Grams 不是很熟悉,这些例子让我很困惑。如果有人能回答我的问题和/或指出一些学习 N-Grams 的教程(不特定于 NLP),我将非常高兴。

谢谢。

编辑:

为了简化问题,我将尝试以不同的方式解释它: 我有一个像下面这样的词汇:

词汇 = [v1, v2, v3, ........vn]

我还有两个序列发生器(SG)。它们都从我的词汇表中生成了一系列单词。

我的目标是从流数据中预测:哪个生成器当前正在生成序列(单词)。

现在我想使用我标记的训练数据(我已经有一些来自 SG 的标记数据)构建两个 N-gram 模型(每个 SG 一个)。最后,当我将流数据输入模型并通过比较 N-gram 模型的预测来选择可能的 SG 时。为了明确 SG1 的 N-gram 模型是否比 SG2 的 N-gram 模型给出更高的概率,我将确定当前的流数据是由 SG1 生成的。

希望解释有助于理解我的担忧。我非常感谢您为回答这个问题所做的努力。

注意:如果您知道其他可以很好地解决这个问题的模型(比 N-gram 模型更好),请提及。

谢谢。

【问题讨论】:

  • 不确定这是否会有所帮助,但您可以将其视为类似的东西,而不是单词将其视为字符串,我不太了解 N-gram,但从查看您可以将这些元素转换为字符串,然后在完成操作后将其转换回整数。

标签: python nlp nltk prediction n-gram


【解决方案1】:

在这种情况下,您绝对可以使用 n-gram。

首先让我确保我理解:

你有一个词汇:

词汇 = [v0, v1, v2, v3, ........vn]

还有 2 个序列生成器,它们从您的词汇中获取元素并返回词汇序列列表:

sg1 = [v0, v1, v2, v1, v3] sg2 = [v2, v4, v6, v2, v8]

现在,如果我理解正确,您想使用 n-gram 人为地复制和增强您的 sg1 和 sg2 输出:

ngramSg1 = [v0, v1, v3, v0, v1, v2, v1, v2, ...] ngramSg2 = [v2, v4, v6, v2, v8, v2, v6, v2, ...]

然后,您想使用 ML 模型来确定 n-gram 输出的来源(SG1 或 SG2)。我对吗?我在盘旋吗?

如果和我描述的一样,那么您应该可以使用我在上一个答案中编写的代码或您想要的任何 n-gram 库。尽管如此,如果我理解正确,您的词汇表是由数字列表而不是单个对象组成的。如果是这种情况,那么您可能找不到任何可以处理它的库。太具体了您可能必须编写自己版本的基于 n-gram 的序列生成器。

但是,您的案例对于词嵌入(基本上是使用向量作为词的表示形式的语言处理算法)看起来有点熟悉。如果您还不了解它们,您可能需要查看 gensim 的 word2vecdoc2vecfastText,然后采用或调整它们。

【讨论】:

    【解决方案2】:

    好的,我不确定你到底想做什么。不过我们还是试试吧。

    首先,N-gram 是如何工作的: N-gram 是序列概率的非常简单的预测器。由于句子只是单词序列,单词只是字符序列,因此它通常适用于字符串:

    问题:你有一个字母列表,你想找出序列中的下一个字母是什么。

    letterSequence = ['a', 'b', None] 
    

    如果你有一堆字母按顺序排列,你可以记下这些序列是什么:

    training_data = ['a', 'b', 'c',
                 'a', 'b', 'c',
                 'a', 'b', 'd',
                 'a', 'b', 'f',
                 'b', 'c', 'd']
    

    乍一看,你可以看到序列 'a','b','c' 的概率是 'a','b','d' 或 'a' 的概率的两倍','b','f'。 我们要做的是统计相同序列在training_data中出现的次数,然后选择出现频率更高的那个。

    def makeNestedDict(aDict, listOfKeys):
        if len(listOfKeys) == 0: 
            if aDict != {}: return aDict
            return 0
        if listOfKeys[0] not in aDict:
            aDict[listOfKeys[0]] = {}
        aDict[listOfKeys[0]] = makeNestedDict(aDict[listOfKeys[0]], listOfKeys[1:])
        return aDict
    
    def makeCoreferenceDict(ressource):
        #we'll use 3-grams but we could have chosen any n for n-grams
        ngramDict = {}
        index = 0
        #we make sure we won't go further than the length of the list
        while (index+2) < len(ressource):
            k1 = ressource[index]
            k2 = ressource[index+1]
            k3 = ressource[index+2]
            ngramDict = makeNestedDict(ngramDict, [k1, k2, k3])            
            ngramDict[k1][k2][k3] += 1 #counting
            index += 1
        return ngramDict
    
    def predict(unkSequence, ngramDict):
        import operator
        corefDict = ngramDict[unkSequence[0]][unkSequence[1]]
        return max(corefDict.items(), key=operator.itemgetter(1))
    
    ############################################
    ngramDict = makeCoreferenceDict(training_data)
    #the most common letter that follows 'a', 'b' is... 
    predict(letterSequence, ngramDict)
    >>> ('c', 2) #... is 'c' and it appears twice in the data
    

    您还可以通过替换行(在 makeCoreferenceDict 函数中)来获得预测分数,而不是获得最常见的元素:

    ngramDict[k1][k2][k3] += 1 #counting
    

    与:

    ngramDict[k1][k2][k3] += 1.0/float(len(ressource)) #add to the score
    

    所以:

    def showScore(unkSequence, ngramDict):
        return ngramDict[unkSequence[0]][unkSequence[1]]
    
    ############################################
    ngramDict = makeCoreferenceDict(training_data)
    #the most common letter that follows 'a', 'b' is... 
    showScore(letterSequence, ngramDict)
    >>> {'c': 0.13333333333333333, 'd': 0.06666666666666667, 'f': 0.06666666666666667}
    

    现在,n-gram 方法依赖于有限的元素集(字符、单词、自然数等)。现在,在您的示例中,“vocabs”和“training_data”几乎没有任何共同点。而且我认为您真正需要的是获得单词之间的距离分数。我猜是因为你说的:

    在我想展示的示例中,训练“单词”(3 个数字的列表)与我的词汇表中的“单词”并不完全相同,但它们会非常接近。

    在这种情况下,在这里显示它有点太复杂了,但你可能想测量它们之间的距离

    “词汇”中每个元素的每个数字

    “training_data”中每个序列中每个元素的每个数字

    然后比较它们并选择较小的分数。

    如果这不是您问题的答案,请重新表述或给我们提供更多示例。 无论如何,祝你好运。

    【讨论】:

    • 感谢您的评论。但是你不认为使用像“sklearn”这样的库/包是更好的选择,而不是实现我自己的 N-gram 模型。
    • 是的,您可能希望为您想做的事情实现一个好的 ML 模型。如果您正在使用向量,或者如果您想要做的是分类器并且您的训练数据被标记,或者如果您想对您的数据使用 sklearn 向量器。但是在你解释你想做什么和你的目标是什么之前,很难给你一个更好的答案。你告诉我们你“想要创建一个不能使用‘英语单词’的 N-Gram 模型”。但是,正如我所解释的,看起来你需要的东西与 n-gram 并没有真正的关系,它一定是别的东西。我们不知道是什么。
    • 我编辑了这个问题。请查看更新版本。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 2013-11-25
    • 1970-01-01
    相关资源
    最近更新 更多