当前位置: 首页 > 知识库问答 >
问题:

spark规范化数组的数据帧

鲁博雅
2023-03-14

如何规范化主要由嵌套数组组成的 spark 数据帧?

case class FooBar(id:String, foo:Seq[String], bar:String, baz: Seq[String])
val f = Seq(FooBar("thinga", Seq("1 "), "1 2 3 ", Seq("2 ")),
    FooBar("thinga", Seq("1 2 3 4 "), " 0 0 0 ", Seq("2 3 4 5 ")),
    FooBar("thingb", Seq("1 2 "), "1 2 3 4 5 ", Seq("1 2 ")),
    FooBar("thingb", Seq("0 ", "0 ", "0 "), "1 2 3 4 5 ", Seq("1 2 3 "))).toDS
f.printSchema
f.show(false)
+------+------------+----------+----------+
|    id|         foo|       bar|       baz|
+------+------------+----------+----------+
|thinga|        [1 ]|    1 2 3 |      [2 ]|
|thinga|  [1 2 3 4 ]|    0 0 0 |[2 3 4 5 ]|
|thingb|      [1 2 ]|1 2 3 4 5 |    [1 2 ]|
|thingb|[0 , 0 , 0 ]|1 2 3 4 5 |  [1 2 3 ]|
+------+------------+----------+----------+


scala> f.printSchema
root
 |-- id: string (nullable = true)
 |-- foo: array (nullable = true)
 |    |-- element: string (containsNull = true)
 |-- bar: string (nullable = true)
 |-- baz: array (nullable = true)
 |    |-- element: string (containsNull = true)

我想要类似emple的东西,它将保留(id,foo,bar,baz)的模式,但为数组的每个值返回一个单独的记录。最终结果不应再包含数组。

Foo和baz是相关的。它们的顺序不得扭曲。它们总是具有相同的长度,foo的第一个值与baz的第一个数值相关,以此类推。也许我应该先将它们组合成一个列/结构?

最终结果应如下所示:

+------+------------+----------+----------+
|    id|         foo|       bar|       baz|
+------+------------+----------+----------+
|thinga|        1   |    1     |      2   |
|thinga|        1   |      2   |      2   |
|thinga|        1   |        3 |      2   |    
|thinga|  1         |    0     |2         |
|thinga|  2         |    0     |3         |
|thinga|  3         |    0     |4         |
|thinga|  4         |    0     |5         |
|thinga|  1         |    0     |2         |
|thinga|  2         |    0     |3         |
|thinga|  3         |    0     |4         |
|thinga|  4         |    0     |5         |

|thinga|  1         |    0     |2         |
|thinga|  2         |    0     |3         |
|thinga|  3         |    0     |4         |
|thinga|  4         |    0     |5         |

....

|thingb|0           |1         |       1  |
|thingb|0           |2         |       2  |
|thingb|0           |3         |       3  |
|thingb|0           |4         |       1  |
|thingb|0           |5         |       2  |
|thingb|0           |1         |       3  |
|thingb|0           |2         |       1  |
|thingb|0           |3         |       2  |
|thingb|0           |4         |       3  |
|thingb|0           |5         |       1  |
|thingb|0           |1         |       2  |
|thingb|0           |2         |       3  |
|thingb|0           |3         |       1  |
|thingb|0           |4         |       2  |
|thingb|0           |5         |       3  |
+------+------------+----------+----------+

部分相关问题-爆炸(转置?)Spark SQL表中的多列

共有1个答案

岳志义
2023-03-14

根据我们的讨论(请检查初始帖子下的评论),以下数据应有效:

+------+-------+---------+-------+
|    id|    foo|      bar|    baz|
+------+-------+---------+-------+
|thinga|      1|    1 2 3|      2|
|thinga|1 2 3 4|    0 0 0|2 3 4 5|
|thingb|    1 2|1 2 3 4 5|    1 2|
|thingb|  0 0 0|1 2 3 4 5|  1 2 3|
+------+-------+---------+-------+

