scala - 如何在 Spark 中创建一组 ngram?

标签 scala apache-spark

我正在使用 Scala 从 Spark 2.2 数据框列中提取 Ngram,因此(本例中为 trigrams):

val ngram = new NGram().setN(3).setInputCol("incol").setOutputCol("outcol")

如何创建一个包含所有 1 到 5 克的输出列?所以它可能是这样的:

val ngram = new NGram().setN(1:5).setInputCol("incol").setOutputCol("outcol")

但这行不通。 我可以遍历 N 并为 N 的每个值创建新的数据帧,但这似乎效率低下。任何人都可以指出我正确的方向,因为我的 Scala 很笨拙吗?

最佳答案

如果你想将它们组合成向量,你可以重写 Python answer通过 zero323 .

import org.apache.spark.ml.feature._
import org.apache.spark.ml.Pipeline

def buildNgrams(inputCol: String = "tokens", 
                 outputCol: String = "features", n: Int = 3) = {

  val ngrams = (1 to n).map(i =>
      new NGram().setN(i)
        .setInputCol(inputCol).setOutputCol(s"${i}_grams")
  )

  val vectorizers = (1 to n).map(i =>
     new CountVectorizer()
      .setInputCol(s"${i}_grams")
      .setOutputCol(s"${i}_counts")
  )

  val assembler = new VectorAssembler()
    .setInputCols(vectorizers.map(_.getOutputCol).toArray)
    .setOutputCol(outputCol)

  new Pipeline().setStages((ngrams ++ vectorizers :+ assembler).toArray)

}

val df = Seq((1, Seq("a", "b", "c", "d"))).toDF("id", "tokens")

结果

buildNgrams().fit(df).transform(df).show(1, false)
// +---+------------+------------+---------------+--------------+-------------------------------+-------------------------+-------------------+-------------------------------------+
// |id |tokens      |1_grams     |2_grams        |3_grams       |1_counts                       |2_counts                 |3_counts           |features                             |
// +---+------------+------------+---------------+--------------+-------------------------------+-------------------------+-------------------+-------------------------------------+
// |1  |[a, b, c, d]|[a, b, c, d]|[a b, b c, c d]|[a b c, b c d]|(4,[0,1,2,3],[1.0,1.0,1.0,1.0])|(3,[0,1,2],[1.0,1.0,1.0])|(2,[0,1],[1.0,1.0])|[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]|
// +---+------------+------------+---------------+--------------+-------------------------------+-------------------------+-------------------+-------------------------------------+

使用 UDF 可以更简单:

val ngram = udf((xs: Seq[String], n: Int) => 
  (1 to n).map(i => xs.sliding(i).filter(_.size == i).map(_.mkString(" "))).flatten)

spark.udf.register("ngram", ngram)

val ngramer =  new SQLTransformer().setStatement(
  """SELECT *, ngram(tokens, 3) AS ngrams FROM __THIS__"""
)

ngramer.transform(df).show(false)
// +---+------------+----------------------------------+
// |id |tokens      |ngrams                            |
// +---+------------+----------------------------------+
// |1  |[a, b, c, d]|[a, b, c, d, ab, bc, cd, abc, bcd]|
// +---+------------+----------------------------------+

关于scala - 如何在 Spark 中创建一组 ngram?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48461076/

相关文章:

apache-spark - Spark 2.0如何处理列可为空性?

java - SPARK 驱动程序在读取多个 S3 文件时内存不足

scala - 在类构造函数中使用特征方法

在平面映射 AnyRef* 后,Scala 无法解析正确的重载 SLF4J 方法

scala - Apache Spark K-Means 集群 - 用于输入的 RDD

scala - 为什么 Scala 的 Traversable 有两个类型略有不同的 copyToArray 方法?

scala - collect_list() 是否保持行的相对顺序?

apache-spark - Spark worker 上缺少 SLF4J 记录器

scala - Scala 中的 Spark : How to avoid linear scan for searching a key in each partition?

Scala 构造函数