为自定义词汇表创建 N-gram 模型

Create a N-gram model for custom vocabulary

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

vocabs = [ [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 不是很熟悉,这些例子让我很困惑。如果有人能回答我的问题,我将非常高兴 and/or 指出一些一般学习 N-Grams 的教程(不特定于 NLP)。

谢谢。

编辑:

为了简化问题,我会尝试用不同的方式解释它: 我的词汇如下:

vocabs = [v1, v2, v3, ........vn]

我还有两个sequence generator(SG)。他们都从我的词汇表中生成了一系列单词。

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

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

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

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

谢谢。

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

首先 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 中出现的次数,select 中出现频率更高的序列。

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" 几乎没有任何共同点。而且我认为您真正需要的是获得单词之间的距离分数。我猜是因为你所说的:

In the example I wanted to show that, the training "words" (list of 3 number) are not exactly the same as the "words" in my vocabulary but they will be very close.

在那种情况下,在这里显示它有点太复杂了,但您可能想测量

之间的距离

"vocabs"中每个元素的每个编号

"training_data"

中每个序列中每个元素的每个编号

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

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

那样的话,你绝对可以使用n-grams。

首先让我确定我理解了:

你的词汇量:

vocabs = [v0, v1, v2, v3, ........vn]

和 2 个序列生成器,它们从您的词汇表中获取元素和 return 词汇表序列列表:

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 的 word2vec, doc2vec or fastText 并采用或改编它们。