则初始化代码如下:

case class FooBar(id:String, foo:String, bar:String, baz: String)
val f = Seq(FooBar("thinga", "1", "1 2 3", "2"),
  FooBar("thinga", "1 2 3 4", "0 0 0", "2 3 4 5"),
  FooBar("thingb", "1 2", "1 2 3 4 5", "1 2"),
  FooBar("thingb", "0 0 0", "1 2 3 4 5", "1 2 3")).toDS()

如果是这种情况,那么这段代码应该会产生预期的结果:

f
  .withColumn("foo", split($"foo", " "))
  .withColumn("baz", split($"baz", " "))
  .withColumn("bar", explode(split($"bar", " ")))
  .map { case Row(id: String, foo: Seq[String], bar: String, baz: Seq[String]) =>
    val c = for ((f, b) <- foo.zip(baz)) yield {
      (f, b)
    }
    (id, bar, c)
  }.toDF(cols: _*)
  .withColumn("foo+baz", explode($"foo+baz"))
  .withColumn("foo", $"foo+baz._1")
  .withColumn("baz", $"foo+baz._2")
  .drop($"foo+bar")
  .select("id", "foo", "bar", "baz")
  .show(100)

前两个转换将拆分分隔的列 foo 和 baz 的空间。由于列栏是字符串,我们需要将其转换为具有拆分的数组,然后分解它。地图将返回一个元组 (id, 柱, c),其中 c 是元组序列 (foo, bar)。映射后,我们得到下一个输出:

