簡體   English   中英

在 PySpark 數據框中添加列總和作為新列

[英]Add column sum as new column in PySpark dataframe

我正在使用 PySpark,並且我有一個包含一堆數字列的 Spark 數據框。 我想添加一個列,它是所有其他列的總和。

假設我的數據框有“a”、“b”和“c”列。 我知道我可以這樣做:

df.withColumn('total_col', df.a + df.b + df.c)

問題是我不想單獨輸入每一列並添加它們,特別是如果我有很多列。 我希望能夠自動執行此操作或通過指定要添加的列名列表來執行此操作。 有沒有另一種方法可以做到這一點?

這並不明顯。 我沒有看到 spark Dataframes API 中定義的列的基於行的總和。

版本 2

這可以通過一種相當簡單的方式完成:

newdf = df.withColumn('total', sum(df[col] for col in df.columns))

df.columns由 pyspark 作為字符串列表提供,給出 Spark Dataframe 中的所有列名。 對於不同的總和,您可以提供任何其他列名稱列表。

我沒有嘗試將此作為我的第一個解決方案,因為我不確定它會如何表現。 但它有效。

版本 1

這過於復雜,但也有效。

你可以這樣做:

  1. 使用df.columns獲取列的名稱列表
  2. 使用該名稱列表來制作列列表
  3. 將該列表傳遞給將以折疊類型功能方式調用列的重載添加函數的內容

使用 python 的reduce ,一些關於運算符重載如何工作的知識,以及此處列的 pyspark 代碼變為:

def column_add(a,b):
     return  a.__add__(b)

newdf = df.withColumn('total_col', 
         reduce(column_add, ( df[col] for col in df.columns ) ))

注意這是一個python reduce,而不是spark RDD reduce,reduce的第二個參數中的括號項需要括號,因為它是一個列表生成器表達式。

經測試,有效!

$ pyspark
>>> df = sc.parallelize([{'a': 1, 'b':2, 'c':3}, {'a':8, 'b':5, 'c':6}, {'a':3, 'b':1, 'c':0}]).toDF().cache()
>>> df
DataFrame[a: bigint, b: bigint, c: bigint]
>>> df.columns
['a', 'b', 'c']
>>> def column_add(a,b):
...     return a.__add__(b)
...
>>> df.withColumn('total', reduce(column_add, ( df[col] for col in df.columns ) )).collect()
[Row(a=1, b=2, c=3, total=6), Row(a=8, b=5, c=6, total=19), Row(a=3, b=1, c=0, total=4)]

最直接的方法是使用expr函數

from pyspark.sql.functions import *
data = data.withColumn('total', expr("col1 + col2 + col3 + col4"))

解決方案

newdf = df.withColumn('total', sum(df[col] for col in df.columns))

由@Paul 作品發布。 盡管如此,我還是收到了錯誤,正如我所看到的一樣,

TypeError: 'Column' object is not callable

一段時間后,我發現了問題(至少在我的情況下)。 問題是我之前用這條線導入了一些pyspark函數

from pyspark.sql.functions import udf, col, count, sum, when, avg, mean, min

所以該行導入了sum pyspark 命令,而df.withColumn('total', sum(df[col] for col in df.columns))應該使用普通的 python sum函數。

您可以使用del sum刪除 pyspark 函數的引用。

否則在我的情況下,我將導入更改為

import pyspark.sql.functions as F

然后將函數引用為F.sum

將列表中的多列匯總為一列

PySpark 的sum函數不支持列添加。 這可以使用expr函數來實現。

from pyspark.sql.functions import expr

cols_list = ['a', 'b', 'c']

# Creating an addition expression using `join`
expression = '+'.join(cols_list)

df = df.withColumn('sum_cols', expr(expression))

這為我們提供了所需的列總和。

我的問題與上述類似(稍微復雜一點),因為我必須在 PySpark 數據幀中添加連續的列總和作為新列。 這種方法使用了上面 Paul 版本 1 中的代碼:

import pyspark
from pyspark.sql import SparkSession
import pandas as pd

spark = SparkSession.builder.appName('addColAsCumulativeSUM').getOrCreate()
df=spark.createDataFrame(data=[(1,2,3),(4,5,6),(3,2,1)\
                              ,(6,1,-4),(0,2,-2),(6,4,1)\
                              ,(4,5,2),(5,-3,-5),(6,4,-1)]\
                              ,schema=['x1','x2','x3'])
df.show()

+---+---+---+
| x1| x2| x3|
+---+---+---+
|  1|  2|  3|
|  4|  5|  6|
|  3|  2|  1|
|  6|  1| -4|
|  0|  2| -2|
|  6|  4|  1|
|  4|  5|  2|
|  5| -3| -5|
|  6|  4| -1|
+---+---+---+

colnames=df.columns

添加累積總和(連續)的新列:

for i in range(0,len(colnames)):
    colnameLst= colnames[0:i+1]
    colname = 'cm'+ str(i+1)
    df = df.withColumn(colname, sum(df[col] for col in colnameLst))

df.show()

+---+---+---+---+---+---+
| x1| x2| x3|cm1|cm2|cm3|
+---+---+---+---+---+---+
|  1|  2|  3|  1|  3|  6|
|  4|  5|  6|  4|  9| 15|
|  3|  2|  1|  3|  5|  6|
|  6|  1| -4|  6|  7|  3|
|  0|  2| -2|  0|  2|  0|
|  6|  4|  1|  6| 10| 11|
|  4|  5|  2|  4|  9| 11|
|  5| -3| -5|  5|  2| -3|
|  6|  4| -1|  6| 10|  9|
+---+---+---+---+---+---+

添加的“累計和”列如下:

cm1 = x1
cm2 = x1 + x2
cm3 = x1 + x2 + x3
df = spark.createDataFrame([("linha1", "valor1", 2), ("linha2", "valor2", 5)], ("Columna1", "Columna2", "Columna3"))

df.show()

+--------+--------+--------+
|Columna1|Columna2|Columna3|
+--------+--------+--------+
|  linha1|  valor1|       2|
|  linha2|  valor2|       5|
+--------+--------+--------+

df = df.withColumn('DivisaoPorDois', df[2]/2)
df.show()

+--------+--------+--------+--------------+
|Columna1|Columna2|Columna3|DivisaoPorDois|
+--------+--------+--------+--------------+
|  linha1|  valor1|       2|           1.0|
|  linha2|  valor2|       5|           2.5|
+--------+--------+--------+--------------+

df = df.withColumn('Soma_Colunas', df[2]+df[3])
df.show()

+--------+--------+--------+--------------+------------+
|Columna1|Columna2|Columna3|DivisaoPorDois|Soma_Colunas|
+--------+--------+--------+--------------+------------+
|  linha1|  valor1|       2|           1.0|         3.0|
|  linha2|  valor2|       5|           2.5|         7.5|
+--------+--------+--------+--------------+------------+

一個非常簡單的方法是使用 select 而不是 withcolumn 如下:

df = df.select('*', (col("a")+col("b")+col('c).alias("total"))

這應該為您提供所需的金額,並根據要求進行細微的更改

以下方法對我有用:

  1. 導入pyspark sql函數
    from pyspark.sql 導入函數為 F
  2. 使用 F.expr(list_of_columns)
    data_frame.withColumn('Total_Sum',F.expr('col_name 1 +col_name 2 +..col_name n )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM