NLP bag-of-words / TF-IDF用于聚类(和分类)短句

时间:2017-02-15 09:13:31

标签: node.js algorithm nlp k-means hierarchical-clustering

我想通过其中一个字符串键值(description)来聚类Javascript对象。我已经尝试了多种解决方案,并想了解如何解决问题。

我想要的: 假设我有一个对象数据库。可能有很多(可能数千,可能是数万)。我需要能够:

  1. 通过逻辑(有类)组中的相似性来聚类对象。语义匹配会很棒但是现在只需字符串相似就足够了。在他们聚集后,我需要为每个人分配一些categoryId(代表他们所属的集群)。
  2. 每当将新对象添加到数据库时,我需要将它们分类到现有组/建议新的群集。
  3. 我还没有尝试解决问题#2,但这是我尝试使用#1。

    • 使用Levenshtein距离进行层次聚类(单链接) - 此处的问题是性能,结果令人满意(我使用了来自hierarchical-clustering的{​​{1}}库)但在150左右,我不得不等一下。不会成千上万。

    • TF-IDF,矢量化+ k-means - 性能非常好。它将轻松地通过5000个对象。但结果肯定是关闭的(可能是我实现中的一个错误)。我使用npm中的natural库来计算TF-IDF和npm)。

    • 词袋+ k-means - 我现在正试图实现这个,但还没有运气。

    对于#2我想过使用朴素贝叶斯(但我还没有尝试过)。

    有什么建议吗?如果对象只是聚集就好了。如果我可以提取群组聚集的标签(比如来自TF-IDF)会更好。

1 个答案:

答案 0 :(得分:0)

使用张量流,可以创建一个深度学习模型,该模型一旦受过训练就可以用来预测传入单词的类别。

让我们假设这是数据集:

let data = [{description: 'just something', label: '1'}, {description: 'something else', label: '2'}]

在文本分类中要做的第一件事是将文本编码为张量。只要给定所关注的域,可以使用许多算法,只要它们可以带来良好的准确性。特别是,universal-sentence encoder可以将每个句子转换为大小为512的一维张量。

const useModel = await use.load()
let features = data.map(d => useModel.embed(d.description))
features = tf.stack(features) // create a 2d tensor from the array of 1d tensor
let labels = tf.oneHot([0, 1], 2) // encode it as oneHot
// more details on labels encoding in this answer 
// https://stackoverflow.com/questions/59127861/how-may-i-define-my-own-labels-in-tensorflow-js/59128300#59128300

第二件事是为分类创建模型。尽管可以使用FCNN,但是对于NLP处理,由于将在将输出转发到其他层时,这些单元将考虑数据的上下文,因此大多数使用LSTM或双向LSTM。这是这种模型的一个例子

const model = tf.sequential({
    layers: [
        tf.layers.lstm({ inputShape: [1, 512], units: 16, activation: "relu", returnSequences: true }),
        tf.layers.lstm({ units: 16, activation: "relu", returnSequences: true }),
        tf.layers.lstm({ units: 16, activation: "relu", returnSequences: false }),
        tf.layers.dense({ units: numberOfCategories, activation: "softmax" }),
    ]
}) // in this example of the numberOfCategories is 2

[n, 512]的inputShape用于指示模型一次将被n个句子喂入。如果句子的数量可变,则inputShape将为[null, 512]

模型将被训练

model.compile({
    optimizer: "adam",
    loss: "categoricalCrossentropy",
    metrics: ["accuracy"]
})
model.fit(features, labels, {
    epochs: number,// as needed to have a good accuracy
    callbacks: {
        onBatchEnd(batch, logs) {
            console.log(logs.acc)
        }
    }
})

训练完模型后,对于每个传入的单词,都会有一个预测。但是传入的单词将需要首先转换为上述张量a。

let prediction = model.predict( await useModel.embed('newWord').reshape([1, 1, -1])).argMax([-1])
prediction.print() // will print the index of the label

如果尚未标记训练数据(这意味着该对象没有标签属性),则应该对数据进行聚类。 tensorflow.js中尚无聚类算法。 对于文本集群,我们首先需要创建令牌。 use程序包具有令牌生成器;还有软件包natural。标记后,node-kmeans可用于标记数据集。从这一步开始,可以使用第一种方法。

另一种方法可能是使用标记化的句子来训练模型。但由于所有句子的形状都不相同,因此需要使用tf.pad

添加填充