将Spark数据框列转换为行

时间:2019-12-11 08:04:01

标签: scala apache-spark

我有一个这样的Spark数据框:

    +-----+-----+-------+--------+
    |  A  |B    |2017Q1 | 2017Q2 |
    +-----+----------------------+
    |  1  |  101|  0.6  |  0.8   |
    |  2  |  102|  0.7  |  0.9   |
    |  3  |  103|  0.9  |  0.4   |
    |  ...|  ...|  ...  |  ...   |

此处的年和季度列可以是动态的。 意味着我也可能会获得2017Q3、2017Q4等的专栏。 我想将2017Q12017Q2的列值转换为行,如下所示:

+-----+-----+-------+--------+----+
|  A  |B    |Year   | Quarter|Val |
+-----+----------------------+----+
|  1  |  101| 2017  |  1     |0.6 |
|  1  |  101| 2017  |  2     |0.8 |
|  2  |  102| 2017  |  1     |0.7 |
|  ...|  ...|  ...  |  ...   |.   |

有人可以帮我这个忙吗?我正在使用Spark 2.4.4

1 个答案:

答案 0 :(得分:2)

在Spark SQL中,您可以创建一个包含两个季度值的数组。由于您需要记住哪个值对应于哪个四分之一,因此可以创建一个结构以将四分之一的索引与其值绑定。要使其动态,可以使用四分之一的列表。为了使其更加通用,我们可以按如下所示从数据框的列名称中提取四分之一。

val quarters = df.columns
    .filter( _.matches("[0-9]{4}Q[1-4]") ) // all the columns matching the regex
    .sorted

df.withColumn("value", explode(array(
       quarters.indices.map(i =>
            struct(lit(i+1) as "val", col(quarters(i)) as "quarter")
       ) : _*
  )))
  .withColumn("Quarter", $"value.quarter")
  .withColumn("Val", $"value.val")
  .drop( quarters :+ "value" : _*)