PySpark之列操作

简介

PySpark中的withColumn()函数可以用于修改或者更新值,以及转换DataFrame中已存在的列的类型,添加或者创建一个新的列等等。它是对DataFrame的transformation操作。withColumnRenamed()函数用来重命名一个或多个DataFrame中已存在的列。
sort()函数可以用来对单个列或者多个列进行排序。
groupby()函数用来将同一种类型的数据收集到一个组里,然后可以对这个组使用聚合函数。

1. 列基本操作

老规矩,还是先创建一个DataFrame,以下全部例子都是以这个测试数据为例。

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

spark = SparkSession.builder.appName('SparkByExamples.com').getOrCreate()

data = [('James','','Smith','1991-04-01','M',3000),
  ('Michael','Rose','','2000-05-19','M',4000),
  ('Robert','','Williams','1978-09-05','M',4000),
  ('Maria','Anne','Jones','1967-12-01','F',4000),
  ('Jen','Mary','Brown','1980-02-17','F',-1)
]

columns = ["firstname","middlename","lastname","dob","gender","salary"]
df = spark.createDataFrame(data=data, schema = columns)
df.printSchema()
df.show(truncate=False)

输出:

1.1 改变列的数据类型

通过对DataFrame使用withColumn()函数,我们可以强制转换或者改变一个列的类型,下面的例子把"salary"列的数据类型由"long"转为"Integer":

df2 = df.withColumn("salary",col("salary").cast("Integer"))
df2.printSchema()

输出:

1.2 更新已存在列中的值

为了改变值,我们需要传入已存在的列名称作为第一个参数,要修改的值作为第二个参数。下面的例子将"salary"这一列的值全部乘以100:

df3 = df.withColumn("salary",col("salary")*100)
df3.show()

输出:

1.3 根据已存在列创建一个新的列

要创建一个新的列,我们需要将新列的名称作为第一个参数传入,对已有列叠加一个操作之后作为第二个参数传入,如下例子是对"salary"列的元素乘以-1,然后创建了一个名为"CopiedColumn"的列:

df4 = df.withColumn("CopiedColumn",col("salary")* -1)
df4.show()

输出:

1.4 创建一个新的列

将要创建的新列的名称作为第一个参数传入,第二个参数这里使用的是lit(),lit函数是用来给DataFrame添加一个包含常数值的列。下面的例子给DataFrame添加了一个新的"Country"列:

df5 = df.withColumn("Country", lit("USA"))
df5.show()

输出:

1.5 重命名一个列

直接使用withColumnRenamed函数来重命名,第一个参数为原先的列名称,第二个为新的名称。下例将"gender"列改民为"sex":

df.withColumnRenamed("gender","sex") \
  .show(truncate=False) 

输出:

1.6 对列进行排序

我们在这里重新创建一个DataFrame,方便演示:

simpleData = [("James","Sales","NY",90000,34,10000), \
    ("Michael","Sales","NY",86000,56,20000), \
    ("Robert","Sales","CA",81000,30,23000), \
    ("Maria","Finance","CA",90000,24,23000), \
    ("Raman","Finance","CA",99000,40,24000), \
    ("Scott","Finance","NY",83000,36,19000), \
    ("Jen","Finance","NY",79000,53,15000), \
    ("Jeff","Marketing","CA",80000,25,18000), \
    ("Kumar","Marketing","NY",91000,50,21000) \
  ]
columns= ["employee_name","department","state","salary","age","bonus"]
df = spark.createDataFrame(data = simpleData, schema = columns)
df.printSchema()
df.show(truncate=False)

下面按照"department"和"state"这两列来进行排序,默认是升序排序,下面这两种写法输出是一样的:

df.sort("department","state").show(truncate=False)
# df.sort(col("department"),col("state")).show(truncate=False)

输出:

如果想降序排序,则可以使用desc()函数,默认是升序,也可以通过asc()函数显式指定。下面的例子对"department"列进行升序,对"state"列进行降序,如下:

df.sort(df.department.asc(),df.state.desc()).show(truncate=False)

输出:

2. 列进阶操作

当我们对DataFrame使用groupby()函数时,它返回一个GroupedData对象,这个对象包含了以下聚合函数:

  • count() - 用来计算每个组中的行数
  • mean() - 用来计算每个组中的平均值
  • max() - 用来计算每个组中的最大值
  • min() - 用来计算每个组中的最小值
  • sum() - 用来计算每个组中的总和
  • avg() - 用来计算每个组中的平均值
  • agg() - agg()函数可以一次执行多个聚合函数

还是先创建一个DataFrame,它包含了如下几个列,“employee_name”, “department”, “state“, “salary”, “age” 以及 “bonus” columns。

simpleData = [("James","Sales","NY",90000,34,10000),
    ("Michael","Sales","NY",86000,56,20000),
    ("Robert","Sales","CA",81000,30,23000),
    ("Maria","Finance","CA",90000,24,23000),
    ("Raman","Finance","CA",99000,40,24000),
    ("Scott","Finance","NY",83000,36,19000),
    ("Jen","Finance","NY",79000,53,15000),
    ("Jeff","Marketing","CA",80000,25,18000),
    ("Kumar","Marketing","NY",91000,50,21000)
  ]

schema = ["employee_name","department","state","salary","age","bonus"]
df = spark.createDataFrame(data=simpleData, schema = schema)
df.printSchema()
df.show(truncate=False)

输出:

2.1 对DataFrame的单列使用groupBy以及聚合函数

将测试数据"department"列中所有相同的元素聚集在一起,形成若干个组,然后对每个组中的"salary"列求和。

df.groupBy("department").sum("salary").show(truncate=False)

结果:

上述操作相当于求每个不同部门中员工的薪资总和。同理也可以求薪资的最小值,最大值、平均值等等。如下:

df.groupBy("department").min("salary")
df.groupBy("department").max("salary")
df.groupBy("department").avg("salary")

2.2 对DataFrame的多列使用groupBy以及聚合函数

groupBy函数也可以同时对多列进行操作,同理聚合函数也可以对多列进行操作。下面的例子演示了根据"department"和"state"列将原始数据分为若干个组,然后分别求"salary"和"bonus"的总和:

df.groupBy("department","state").sum("salary","bonus").show()

输出:

2.3 同时执行多个聚合函数

我们需要借助agg()函数,在一次groupBy操作中执行多个聚合操作。

df.groupBy("department") \
    .agg(sum("salary").alias("sum_salary"), \
         avg("salary").alias("avg_salary"), \
         sum("bonus").alias("sum_bonus"), \
         max("bonus").alias("max_bonus") \
     ) \
    .show(truncate=False)

输出:

这个代码的意思是,对原始数据按照"department"列中的不同元素,分为3个组,然后对每个组的"salary"和"bonus"列分别求总和和平均值,并且分别起了别名。
当然,还可以叠加filter操作,比如我们想筛选上述结果中,"sum_bonus"大于5000的,那么可以叠加一个"where"操作,代码如下:

df.groupBy("department") \
    .agg(sum("salary").alias("sum_salary"), \
      avg("salary").alias("avg_salary"), \
      sum("bonus").alias("sum_bonus"), \
      max("bonus").alias("max_bonus")) \
    .where(col("sum_bonus") >= 50000) \
    .show(truncate=False)

输出:

可以看到,"sum_salary"那一列小于50000的数据被筛选掉了。

参考

  • https://sparkbyexamples.com/pyspark/pyspark-groupby-explained-with-example/
  • https://sparkbyexamples.com/pyspark/pyspark-withcolumn/

你可能感兴趣的:(PySpark之列操作)