【问题标题】:Spark: StringIndexer on sentencesSpark:句子上的字符串索引器
【发布时间】:2018-05-20 22:32:57
【问题描述】:

我正在尝试对一列句子执行 StringIndexer,即将单词列表转换为整数列表。

例如:

输入数据集

  (1, ["I", "like", "Spark"])
  (2, ["I", "hate", "Spark"])

我预计 StringIndexer 之后的输出是这样的:

  (1, [0, 2, 1])
  (2, [0, 3, 1])

理想情况下,我想将这种转换作为 Pipeline 的一部分,以便我可以将耦合转换器链接在一起并序列化以进行在线服务。

这是 Spark 原生支持的吗?

谢谢!

【问题讨论】:

    标签: java scala apache-spark machine-learning apache-spark-mllib


    【解决方案1】:

    用于将文本转换为特征的标准TransformersCountVectorizer

    CountVectorizer 和 CountVectorizerModel 旨在帮助将文本文档集合转换为令牌计数向量。

    HashingTF:

    使用散列技巧将一系列术语映射到它们的术语频率。目前我们使用 Austin Appleby 的 MurmurHash 3 算法(MurmurHash3_x86_32)来计算术语对象的哈希码值。由于使用简单的模将散列函数转换为列索引,因此建议使用 2 的幂作为 numFeatures 参数;否则特征将不会均匀地映射到列。

    两者都有binary 选项,可用于从计数切换到二进制向量。

    没有内置的 Transfomer 可以给出你想要的准确结果(它对 ML 算法没有用处)你可以购买 explode 应用 StringIndexercollect_list / collect_set

    import org.apache.spark.ml.feature._
    import org.apache.spark.ml.Pipeline
    
    
    val df = Seq(
      (1, Array("I", "like", "Spark")), (2, Array("I", "hate", "Spark"))
    ).toDF("id", "words")
    
    val pipeline = new Pipeline().setStages(Array(
      new SQLTransformer()
        .setStatement("SELECT id, explode(words) as word FROM __THIS__"),
      new StringIndexer().setInputCol("word").setOutputCol("index"),
      new SQLTransformer()
        .setStatement("""SELECT id, COLLECT_SET(index) AS values 
                         FROM __THIS__ GROUP BY id""")
    ))
    
    pipeline.fit(df).transform(df).show
    
    // +---+---------------+                      
    // | id|         values|
    // +---+---------------+
    // |  1|[0.0, 1.0, 3.0]|
    // |  2|[2.0, 0.0, 1.0]|
    // +---+---------------+
    

    使用CountVectorizerudf

    import org.apache.spark.ml.linalg._
    
    
    spark.udf.register("indices", (v: Vector) => v.toSparse.indices)
    
    val pipeline = new Pipeline().setStages(Array(
      new CountVectorizer().setInputCol("words").setOutputCol("vector"),
      new SQLTransformer()
        .setStatement("SELECT *, indices(vector) FROM __THIS__")
    ))
    
    pipeline.fit(df).transform(df).show
    
    // +---+----------------+--------------------+-------------------+
    // | id|           words|              vector|UDF:indices(vector)|
    // +---+----------------+--------------------+-------------------+
    // |  1|[I, like, Spark]|(4,[0,1,3],[1.0,1...|          [0, 1, 3]|
    // |  2|[I, hate, Spark]|(4,[0,1,2],[1.0,1...|          [0, 1, 2]|
    // +---+----------------+--------------------+-------------------+
    

    【讨论】:

    • 非常感谢您的详细解答。很好奇,为什么你说这对 ML 没用。我尝试这样做的原因是我正在转换 spark 中的数据,然后将转换后的数据输入到 Tensorflow 框架中进行训练。 TF 模型想要消耗“句子”进行 NLP 处理。
    • 通常机器学习工具需要一个固定大小的数据向量表示,你不能只传递索引列表。
    • 啊,也许我没有说出我的问题。当我说索引列表时,我的意思是索引数组。我试图解决的问题是,我需要将原始句子转换为固定大小的数字向量。如果句子的长度比大小长,我会剪掉它;另一方面,如果句子长度较短,我将使用默认值填充数组。那么如果是向量(而不是列表),您对数据预处理有更好的建议吗?
    • 不要填充 - 您的数据将是完整的。混合。使用 CountVectorizerHashingTF 并将输出 (SparseVector) 转换为您的代码可以使用的内容:)
    猜你喜欢
    • 2018-07-24
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多