Pyspark-转置多个数据框

时间:2018-11-07 14:17:08

标签: python apache-spark dataframe pyspark

我有多个看起来像这样的数据框。

df1:

+---------+---------+---------+
|sum(col1)|sum(col2)|sum(col3)|
+---------+---------+---------+
|       10|        1|        0|
+---------+---------+---------+

df2:

+---------+---------+
|sum(col1)|sum(col2)|
+---------+---------+
|       20|        6|
+---------+---------+

df3:

+---------+---------+---------+---------+
|sum(col1)|sum(col2)|sum(col3)|sum(col4)|
+---------+---------+---------+---------+
|        1|        5|        3|        4|
+---------+---------+---------+---------+

对于上面的示例,输出应如下所示。

+--------+------+------+------+
|col_name|value1|value2|value3|
+--------+------+------+------+
|    col1|    10|    20|     1|
|    col2|     1|     6|     5|
|    col3|     0|  null|     3|
|    col4|  null|  null|     4|
+--------+------+------+------+

我正在使用spark 1.6.3来做到这一点。在上面的示例中,我对特定表的总和计算不同,但是我有多个表来为每个表计算总和,并且输出应以上述格式合并。

关于如何实现此目标的任何想法?

2 个答案:

答案 0 :(得分:1)

这可能是在pyspark之外最容易做到的,并且如果要处理的数据足够小,那可能就是您应该做的,因为这样做是在pyspark上效率不高。

如果出于某种原因需要执行此操作,请使用pyspark,则可以通过几个数据框转换来执行此操作。我们需要做的第一件事是将所有单个数据帧转换为相同的架构,这将允许我们迭代地从每个数据帧中进行选择,然后合并为最终结果。以下是实现此目的的一种方法。

from pyspark.sql.functions import lit,col
from pyspark.sql.types import StructType, StructField, IntegerType, StringType

a = [[10,1,0]]
b = [[20,6]]
c = [[1,5,3,4]]

dfa = spark.createDataFrame(a,['col1','col2','col3'])
dfb = spark.createDataFrame(b,['col1','col2'])
dfc = spark.createDataFrame(c,['col1','col2','col3','col4'])

dfdict = {'dfa':dfa,'dfb':dfb,'dfc':dfc}
columns = set([col for dfname in dfdict for col in dfdict[dfname].columns])

for dfname in dfdict:
    for colname in columns-set(dfdict[dfname].columns):
        dfdict[dfname] = dfdict[dfname].withColumn(colname, lit(None).cast(StringType()))

schema = StructType([StructField("col_name", StringType(), True)]+\
                    [StructField("value_"+dfname, IntegerType(), True) for dfname in dfdict])
resultdf=spark.createDataFrame([],schema = schema)

for colname in columns:
    resultdf = resultdf\
                .union(dfdict['dfa'].select(lit(colname).alias('col_name'),
                       col(colname).alias('value_dfa'))\
                .crossJoin(dfdict['dfb'].select(col(colname).alias('value_dfb')))\
                .crossJoin(dfdict['dfc'].select(col(colname).alias('value_dfc'))))

resultdf.orderBy('col_name').show()

>>>

+--------+---------+---------+---------+
|col_name|value_dfa|value_dfb|value_dfc|
+--------+---------+---------+---------+
|    col1|       10|       20|        1|
|    col2|        1|        6|        5|
|    col3|        0|     null|        3|
|    col4|     null|     null|        4|
+--------+---------+---------+---------+

可能有一些方法可以通过删除交叉连接并将其替换为更聪明的方法来提高其效率。

如果需要处理具有多行的起始数据帧,则需要将行聚合在一起(或更改预期输出的要求)。例如,您可能希望对所有内容进行汇总,例如以下示例。

from pyspark.sql.functions import sum

d = [[1,2,3],[4,5,6]]
dfd = spark.createDataFrame(a,['col1','col2','col3'])

dfdagg = dfd.groupby().agg(*[sum(col) for colname in dfa.columns])

现在dfdagg可以使用与上面使用其他数据帧相同的方式使用。

答案 1 :(得分:0)

以另一种方式,您可以使用堆栈函数来转置dfs,然后将其合并

>>> df1x = df1.selectExpr("stack(3, 'col1', col1, 'col2', col2, 'col3', col3) as (col_name, value1)")
>>> df1x.show()
+--------+------+
|col_name|value1|
+--------+------+
|    col1|    10|
|    col2|     1|
|    col3|     0|
+--------+------+

>>> df2x = df2.selectExpr("stack(2, 'col1', col1, 'col2', col2) as (col_name, value2)")
>>> df2x.show()
+--------+------+
|col_name|value2|
+--------+------+
|    col1|    20|
|    col2|     6|
+--------+------+

>>> df3x = df3.selectExpr("stack(4, 'col1', col1, 'col2', col2, 'col3', col3, 'col4', col4) as (col_name, value3)")
>>> df3x.show()
+--------+------+
|col_name|value3|
+--------+------+
|    col1|     1|
|    col2|     5|
|    col3|     3|
|    col4|     4|
+--------+------+

>>> df1x.join(df2x, "col_name", "full").join(df3x, "col_name", "full").sort("col_name").show()
+--------+------+------+------+                                                 
|col_name|value1|value2|value3|
+--------+------+------+------+
|    col1|    10|    20|     1|
|    col2|     1|     6|     5|
|    col3|     0|  null|     3|
|    col4|  null|  null|     4|
+--------+------+------+------+