Tom*_*ski 5 algorithm nlp hierarchical-clustering k-means tensorflow.js
我想通过它们的字符串键值 ( description)之一对 Javascript 对象进行聚类。我已经尝试了多种解决方案,并希望获得有关如何解决问题的一些指导。
我想要什么:假设我有一个对象数据库。可能有很多(可能有数千个,也可能有数万个)。我需要能够:
categoryId每一个分配一些(代表它们所属的集群)。我还没有尝试解决问题 #2,但这是我尝试解决问题 #1 的方法。
具有 Levenshtein 距离(单链接)的层次聚类- 这里的问题是性能,结果令人满意(我使用了hierarchical-clustering来自 的库npm)但在 150 左右我将不得不等待大约一分钟。不会为数千人工作。
TF-IDF,矢量化 + k-means - 性能很棒。它将轻松通过 5000 个对象。但结果肯定是关闭的(可能是我的实现中的一个错误)。我使用(natural库 fromnpm来计算 TF-IDF 和node-kmeans)。
Bag-of-Words + k-means - 我现在正在尝试实现这个,还没有任何运气。
对于#2,我想过使用朴素贝叶斯(但我还没有尝试过)。
有什么建议?如果对象只是聚集在一起就好了。如果我可以提取组聚类所依据的标签(如从 TF-IDF 中提取),那就更好了。
使用张量流,可以创建深度学习模型,该模型经过训练后可以用于预测传入单词的类别。
我们假设这是数据集:
let data = [{description: 'just something', label: '1'}, {description: 'something else', label: '2'}]
Run Code Online (Sandbox Code Playgroud)
文本分类要做的第一件事是将文本编码为张量。可以使用许多算法,只要它们能够在给定感兴趣的领域中提供良好的准确性。特别是,通用句子编码器会将每个句子转换为大小为 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
Run Code Online (Sandbox Code Playgroud)
第二件事是创建分类模型。尽管可以使用 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
Run Code Online (Sandbox Code Playgroud)
inputShape[n, 512]用于指示模型将一次输入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)
}
}
})
Run Code Online (Sandbox Code Playgroud)
模型训练完成后,对于每个传入的单词,都会有一个预测。但是传入的单词需要首先转换为如上所述的张量。
let prediction = model.predict( await useModel.embed('newWord').reshape([1, 1, -1])).argMax([-1])
prediction.print() // will print the index of the label
Run Code Online (Sandbox Code Playgroud)
如果训练数据尚未标记(意味着该对象不具有标签属性),则应对数据进行聚类。tensorflow.js 中还没有聚类算法。对于文本聚类,我们首先需要创建标记。use包有一个分词器;还有包裹natural。标记化后,node-kmeans可用于标记数据集。从这一步开始,就可以使用第一种方法了。
另一种方法可能是使用标记化的句子来训练模型。但由于所有的句子不具有相同的形状,因此需要使用添加填充tf.pad