如何将 Spark 数据帧行拆分为列?

时间:2021-01-02 09:18:08

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

我有一个 Pyspark 数据框,我想根据给定列的唯一值将其行拆分为列,并与另一列的值连接。出于说明目的,让我使用以下示例,其中我的原始数据框是 df

df.show()
+-----+-----+
| col1| col2|
+-----+-----+
|   z1|   a1|
|   z1|   b2|
|   z1|   c3|
|   x1|   a1|
|   x1|   b2|
|   x1|   c3|
+-----+-----+

我想做的是拆分 col1唯一 值,从而通过加入col3。我所追求的结果数据框如下所示:

col2

此说明性示例仅包含 +-----+-----+-----+ | col1| col2| col3| +-----+-----+-----+ | z1| a1| x1 | | z1| b2| x1 | | z1| c3| x1 | +-----+-----+-----+ 中的两个唯一值(即 col1z1)。理想情况下,我想编写一段代码来自动检测 x1 中的唯一值,从而生成一个新的对应列。有谁知道我可以从哪里开始?

编辑col1z1 最终分别位于 x1col1 中是任意的。这绝对可能是相反的,因为我只是对按唯一值进行拆分感兴趣。

非常感谢,

马里奥安萨斯

2 个答案:

答案 0 :(得分:2)

我认为您正在尝试按 col2 分组并收集一组不同的 col1 值。

import pyspark.sql.functions as F

df2 = df.groupBy('col2').agg(F.collect_set('col1').alias('col'))
df3 = df2.select(
    'col2',
    *[F.col('col')[i] for i in range(df2.select(F.max(F.size('col'))).head()[0])]
)

df3.show()
+----+------+------+
|col2|col[0]|col[1]|
+----+------+------+
|  b2|    z1|    x1|
|  a1|    z1|    x1|
|  c3|    z1|    x1|
+----+------+------+

然后您可以根据需要重新排列/重命名列。

我不清楚为什么 z1 应该在您的问题中加入 col1x1 中的 col3。它很可能是相反的 - 无法从您的逻辑中看出。

答案 1 :(得分:1)

您可以join使用两个条件和dropDuplicates

df.alias('left').join(
    df.alias('right'),
    on = [
          F.col('left.col2') == F.col('right.col2'),
          F.col('left.col1') != F.col('right.col1')
          ]
).dropDuplicates(['col2']).show()

输出:

+----+----+----+----+
|col1|col2|col1|col2|
+----+----+----+----+
|  x1|  b2|  z1|  b2|
|  x1|  a1|  z1|  a1|
|  x1|  c3|  z1|  c3|
+----+----+----+----+

然后您可以drop并重命名列:

df.alias('left').join(
    df.alias('right'),
    on = [
          F.col('left.col2') == F.col('right.col2'),
          F.col('left.col1') != F.col('right.col1')
          ]
).dropDuplicates(['col2'])\
.drop(F.col('right.col2'))\
.select(
    F.col('right.col1'), F.col('col2'), F.col('left.col1').alias('col3')
).show()

输出:

+----+----+----+
|col1|col2|col3|
+----+----+----+
|  z1|  b2|  x1|
|  z1|  a1|  x1|
|  z1|  c3|  x1|
+----+----+----+

您也可以使用 SQL:

df.createOrReplaceTempView('df')

spark.sql(
    """
    SELECT
      l.col1 AS col1,
      l.col2 AS col2,
      r.col1 AS col3 
    FROM df AS l
    INNER JOIN df AS r
    ON l.col2 = r.col2
    AND l.col1 <> r.col1
    """
).dropDuplicates(['col2']).show()

输出:

+----+----+----+
|col1|col2|col3|
+----+----+----+
|  z1|  b2|  x1|
|  z1|  a1|  x1|
|  z1|  c3|  x1|
+----+----+----+