【问题标题】:How to explode multiple columns of a dataframe in pyspark如何在pyspark中分解数据框的多列
【发布时间】:2018-12-07 12:41:14
【问题描述】:

我有一个数据框,其中包含类似于以下列的列表。所有列中列表的长度都不相同。

Name  Age  Subjects                  Grades
[Bob] [16] [Maths,Physics,Chemistry] [A,B,C]

我想以得到以下输出的方式分解数据框-

Name Age Subjects Grades
Bob  16   Maths     A
Bob  16  Physics    B
Bob  16  Chemistry  C

我怎样才能做到这一点?

【问题讨论】:

  • 您想将给定数组中的索引与行中的其他数组匹配吗?就像Maths -> A、Physics -> B 和Chemistry -> C 一样。所以像Maths -> B 这样的东西是错误的。
  • 是的@Tanjin 那是错误的

标签: python dataframe pyspark


【解决方案1】:

PySpark 在 2.4 中添加了一个 arrays_zip 函数,从而无需 Python UDF 来压缩数组。

import pyspark.sql.functions as F
from pyspark.sql.types import *

df = sql.createDataFrame(
    [(['Bob'], [16], ['Maths','Physics','Chemistry'], ['A','B','C'])],
    ['Name','Age','Subjects', 'Grades'])
df = df.withColumn("new", F.arrays_zip("Subjects", "Grades"))\
       .withColumn("new", F.explode("new"))\
       .select("Name", "Age", F.col("new.Subjects").alias("Subjects"), F.col("new.Grades").alias("Grades"))
df.show()

+-----+----+---------+------+
| Name| Age| Subjects|Grades|
+-----+----+---------+------+
|[Bob]|[16]|    Maths|     A|
|[Bob]|[16]|  Physics|     B|
|[Bob]|[16]|Chemistry|     C|
+-----+----+---------+------+
【解决方案2】:

这行得通,

import pyspark.sql.functions as F
from pyspark.sql.types import *

df = sql.createDataFrame(
    [(['Bob'], [16], ['Maths','Physics','Chemistry'], ['A','B','C'])],
    ['Name','Age','Subjects', 'Grades'])
df.show()

+-----+----+--------------------+---------+
| Name| Age|            Subjects|   Grades|
+-----+----+--------------------+---------+
|[Bob]|[16]|[Maths, Physics, ...|[A, B, C]|
+-----+----+--------------------+---------+

将udf 与zip 一起使用。 explode 需要的那些列必须在爆炸前合并。

combine = F.udf(lambda x, y: list(zip(x, y)),
              ArrayType(StructType([StructField("subs", StringType()),
                                    StructField("grades", StringType())])))

df = df.withColumn("new", combine("Subjects", "Grades"))\
       .withColumn("new", F.explode("new"))\
       .select("Name", "Age", F.col("new.subs").alias("Subjects"), F.col("new.grades").alias("Grades"))
df.show()


+-----+----+---------+------+
| Name| Age| Subjects|Grades|
+-----+----+---------+------+
|[Bob]|[16]|    Maths|     A|
|[Bob]|[16]|  Physics|     B|
|[Bob]|[16]|Chemistry|     C|
+-----+----+---------+------+

【讨论】:

  • 如果我需要将 A B 和 C 放在不同的列而不是行中该怎么办
【解决方案3】:

你试过了吗

df.select(explode(split(col("Subjects"))).alias("Subjects")).show()

您可以将数据框转换为 RDD。

对于 RDD,您可以使用 flatMap 函数来分隔主题。

【讨论】:

  • 我尝试使用平面地图作为 df.rdd.flatMap(lambda x: zip(*[x[c] for c in dcols])).toDF(dcols) 但它只是给我第一行并忽略其余行- |16 |A |Bob |Maths |
猜你喜欢
  • 2020-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多