+------+---+--------------------+
|    id|bar|             foo+baz|
+------+---+--------------------+
|thinga|  1|             [[1,2]]|
|thinga|  2|             [[1,2]]|
|thinga|  3|             [[1,2]]|
|thinga|  0|[[1,2], [2,3], [3...|
|thinga|  0|[[1,2], [2,3], [3...|
|thinga|  0|[[1,2], [2,3], [3...|
|thingb|  1|      [[1,1], [2,2]]|
|thingb|  2|      [[1,1], [2,2]]|
|thingb|  3|      [[1,1], [2,2]]|
|thingb|  4|      [[1,1], [2,2]]|
|thingb|  5|      [[1,1], [2,2]]|
|thingb|  1|[[0,1], [0,2], [0...|
|thingb|  2|[[0,1], [0,2], [0...|
|thingb|  3|[[0,1], [0,2], [0...|
|thingb|  4|[[0,1], [0,2], [0...|
|thingb|  5|[[0,1], [0,2], [0...|
+------+---+--------------------+

接下来,我们用“foo-baz”再进行一次分解,这次提取最终的元组。现在,输出如下所示:

+------+---+-------+
|    id|bar|foo+baz|
+------+---+-------+
|thinga|  1|  [1,2]|
|thinga|  2|  [1,2]|
|thinga|  3|  [1,2]|
|thinga|  0|  [1,2]|
|thinga|  0|  [2,3]|
|thinga|  0|  [3,4]|
|thinga|  0|  [4,5]|
|thinga|  0|  [1,2]|
.....
|thingb|  1|  [0,2]|
|thingb|  1|  [0,3]|
|thingb|  2|  [0,1]|
|thingb|  2|  [0,2]|
|thingb|  2|  [0,3]|
|thingb|  3|  [0,1]|
|thingb|  3|  [0,2]|
|thingb|  3|  [0,3]|
|thingb|  4|  [0,1]|
|thingb|  4|  [0,2]|
|thingb|  4|  [0,3]|
|thingb|  5|  [0,1]|
|thingb|  5|  [0,2]|
|thingb|  5|  [0,3]|
+------+---+-------+ 

最后,我们从foo baz填充foo和baz列。_1和foo baz。_2分别。这将是最终输出:

+------+---+---+---+
|    id|foo|bar|baz|
+------+---+---+---+
|thinga|  1|  1|  2|
|thinga|  1|  2|  2|
|thinga|  1|  3|  2|
|thinga|  1|  0|  2|
|thinga|  2|  0|  3|
|thinga|  3|  0|  4|
|thinga|  4|  0|  5|
|thinga|  1|  0|  2|
|thinga|  2|  0|  3|
|thinga|  3|  0|  4|
|thinga|  4|  0|  5|
|thinga|  1|  0|  2|
|thinga|  2|  0|  3|
|thinga|  3|  0|  4|
|thinga|  4|  0|  5|
|thingb|  1|  1|  1|
|thingb|  2|  1|  2|
|thingb|  1|  2|  1|
|thingb|  2|  2|  2|
|thingb|  1|  3|  1|
|thingb|  2|  3|  2|
|thingb|  1|  4|  1|
|thingb|  2|  4|  2|
|thingb|  1|  5|  1|
|thingb|  2|  5|  2|
|thingb|  0|  1|  1|
|thingb|  0|  1|  2|
|thingb|  0|  1|  3|
|thingb|  0|  2|  1|
|thingb|  0|  2|  2|
|thingb|  0|  2|  3|
|thingb|  0|  3|  1|
|thingb|  0|  3|  2|
|thingb|  0|  3|  3|
|thingb|  0|  4|  1|
|thingb|  0|  4|  2|
|thingb|  0|  4|  3|
|thingb|  0|  5|  1|
|thingb|  0|  5|  2|
|thingb|  0|  5|  3|
+------+---+---+---+  
 类似资料:
  • 我有一个数据框,如图所示: 我必须将数据框的关闭列规范化如下: > 对于每个符号,我们必须将随后几天的收盘价除以第一个收盘价。这意味着2020年11月24日APLO的正常化关闭时间将计算为: 标准化收盘价=(2020年11月24日收盘)/(2020年11月23日收盘)=0.9915(仅适用于APLO) 现在,如果符号改变,方法保持不变,只有上述公式中的值改变。因此,对于AUBANK而言,2020年

  • 我有一个包含2171列和200行的df。我想标准化这些COL的范围。 [输入df] [如果代码仅用于一个列,我不确定如何应用于一系列列] 我对python非常陌生,我不知道为什么它会给我以下错误:

  • 我阅读了cassandra数据建模,除了非规范化数据可能会发生变化之外,一切都很清楚。我如何同步它?当用户电子邮件更改时,更新的方法是什么: < code>groupname是组的一部分,数据模型中的用户可能不知道任何组,因此在用户更改后无法更新电子邮件。 下面描述的解决方案是否合适? 向用户模型中添加一列(类型

  • 问题内容: 我想知道是否有人对如何规范化数据库有任何建议。现在,我不是要设计结构,而是要实际将数据库数据从旧结构移动到新的规范化结构。我知道我可以编写类似PHP脚本的内容,但是我想知道是否有一种方法可以在SQL中进行。特别是MySQL。 **编辑:有人尝试过SwisSQL吗?这是一个迁移工具,但我不确定它是否能满足我的要求。 问题答案: 这是在脚本中标准化表的示例。我建议你做这样的事情 您将首先创

  • 表规范 命名统一小写下划线 非CMF核心应用,统一带应用表前缀,如portal_ 插件表,统一带插件表前缀,如:demo_ 表默认编码utf8mb4,默认排序规则utf8mb4_general_ci 引擎统一innodb 写表注释 字段规范 命名统一小写下划线 非自增主键一定要写字段注释 数据类型尽量用数字类型,数字类型的比字符类型的要快很多。 数据类型尽量小,这里的尽量小是指在满足可以预见的未来

  • 表规范 命名统一小写下划线 非CMF核心应用,统一带应用表前缀,如portal_ 插件表,统一带插件表前缀,如:plugindemo 表默认编码utf8mb4,默认排序规则utf8mb4_general_ci 引擎统一innodb 写表注释 字段规范 命名统一小写下划线 非自增主键一定要写字段注释 数据类型尽量用数字类型,数字类型的比字符类型的要快很多。 数据类型尽量小,这里的尽量小是指在满足可以