【问题标题】:SPARK : Set a column value based on multiple row conditionsSPARK :根据多行条件设置列值
【发布时间】:2019-01-07 03:28:52
【问题描述】:

我有以下格式的数据框:

+----+---+-----+------+-----+------+
|AGEF|SEX|F0_34|F35_44|M0_34|M35_44|
+----+---+-----+------+-----+------+
|  30|  0|    0|     0|    0|     0|
|  94|  1|    0|     0|    0|     0|
|  94|  0|    0|     0|    0|     0|
|  94|  0|    0|     0|    0|     0|
|  94|  1|    0|     0|    0|     0|
|  44|  0|    0|     0|    0|     0|
|  66|  0|    0|     0|    0|     0|
|  66|  0|    0|     0|    0|     0|
|  74|  0|    0|     0|    0|     0|
|  74|  0|    0|     0|    0|     0|
|  29|  0|    0|     0|    0|     0|

现在基于 AGEF 和 SEX 列的值,我需要将 1 分配给相应的列名。每个列名都是不言自明的,比如 F0_34 是 0 到 34 岁之间的女性,其他情况类似。

预期输出是

+----+---+-----+------+-----+------+
|AGEF|SEX|F0_34|F35_44|M0_34|M35_44|
+----+---+-----+------+-----+------+
|  30|  0|    1|     0|    0|     0|
|  94|  1|    0|     0|    0|     0|
|  94|  0|    0|     0|    0|     0|
|  94|  0|    0|     0|    0|     0|
|  94|  1|    0|     0|    0|     0|
|  44|  0|    0|     1|    0|     0|
|  66|  0|    0|     0|    0|     0|
|  66|  0|    0|     0|    0|     0|
|  74|  0|    0|     0|    0|     0|
|  74|  0|    0|     0|    0|     0|
|  29|  0|    1|     0|    0|     0|

提前致谢!!!

【问题讨论】:

    标签: apache-spark dataframe apache-spark-sql


    【解决方案1】:

    通常最有效的方法是直接对 SQL 表达式进行操作。例如:

    def categorize(ageRanges: Seq[(Int, Int)], sexValues: Seq[(Int, String)]) = for {
      (ageL, ageH) <- ageRanges
      (sexV, sexL) <- sexValues
    } yield ($"SEX" === sexL && $"AGEF".between(ageL, ageH)).alias(
      s"$sexL-$ageL-$ageH"
    )
    
    df.select(
      $"*" +: categorize(Seq((0, 34), (35, 44)), Seq((0, "F"), (1, "M"))): _*
    )
    

    【讨论】:

      【解决方案2】:

      最简单的方法是制作一个带有 5 个参数(例如:actual_age、actual_sex、target_sex、target_min_age、target_max_age)并返回 1 或 0 的 UDF。如下所示:

      val ageRanger = udf[Int,Int,Int,Int,Int,Int]((age: Int, sex: Int, targetSex: Int, targetMinAge: Int, targetMaxAge: Int) => { 
        if (age >= targetMinAge && age <= targetMaxAge && sex == targetSex) 1 else 0
      })
      

      如果你有这个DataFrame:

      val df = Seq((30,0),(94,1),(94,0),(44,0)).toDF("AGEF", "SEX")
      // +----+---+
      // |AGEF|SEX|
      // +----+---+
      // |  30|  0|
      // |  94|  1|
      // |  94|  0|
      // |  44|  0|
      // +----+---+
      
      df.withColumn("F0_34", ageRanger($"AGEF", $"SEX", lit(0), lit(0), lit(34)))
        .withColumn("F35_44", ageRanger($"AGEF", $"SEX", lit(0), lit(35), lit(44)))
        .show
      // +----+---+-----+------+
      // |AGEF|SEX|F0_34|F35_44|
      // +----+---+-----+------+
      // |  30|  0|    1|     0|
      // |  94|  1|    0|     0|
      // |  94|  0|    0|     0|
      // |  44|  0|    0|     1|
      // +----+---+-----+------+
      

      请注意,您必须将值作为Columns 传递到UDF,因此我使用lit(...) 将我的Int 值包装为硬编码值。可能有一种更巧妙的方法可以做到这一点,但这种方式效果很好。

      【讨论】:

        猜你喜欢
        • 2020-07-08
        • 1970-01-01
        • 2021-07-30
        • 2023-01-13
        • 1970-01-01
        • 2020-12-13
        • 2019-06-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多