我有一个具有一行和几列的数据框。一些列是单个值,另一些是列表。所有列表列的长度均相同。我想将每个列表列拆分为单独的行,同时将任何非列表列保持原样。样本DF:from pyspark import Rowfrom pyspark.sql import SQLContextfrom pyspark.sql.functions import explodesqlc = SQLContext(sc)df = sqlc.createDataFrame([Row(a=1, b=[1,2,3],c=[7,8,9], d='foo')])# +---+---------+---------+---+# | a| b| c| d|# +---+---------+---------+---+# | 1|[1, 2, 3]|[7, 8, 9]|foo|# +---+---------+---------+---+我想要的是:+---+---+----+------+| a| b| c | d |+---+---+----+------+| 1| 1| 7 | foo || 1| 2| 8 | foo || 1| 3| 9 | foo |+---+---+----+------+如果我只有一个列表列,只需执行以下操作即可轻松实现explode:df_exploded = df.withColumn('b', explode('b'))# >>> df_exploded.show()# +---+---+---------+---+# | a| b| c| d|# +---+---+---------+---+# | 1| 1|[7, 8, 9]|foo|# | 1| 2|[7, 8, 9]|foo|# | 1| 3|[7, 8, 9]|foo|# +---+---+---------+---+但是,如果我也尝试使用explode该c列,则会得到一个长度为我想要的平方的数据框:df_exploded_again = df_exploded.withColumn('c', explode('c'))# >>> df_exploded_again.show()# +---+---+---+---+# | a| b| c| d|# +---+---+---+---+# | 1| 1| 7|foo|# | 1| 1| 8|foo|# | 1| 1| 9|foo|# | 1| 2| 7|foo|# | 1| 2| 8|foo|# | 1| 2| 9|foo|# | 1| 3| 7|foo|# | 1| 3| 8|foo|# | 1| 3| 9|foo|# +---+---+---+---+我想要的是-对于每一列,采用该列中数组的第n个元素,并将其添加到新行中。我尝试过在数据框中的所有列之间映射爆炸,但是这似乎也不起作用:df_split = df.rdd.map(lambda col: df.withColumn(col, explode(col))).toDF()
3 回答
慕的地10843
TA贡献1785条经验 获得超8个赞
您需要使用flatMap,而不是map要在每个输入行中创建多个输出行。
from pyspark.sql import Row
def dualExplode(r):
rowDict = r.asDict()
bList = rowDict.pop('b')
cList = rowDict.pop('c')
for b,c in zip(bList, cList):
newDict = dict(rowDict)
newDict['b'] = b
newDict['c'] = c
yield Row(**newDict)
df_split = sqlContext.createDataFrame(df.rdd.flatMap(dualExplode))
FFIVE
TA贡献1797条经验 获得超6个赞
zip将obj的第一个元素与另一个对象的第一个元素,第2个和第2个元素等配对在一起,直到其中一个对象用完元素。您的情况是2个值之后。换句话说,它将配对元素,直到没有更多要配对的项目为止。要提出任何建议,我需要知道您希望程序如何处理未配对的元素(例如,您是否要从第二组中获取空值?)。同样,在此示例中只有1 df。如果你的问题是从这一不同,它可能会更好,只是问了另一个问题
添加回答
举报
0/150
提交
取消