简而言之: 我试图基于一个现有的数据集(Seq[Words]
及其对应的类别)进行训练,并使用该训练后的数据集来根据类别相似性过滤另一个数据集。
我试图训练一个数据集,然后将其用于文本分析。我尝试过使用 NaiveBayes
,但它似乎只能处理现有数据,因此它的预测算法总会返回结果,即使它不匹配任何内容。
因此,我现在尝试使用 TFIDF,并将输出传递到 RowMatrix 中计算相似性。但是,我不确定如何运行我的查询(目前是一个词)。这是我尝试过的方法:
val rddOfTfidfFromCorpus : RDD[Vector]
val query = "word"
val tf = new HashingTF().transform(List(query))
val tfIDF = new IDF().fit(sc.makeRDD(List(tf))).transform(tf)
val mergedVectors = rddOfTfidfFromCorpus.union(sc.makeRDD(List(tfIDF)))
val similarities = new RowMatrix(mergedVectors).columnSimilarities(1.0)
我在这里卡住了(如果我之前的步骤都正确的话)。我尝试过滤 similarities
的 i
和 j
,以便只保留与我的查询 TFIDF 相关的部分,结果得到一个空集合。
总的来说,我想在一个数据集上进行训练,并找出它所属的类别。上面的代码至少试图将其缩小到一个类别,并检查我是否能从中得到一个预测……
*请注意,这是一个玩具示例,所以我只需要一个足够好的解决方案。我使用的是 Spark 1.4.0
回答:
在这里使用 columnSimilarities
是不合适的。因为矩阵中的每一列代表一组术语,你会得到一个标记之间相似性的矩阵,而不是文档。你可以转置矩阵然后使用 columnSimilarities
,但据我所知,你想要的是查询与语料库之间的相似性。你可以使用矩阵乘法来表达这一点,如下所示:
首先,你需要一个在语料库上训练的 IDFModel
。假设它被称为 idf
:
import org.apache.spark.mllib.feature.IDFModel
val idf: IDFModel = ??? // 使用语料库数据训练
以及一个小助手函数:
def toBlockMatrix(rdd: RDD[Vector]) = new IndexedRowMatrix(
rdd.zipWithIndex.map{case (v, i) => IndexedRow(i, v)}).toCoordinateMatrix.toBlockMatrix
首先让我们将查询转换为 RDD 并计算 TF:
val query: Seq[String] = ???
val queryTf = new HashingTF().transform(query)
接下来我们可以应用 IDF 模型并将结果转换为矩阵:
val queryTfidf = idf.transform(queryTf)
val queryMatrix = toBlockMatrix(queryTfidf)
我们也需要一个语料库矩阵:
val corpusMatrix = toBlockMatrix(rddOfTfidfFromCorpus)
如果你将两者相乘,我们会得到一个矩阵,其行数等于查询中的文档数,列数等于语料库中的文档数。
val dotProducts = queryMatrix.multiply(corpusMatrix.transpose)
为了得到正确的余弦相似性,你必须除以幅度的乘积,但如果你能处理这一点的话。
这里有两个问题。首先,这相当昂贵。其次,我不确定它是否真的有用。为了降低成本,你可以先应用某种降维算法,但我们现在先不考虑这一点。
从以下陈述来看
NaiveBayes (…) 似乎只能处理现有数据,因此它的预测算法总会返回结果,即使它不匹配任何内容。
我猜你想要某种无监督学习方法。你可以尝试最简单的方法,即 K-means:
import org.apache.spark.mllib.clustering.{KMeans, KMeansModel}
val numClusters: Int = ???
val numIterations = 20
val model = KMeans.train(rddOfTfidfFromCorpus, numClusters, numIterations)
val predictions = model.predict(queryTfidf)