【问题标题】:Checking if list of strings in a Scala Dataframe column is present in the value of a Map检查 Scala Dataframe 列中的字符串列表是否存在于 Map 的值中
【发布时间】:2022-06-30 09:21:24
【问题描述】:

我有以下数据:

val df = Seq(
    (1, List("A")),
    (2, List("A")), 
    (3, List("A", "B")),
    (4, List("C")),
    (5, List("A")),
    (6, List("A", "C")),
    (7, List("B")),
    (8, List("A", "B", "C")),
    (9, List("A"))
  ).toDF("Serial Number", "my_list")

+--------------------+--------------------+
|       Serial Number|             my_list|
+--------------------+--------------------+
|                   1|                 [A]|
|                   2|                 [A]|
|                   3|               [A,B]|
|                   4|                 [C]|
|                   5|                 [A]|
|                   6|              [A, C]|
|                   7|                 [B]|
|                   8|           [A, B, C]|
|                   9|                 [A]|
+--------------------+--------------------+

我有一张地图

val category_Mapping = Map("Category1" -> [A, B], 
                  "Category2" -> [C],
                  "Category3" -> [B, D])

我想在 data["my_list"] 中查找每个列表元素并为每个 data["Serial Number"] 返回一个输出映射,方法如下:

+--------------------+--------------------+------------------------------------------+
|       Serial Number|             my_list|                                   output |
+--------------------+--------------------+------------------------------------------+
|                   1|                 [A]|{Category1->1, Category2->0, Category3->0}|
|                   2|                 [A]|{Category1->1, Category2->0, Category3->0}|
|                   3|               [A,B]|{Category1->1, Category2->0, Category3->1}|
|                   4|                 [C]|{Category1->0, Category2->1, Category3->0}|
|                   5|                 [A]|{Category1->1, Category2->0, Category3->0}|
|                   6|              [A, C]|{Category1->1, Category2->1, Category3->0}|
|                   7|                 [B]|{Category1->1, Category2->0, Category3->1}|
|                   8|           [A, B, C]|{Category1->1, Category2->1, Category3->1}|
|                   9|                 [A]|{Category1->1, Category2->0, Category3->0}|
+--------------------+--------------------+------------------------------------------+

基本上,如果 data["my_list"] 中的列表中的元素存在于 category_Mapping 中,我想返回一个值为 1 的输出映射。反正我能做到吗?

【问题讨论】:

    标签: dataframe scala apache-spark


    【解决方案1】:

    你可以试试这个
    我是在 spark 本地模式下而不是在集群上这样做的

    // Assuming that your dataframe is stored in a variable called df
    
    // Define a function which will return your map based on the given array in the colum n 'my_list'
    
    def function(lst: mutable.WrappedArray[String]): Map[String, Int] = {
        var map: scala.collection.mutable.Map[String, Int] = scala.collection.mutable.Map("Category1" -> 0, "Category2" -> 0, "Category3" -> 0)
        lst.foreach { l =>
          map.keys.foreach { key =>
            if (Map("Category1" -> Array("A", "B"), "Category2" -> Array("C"), "Category3" -> Array("B", "D"))(key).contains(l))
                map(key) = 1
          }
        }
        map.toMap
    }
    
    // now you can define a udf which will just call the above defined function
    
    val output = udf { (lst: mutable.WrappedArray[String]) => {
        function(lst)
      }
    }
    
    // now you can call the udf on the column 'my_list'
    
    df.withColumn("output", output(col("my_list"))).show(false)
    
    // The output will be as given below
    
    +-------------+---------+------------------------------------------------+
    |Serial Number|my_list  |output                                          |
    +-------------+---------+------------------------------------------------+
    |1            |[A]      |[Category2 -> 0, Category1 -> 1, Category3 -> 0]|
    |2            |[A]      |[Category2 -> 0, Category1 -> 1, Category3 -> 0]|
    |3            |[A, B]   |[Category2 -> 0, Category1 -> 1, Category3 -> 1]|
    |4            |[C]      |[Category2 -> 1, Category1 -> 0, Category3 -> 0]|
    |5            |[A]      |[Category2 -> 0, Category1 -> 1, Category3 -> 0]|
    |6            |[A, C]   |[Category2 -> 1, Category1 -> 1, Category3 -> 0]|
    |7            |[B]      |[Category2 -> 0, Category1 -> 1, Category3 -> 1]|
    |8            |[A, B, C]|[Category2 -> 1, Category1 -> 1, Category3 -> 1]|
    |9            |[A]      |[Category2 -> 0, Category1 -> 1, Category3 -> 0]|
    +-------------+---------+------------------------------------------------+
    

    要根据 category_Mapping 在输出列中获取映射的键,我们可以将 category_Mapping 变量作为参数传递给 udf,并在函数中使用它来动态定义输出映射。可以这样做:

    val category_Mapping = Map("Category1" -> Array("A", "B"), "Category2" -> Array("C"), "Category3" -> Array("B", "D"))
    
    def function(lst: mutable.WrappedArray[String], category_Mapping: Map[String, Array[String]]): Map[String, Int] = {
        var map: scala.collection.mutable.Map[String, Int] = scala.collection.mutable.Map()
        lst.foreach { l =>
            category_Mapping.keys.foreach { key =>
            if(!map.contains(key))
                map(key) = 0
            if (category_Mapping(key).contains(l))
                map(key) = 1
            }
        }
        map.toMap
    }
    
    // the definition of udf has changed in this case.
    
    def output (category_Mapping: Map[String, Array[String]]) = udf { (lst: mutable.WrappedArray[String]) => {
        function(lst,category_Mapping)
    }
    }
    
    df.withColumn("output", output(category_Mapping)(col("my_list"))).show(false)
    

    【讨论】:

    • 我已更新问题以包含 df 的代码。是否可以将 Map 作为参数?由于它的键依赖于category_Mapping的键?
    • @IllustriousImp 是的,你肯定可以做到这一点。我在答案中添加了动态部分。请看一下
    猜你喜欢
    • 2013-08-01
    • 2019-10-03
    • 1970-01-01
    • 2021-10-18
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多