【问题标题】:How to aggregate multiple columns and output as rows?如何聚合多个列并输出为行?
【发布时间】:2021-12-02 16:55:51
【问题描述】:

我正在使用 pyspark,我有这样的数据:

col1 col2 col3
1 0 1
1 1 0
1 1 0
1 0 0

我想要的输出是:

col sum
col1 4
col2 2
col3 1

我的第一个想法是将列名放在一个列表中,循环遍历它,每次对该列求和并将结果合并到一个新的 df。

然后我想,也许可以做多个聚合,例如:

df.agg(sum('col1), sum('col2))

...然后想办法取消透视。

有没有更简单的方法?

【问题讨论】:

    标签: python apache-spark pyspark


    【解决方案1】:

    据我所知,没有更简单的方法。您可以在聚合后对其进行反透视,方法是先将其转换为 Pandas 数据框,然后在其上调用 transpose,或者创建地图,然后分解地图以获得 colsum 列的结果。

    # Assuming initial dataframe is df
    aggDF = df.agg(*[F.sum(F.col(col_name)).alias(col_name) for col_name in df.columns])
    
    # Using pandas
    aggDF.toPandas().transpose().reset_index().rename({'index' : 'col', 0: 'sum'}, axis=1)
    
    # Going spark all the way
    aggDF.withColumn("col", F.create_map([e for col in aggDF.columns for e in (F.lit(col), F.col(col))])).selectExpr("explode(col) as (col, sum)").show()
    
    # Both return
    """
    +----+---+
    | col|sum|
    +----+---+
    |col1|  4|
    |col2|  2|
    |col3|  1|
    +----+---+
    """
    

    如果需要,这适用于超过 3 列。

    【讨论】:

      【解决方案2】:

      您可以使用stack SQL function 取消透视数据帧,如here 所述。所以你的代码会变成,input 作为你的输入数据框:

      from pyspark.sql import functions as F
      
      output = input.agg(
        F.sum("col1").alias("col1"),
        F.sum("col2").alias("col2"),
        F.sum("col3").alias("col3")
      ).select(
        F.expr("stack(3, 'col1', col1, 'col2', col2, 'col3', col3) as (col,sum)")
      )
      

      如果您有以下input 数据框:

      +----+----+----+
      |col1|col2|col3|
      +----+----+----+
      |1   |0   |1   |
      |1   |1   |0   |
      |1   |1   |0   |
      |1   |0   |0   |
      +----+----+----+
      

      您将获得以下output 数据框:

      +----+---+
      |col |sum|
      +----+---+
      |col1|4  |
      |col2|2  |
      |col3|1  |
      +----+---+
      

      【讨论】:

        【解决方案3】:

        你可以先对每一列求和:

        // input
        val df = List((1,0,1),(1,1,0),(1,1,0),(1,0,0)).toDF("col1", "col2", "col3")
        df.show
        
        // sum each column
        val sums = df.agg(sum("coL1").as("col1"), sum("col2").as("col2"), 
        sum("col3").as("col3"))
        sums.show 
        
        +----+----+----+
        |col1|col2|col3|
        +----+----+----+
        |   4|   2|   1|
        +----+----+----+
        

        这为您提供了一个具有 1 行和 3 列的 DS。您可以轻松收集。如果这是您想要的,请使用以下命令创建一个新数据集:

        val sumRow = sums.first
        
        val sumDS = List("col1" -> sumRow.getAs[Long]("col1"), "col2" -> 
        sumRow.getAs[Long]("col2"), "col3" -> sumRow.getAs[Long]("col3")).toDF("col", "sum")
        sumDS.show
        
        +----+---+
        | col|sum|
        +----+---+
        |col1|  4|
        |col2|  2|
        |col3|  1|
        +----+---+
        

        【讨论】:

          猜你喜欢
          • 2021-07-17
          • 2021-06-26
          • 1970-01-01
          • 2015-08-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多