【问题标题】:In Spark, how to do One Hot Encoding for top N frequent values only?在 Spark 中,如何只对前 N 个频繁值进行一次热编码?
【发布时间】:2020-05-30 19:59:48
【问题描述】:

让,在我的数据框 df 中,我有一个列 my_category,其中我有不同的值,我可以使用以下方法查看值计数:

df.groupBy("my_category").count().show()

value   count
a    197
b    166
c    210
d      5
e      2
f      9
g      3

现在,我想在此列上应用 One Hot Encoding (OHE),但仅针对顶部的 N 频繁值(例如 N = 3),并将所有其余不频繁值放在一个虚拟列中(说,“默认”)。例如,输出应该是这样的:

a  b  c  default
0  0  1  0
1  0  0  0
0  1  0  0
1  0  0  0
...
0  0  0  1
0  0  0  1
...

如何在 Spark/Scala 中执行此操作?

注意: 我知道如何在 Python 中做到这一点,例如,首先为每个唯一值构建一个基于频繁的字典,然后通过逐个检查值来创建 OHE 向量,将不频繁的值放在“默认”列中。

【问题讨论】:

    标签: scala apache-spark apache-spark-sql one-hot-encoding


    【解决方案1】:

    自定义函数可以写成,在特定列上应用一个热编码 (OHE),仅用于前 N 个频繁值(比如 N = 3)。

    它与Python比较相似,1)构建一个基于top n频繁的Dataframe/Dictionary。 2)旋转前 n 个频繁的 Dataframe,即创建 OHE 向量。 3)左连接给定的Dataframe和pivot Dataframe,用0替换null,即默认的OHE向量。

    import org.apache.spark.sql.DataFrame
    import org.apache.spark.sql.functions.{col, lit, when}
    import org.apache.spark.sql.Column
    
    import spark.implicits._
    val df = spark
      .sparkContext
      .parallelize(Seq("a", "b", "c", "a", "b", "c", "d", "e", "a", "b", "f", "a", "g", "a", "b", "c", "a", "d", "e", "f", "a", "b", "g", "b", "c", "f", "a", "b", "c"))
      .toDF("value")
    
    val oheEncodedDF = oheEncoding(df, "value", 3)
    
    
    def oheEncoding(df: DataFrame, colName: String, n: Int): DataFrame = {
      df.createOrReplaceTempView("data")
      val topNDF = spark.sql(s"select $colName, count(*) as count from data group by $colName order by count desc limit $n")
    
      val pivotTopNDF = topNDF
        .groupBy(colName)
        .pivot(colName)
        .count()
        .withColumn("default", lit(1))
    
      val joinedTopNDF = df.join(pivotTopNDF, Seq(colName), "left").drop(colName)
    
      val oheEncodedDF = joinedTopNDF
        .na.fill(0, joinedTopNDF.columns)
        .withColumn("default", flip(col("default")))
    
       oheEncodedDF
    }
    
    def flip(col: Column): Column = when(col === 1, lit(0)).otherwise(lit(1))
    

    【讨论】:

    • 以下相关问题:
    • 我有 n 列应用常规 OHE,然后使用 VectorAssembler,如:val s1 = new StringIndexer()... // n such sIndexers val fE = new OneHotEncoderEstimator().setInputCols(Array(s1.getOutputCol), ...).setOutputCols(Array("enc_s1", ... )) val vE = new VectorAssembler().setInputCols(fE.getOutputCols)... 现在,如何扩展 OHE TopN() 作为我管道的一部分?我想要的 oheEncodingTopN() 不能引用“实际”数据帧,因为它将是管道的一部分(适用于训练/测试)。扩展原来的 OneHotEncoderEstimator.scala?还有其他选择吗?
    • @YaleBD 我不确定你到底想做什么,但是有可能以某种方式调用 oheEncodingTopN()。
    • 我明白...基本上我正在尝试构建一个vectorAssembler,以便它可以从您的自定义OneHotEncoder 获取输出。我想要的 oheEncodingTopN() 不能引用“实际”数据帧(因为它是在您的函数中),因为它将是管道的一部分(应用于 trainData/testData)。因此,我正在寻找一种解决方案,它应该在我的管道中作为单独的阶段工作,而不是直接对数据进行操作的函数。我试着在这里解释一下:stackoverflow.com/questions/60423784/…
    • @YaleBD 哦,现在我可以联系了,我会看看。
    猜你喜欢
    • 2017-06-08
    • 2017-11-15
    • 2022-09-27
    • 2020-11-14
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 2018-07-16
    • 2021-02-10
    相关资源
    最近更新 更多