总结来自pyspark的官方文档:http://spark.apache.org/docs/latest/api/python/index.html
pyspark中一共有以下几个包和子包:
pyspark
pyspark.sql
pyspark.streaming
pyspark.ml
pyspark.mllib
Spark最常用的几个核心类有如下:
类名 | 功能 |
---|---|
pyspark.sql.SparkSession | Spark的主要入口点,还包含了操作DataFrame和SQL的方法 |
pyspark.SparkContext | Spark功能的主要入口点 |
pyspark.RDD | 弹性分布式数据集(RDD),Spark中的基本数据集合 |
pyspark.sql.DataFrame | 分布式数据集合,类似与SQL数据库中的表 |
pyspark.sql.Column | DataFrame中的一列数据 |
pyspark.sql.Row | DataFrame中的一行数据 |
pyspark.sql.DataFrameReader | 类中包含读取文件为DataFrame的函数 |
pyspark.sql.DataFrameWriter | 类中包含将DataFrame写入其它文件或数据库的函数 |
pyspark.sqlDataFrameNaFunctions | 用于处理DataFrame中的缺失值 |
pyspark.sqlDataFrameStatFunctions | 用于对DataFrame做统计相关的功能 |
pyspark.sql.functions | 集成了可用于DataFrame的内置函数 |
pyspark.streaming.StreamingContext | Spark Streaming功能的主要入口点 |
pyspark.streaming.DStream | 离散流(DStream),Spark Streaming中的基本数据类型 |
其中,SparkSession和SparkContext 是Spark的两个入口,目前官方推荐使用SparkSession作为入口,实际上SparkSession中包含了SparkContext中的大部分方法。
RDD和DataFrame是Spark中最常用的两种数据集合。Column和Row分别是DataFrame类型中的一列和一行。
-
RDD(Resilient Distributed Dataset),弹性分布式数据集,集合内对象分布在不同的节点之上,可以并行执行操作,是spark应用程序的基本数据结构。RDD中的元素类型是非结构化的,可以是任意JVM对象。
-
DataFrame,类似于关系型数据库中的表,相比于RDD,其内部的每一条记录都是结构化的。一般而言,推荐优先使用这种数据结构,可以轻易的在其上使用sql类操作,与hive结合较好。
1. Session类
1.1 Session类的常用属性
属性 | 返回值类型 |
---|---|
sparkContext | 返回底层的SparkContext对象 |
read | 返回DataFrameReader对象,用于读取文件等 |
version | Spark的版本号,字符串 |
conf | Spark的配置,可用Session.conf.set()设置配置 |
udf | 返回一个UDFRegistration对象 |
readStream | 返回DataStreamReader对象,用于读取数据流 |
streams | 返回StreamingQueryManager,用于管理当前context下激活的所有StreamingQueries |
catalog | 返回Catalog对象,用于创建、删除、更改或查询底层数据库/表/函数等 |
1.2 Session类的常用方法
1.2.1 获取Session对象,打开Spark入口
注意:以下代码中出现的“spark”均为SparkSession对象
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("your_app_name").getOrCreate()
1.2.2 配置Session
spark.conf.set(“spark.sql.sources.partitionOverwriteMode”, “dynamic”)
1.2.3 sql方法
def sql(self, sqlQuery)
传入SQL指令并执行,将获取到的数据存放到DataFrame中并返回
>>> df2 = spark.sql("SELECT field1 AS f1, field2 as f2 from table1")
>>> df2.collect() # 将df的所有数据放到list中并返回,后面会介绍此方法
[Row(f1=1, f2=u'row1'), Row(f1=2, f2=u'row2'), Row(f1=3, f2=u'row3')]
1.2.4 createDataFrame方法
def createDataFrame(self, data, schema=None, samplingRatio=None, verifySchema=True)
通过RDD、list或pandas.DataFrame来创建一个pyspark的DataFrame对象。
data: 用来创建df的原数据。传入类型:RDD、list、tuple、dict或pandas.DataFrame
schema: 用来指定列名或列的数据类型。传入类型:pyspark.sql.types.DataType、datatype string 或 字符串列表表示列名。示例:
1)指定列名:schema=[‘name’, ‘age’]
2)同时指定列名和数据类型:“a: string, b: int”
3)同时指定列名和数据类型
schema = StructType([
StructField("name", StringType(), True),
StructField("age", IntegerType(), True)])
返回值: DataFrame对象
例程:
# 用tuple创建一行两列的df
>>> l = [('Alice', 1)] # tuple
>>> spark.createDataFrame(l).collect()
[Row(_1=u'Alice', _2=1)
# schema参数指定列名
>>> spark.createDataFrame(l, ['name', 'age']).collect()
[Row(name=u'Alice', age=1)]
# 用dict创建一行两列的df
>>> d = [{'name': 'Alice', 'age': 1}]
>>> spark.createDataFrame(d).collect()
[Row(age=1, name=u'Alice')]
# 用rdd创建df
>>> sc = SparkContext.getOrCreate()
>>> rdd = sc.parallelize(l) # 生成rdd的一种方法,会面会讲
>>> spark.createDataFrame(rdd).collect()
[Row(_1=u'Alice', _2=1)]
>>> df = spark.createDataFrame(rdd, ['name', 'age']) # 用rdd创建df,并指定列名
>>> df.collect()
[Row(name=u'Alice', age=1)]
# 用schema参数指定列名和每列的数据类型
>>> from pyspark.sql.types import *
>>> schema = StructType([
... StructField("name", StringType(), True),
... StructField("age", IntegerType(), True)])
>>> df3 = spark.createDataFrame(rdd, schema)
>>> df3.collect()
[Row(name=u'Alice', age=1)]
# 用pandas.DataFrame创建Spark的df
>>> spark.createDataFrame(df.toPandas()).collect() # doctest: +SKIP
[Row(name=u'Alice', age=1)]
>>> spark.createDataFrame(pandas.DataFrame([[1, 2]])).collect() # doctest: +SKIP
[Row(0=1, 1=2)]
# 用rdd创建df,并且用schema参数指定列名和数据类型
>>> spark.createDataFrame(rdd, "a: string, b: int").collect()
[Row(a=u'Alice', b=1)]
>>> rdd = rdd.map(lambda row: row[1])
>>> spark.createDataFrame(rdd, "int").collect()
[Row(value=1)]
>>> spark.createDataFrame(rdd, "boolean").collect() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
Py4JJavaError: ...
1.2.5 range方法
def range(self, start, end=None, step=1, numPartitions=None)
Create a :class:DataFrame
with single :class:pyspark.sql.types.LongType
column named
id
, containing elements in a range from start
to end
(exclusive) with
step value step
.
构建一个只有一列的DataFrame,内容是等差数列。
start: 等差数列开始的数字;
end: 等差数列结束的数字。数列中一定不包含end!
step: 差值是多少;
numPartitions: 从方法说明中没有搞懂什么意思;
返回值: 只有1列的DataFrame,行数为数列的数字个数
# 生成1-6的等差数列,不包含7.
>>> ss.range(1,7,1).collect()
[Row(id=1), Row(id=2), Row(id=3), Row(id=4), Row(id=5), Row(id=6)]
>>> spark.range(1, 7, 2).collect()
[Row(id=1), Row(id=3), Row(id=5)]
# 只指定一个参数,该参数会被视为end
>>> spark.range(3).collect()
[Row(id=0), Row(id=1), Row(id=2)]
1.2.6 stop方法
def stop(self):
停止底层的对象SparkContext。当SparkSession对象被创建时,底层是默认打开一个SparkContext对象的。
2. DataFrame类
2.1 DataFrame类的常用属性
属性 | 功能 |
---|---|
dtypes | 返回所有列名和列数据类型组成的元祖列表,例:[(‘col_1’, ‘int’), (‘col_2’, ‘string’)] |
columns | 返回所有列名组成列表,例:[‘col_1’, ‘col_2’] |
rdd | 将df的内容创建成rdd并返回,原df中的一行Row变为rdd中一个元素 |
na | 返回DataFrameNaFunctions的对象,用于处理缺失值 |
stat | 返回DataFrameStatFunctions的对象,用于做统计相关的功能 |
write | 返回DataFrameWriter对象,用于将df保存到其它文件、数据库或表中 |
writeStream | 返回DataStreamWriter对象,用于将DataFrame流数据写入其他存储结果 |
schema | 返回当前df的schema,格式为pyspark.sql.types.StructType |
isStreaming | False 或 True, 返回当前df是否包含流数据源 |
storageLevel | 返回当前df的存储等级 |
2.2 DataFrame类的常用方法
2.2.1 创建或替换临时表的方法
(1)createOrReplaceTempView(self, name):创建或替换临时表。
使用当前df创建一个临时的表或替换当前有的表(相当于数据库中的表),表的声明周期与生成该df的SparkSession生命周期一致。 参数name为字符串,表示要创建的表名。
例子:
>>> df.createOrReplaceTempView("people") # 用df创建临时表people
>>> df2 = df.filter(df.age > 3)
>>> df2.createOrReplaceTempView("people") # 用df2替换刚才临时表people的内容
>>> df3 = spark.sql("select * from people") # 用sql语句尝试读取临时表people的内容
>>> sorted(df3.collect()) == sorted(df2.collect()) # 验证读取出来的数据与原df2是否一致
True # 一致!
>>> spark.catalog.dropTempView("people") # 删除临时表
(2)createTempView(name):仅创建临时表,当表名已经存在时会报错。
(3)createGlobalTempView(name):创建本地的临时表,当表名已经存在时会报错。
(4)createOrReplaceGlobalTempView(name):创建或替换本地的临时表。
2.2.2 打印DataFrame对象的相关信息方法
(1) printSchema() : 打印df的schema信息
以树的显示格式打印当前df的schema信息。
例子:
>>> df.printSchema()
root
|-- age: integer (nullable = true)
|-- name: string (nullable = true)
<BLANKLINE>
(2) explain(extended=False) : 打印(逻辑和物理)计划
打印(逻辑和物理)计划到控制台,以方便程序员进行debug。参数extended,是否打印逻辑计划,默认False,只打印物理计划。
>>> df.explain()
== Physical Plan ==
Scan ExistingRDD[age#0,name#1]
>>> df.explain(True)
== Parsed Logical Plan ==
...
== Analyzed Logical Plan ==
...
== Optimized Logical Plan ==
...
== Physical Plan ==
...
(3) show(self, n=20, truncate=True, vertical=False):查看df的前几行
打印DataFrame的前几行,相当于pandas里面的head()方法。
n: 打印前几行,默认20.
truncate: 是否截断长度超过20的字符串?默认True截断,也可设置为其它数字自定义截断长度。
vertical: 是否将数据垂直打印(one line per column value)?默认False
例:
>>> df
DataFrame[age: int, name: string]
>>> df.show()
+---+-----+
|age| name|
+---+-----+
| 2|Alice|
| 5| Bob|
+---+-----+
>>> df.show(truncate=3)
+---+----+
|age|name|
+---+----+
| 2| Ali|
| 5| Bob|
+---+----+
>>> df.show(vertical=True)
-RECORD 0-----
age | 2
name | Alice
-RECORD 1-----
age | 5
name | Bob
(4) head(n=None): 打印df的前几行
返回DataFrame的前n行,这个方法是将结果放到本地机器上,所以要求n尽可能的小。
n默认为1。
>>> df.head()
Row(age=2, name=u'Alice')
>>> df.head(1)
[Row(age=2, name=u'Alice')]
(5) describe(*cols) : 查看df的统计信息
查看df的统计信息,包含 count, mean, stddev, min, and max.
如果不指定cols参数,默认统计所有数值和字符串列。
(注意:此函数用于探索性数据分析,因为我们无法保证生成的DataFrame的模式的向后兼容性)
>>> df.describe(['age']).show()
+-------+------------------+
|summary| age|
+-------+------------------+
| count| 2|
| mean| 3.5|
| stddev|2.1213203435596424|
| min| 2|
| max| 5|
+-------+------------------+
>>> df.describe().show()
+-------+------------------+-----+
|summary| age| name|
+-------+------------------+-----+
| count| 2| 2|
| mean| 3.5| null|
| stddev|2.1213203435596424| null|
| min| 2|Alice|
| max| 5| Bob|
+-------+------------------+-----+
(6) summary(*statistics)
计算df中的数字列和字符串列的特定的统计信息,可选有:
- count
- mean
- stddev # 标准差
- min
- max
- 任意近似百分位数,例: ‘75%’ , ‘10%’
如果参数statistics不指定,则默认计算:count, mean, stddev, min, approximate quartiles (percentiles at 25%, 50%, and 75%), and max。
如果只想对某些列进行统计,需要先用select选中某些列。
>>> df.summary().show()
+-------+------------------+-----+
|summary| age| name|
+-------+------------------+-----+
| count| 2| 2|
| mean| 3.5| null|
| stddev|2.1213203435596424| null|
| min| 2|Alice|
| 25%| 2| null|
| 50%| 2| null|
| 75%| 5| null|
| max| 5| Bob|
+-------+------------------+-----+
>>> df.summary("count", "min", "25%", "75%", "max").show()
+-------+---+-----+
|summary|age| name|
+-------+---+-----+
| count| 2| 2|
| min| 2|Alice|
| 25%| 2| null|
| 75%| 5| null|
| max| 5| Bob|
+-------+---+-----+
# 如果只想对某些列进行统计,需要先用select选中某些列
>>> df.select("age", "name").summary("count").show()
+-------+---+----+
|summary|age|name|
+-------+---+----+
| count| 2| 2|
+-------+---+----+
(7) count
def count(self):
返回df中的行数。
>>> df.count()
2
(8) sample
def sample(self, withReplacement=None, fraction=None, seed=None):
相当于在SQL中看sample,返回对df采样的子df。
withReplacement: Sample with replacement or not (default False).
fraction: 采样几分之几的行,可取范围[0.0, 1.0],0.1代表取10%的样本。
seed: 随机种子 (default a random seed).
>>> df = spark.range(10)
>>> df.sample(0.5, 3).count()
4
>>> df.sample(fraction=0.5, seed=3).count()
4
>>> df.sample(withReplacement=True, fraction=0.5, seed=3).count()
1
>>> df.sample(1.0).count()
10
>>> df.sample(fraction=1.0).count()
10
>>> df.sample(False, fraction=1.0).count()
10
(9) limit
def limit(self, num):
相当于SQL中的limit,限定df的前几列。
>>> df.limit(1).collect()
[Row(age=2, name=u'Alice')]
>>> df.limit(0).collect()
[]
2.2.3 对df切片的方法:
(1) first() : 返回df的第一行为Row对象
返回df的第一行,返回值类型为Row对象。
>>> df.first()
Row(age=2, name=u'Alice')
(2) filter(condition) 或 where(condition) : 筛选行
使用给定的condition条件,选择满足条件的行,返回值为DataFrame对象。filter和where是同名同功能的。
**condition:**可选类型两种:
1)数据类型为BooleanType的Column类,如 df.age > 3;
2)字符串:SQL表达式,如"age > 3";
# 第1种类型的筛选条件
>>> df.filter(df.age > 3).collect()
[Row(age=5, name=u'Bob')]
>>> df.where(df.age == 2).collect()
[Row(age=2, name=u'Alice')]
# 第2种类型的筛选条件
>>> df.filter("age > 3").collect()
[Row(age=5, name=u'Bob')]
>>> df.where("age = 2").collect()
[Row(age=2, name=u'Alice')]
(3) *select(cols) : 用string筛选df的列
根据表达式筛选特定的列出来,返回一个新的DataFrame。
cols: list of column names (string) or expressions (:class:Column
). 即list或string
如果其中一个列名为’*’,则会把整个df都选中。
>>> df.select('*').collect()
[Row(age=2, name=u'Alice'), Row(age=5, name=u'Bob')]
# 对列名排序
>>> df.select('name', 'age').collect()
[Row(name=u'Alice', age=2), Row(name=u'Bob', age=5)]
# 根据原先列做数据转换,还可以命名新的列名
>>> df.select(df.name, (df.age + 10).alias('age')).collect()
[Row(name=u'Alice', age=12), Row(name=u'Bob', age=15)]
(4) selectExpr(*expr): 用SQL筛选df的列
select方法的变种,输入参数是SQL表达式:
例子:
>>> df.selectExpr("age * 2", "abs(age)").collect()
[Row((age * 2)=4, abs(age)=2), Row((age * 2)=10, abs(age)=5)]
(5)drop : 删除列
def drop(self, *cols):
丢掉原df中的某些列,返回一个丢掉列后的DataFrame。
cols: 列名字符串组成的列表[‘col_1’,‘col_2’],或类型为Column
的对象,如df.name。
>>> df.drop('age').collect()
[Row(name=u'Alice'), Row(name=u'Bob')]
>>> df.drop(df.age).collect()
[Row(name=u'Alice'), Row(name=u'Bob')]
>>> df.join(df2, df.name == df2.name, 'inner').drop(df.name).collect()
[Row(age=5, height=85, name=u'Bob')]
>>> df.join(df2, df.name == df2.name, 'inner').drop(df2.name).collect()
[Row(age=5, name=u'Bob', height=85)]
>>> df.join(df2, 'name', 'inner').drop('age', 'height').collect()
[Row(name=u'Bob')]
(6) colRegex : 用正则表达式选择列,返回Column对象
def colRegex(self, colName):
用正则表达式来选择df的某些列,返回Column对象,返回值可以输入到其它方法中要求输入列名的地方,如cols等参数。
colName: string, column name specified as a regex.
>>> df = spark.createDataFrame([("a", 1), ("b", 2), ("c", 3)], ["Col1", "Col2"])
>>> df.select(df.colRegex("`(Col1)?+.+`")).show()
+----+
|Col2|
+----+
| 1|
| 2|
| 3|
+----+
2.2.4 分组和聚合操作
(1) groupby(*cols) 或 groupBy
同pandas里面的groupby,根据某些列将df分组,以方便做其它统计聚合操作。
返回值为GroupedData对象,所有可以做的操作见类:GroupedData
。
cols: list of columns to group by. Each element should be a column name (string) or an expression (:class:Column
).
>>> df.groupBy().avg().collect()
[Row(avg(age)=3.5)]
>>> sorted(df.groupBy('name').agg({'age': 'mean'}).collect())
[Row(name=u'Alice', avg(age)=2.0), Row(name=u'Bob', avg(age)=5.0)]
>>> sorted(df.groupBy(df.name).avg().collect())
[Row(name=u'Alice', avg(age)=2.0), Row(name=u'Bob', avg(age)=5.0)]
>>> sorted(df.groupBy(['name', df.age]).count().collect())
[Row(name=u'Alice', age=2, count=1), Row(name=u'Bob', age=5, count=1)]
(2) agg(self, *exprs)
agg对应英文单词Aggregate,意思为聚合!可实现在df上直接进行聚合操作(最值、平均值等)。
agg方法是快速实现df.groupBy.agg()功能的一种方法。
>>> df.agg({"age": "max"}).collect()
[Row(max(age)=5)]
>>> from pyspark.sql import functions as F
>>> df.agg(F.min(df.age)).collect()
[Row(min(age)=2)]
2.2.5 合并操作
(1) join
def join(self, other, on=None, how=None):
用给定的join表达式合并两个df。
other: 要与本df进行合并的df,本df为左表,other为右表。
on: 根据哪些列进行join,可选:列字符串、列字符串列表、Column类型的对象。
注意: on指定的列必须在两个表中都存在!!!
how: str, 默认为 inner
. Must be one of: inner
, cross
, outer
,
full
, full_outer
, left
, left_outer
, right
, right_outer
,
left_semi
, and left_anti
.
>>> df.join(df2, df.name == df2.name, 'outer').select(df.name, df2.height).collect()
[Row(name=None, height=80), Row(name=u'Bob', height=85), Row(name=u'Alice', height=None)]
>>> df.join(df2, 'name', 'outer').select('name', 'height').collect()
[Row(name=u'Tom', height=80), Row(name=u'Bob', height=85), Row(name=u'Alice', height=None)]
>>> cond = [df.name == df3.name, df.age == df3.age]
>>> df.join(df3, cond, 'outer').select(df.name, df3.age).collect()
[Row(name=u'Alice', age=2), Row(name=u'Bob', age=5)]
>>> df.join(df2, 'name').select(df.name, df2.height).collect()
[Row(name=u'Bob', height=85)]
>>> df.join(df4, ['name', 'age']).select(df.name, df.age).collect()
[Row(name=u'Bob', age=5)]
crossJoin(self, other): (一般不用!!!)
返回本df与other两个df的笛卡尔积。
(2) 行方向的合并,增加行
union(self, other):
合并本df和other这个df的所有行,返回一个新的DataFrame。
本方法类似与SQL中的 UNION ALL
,与SQL中相同,本方法是根据列的位置来合并两个df的(不是根据列名),也就是说两表中同为第1列的会合并为一列,不论这两列的列名是否相同。
>>> df1 = spark.createDataFrame([[1, 2, 3]], ["col0", "col1", "col2"])
>>> df2 = spark.createDataFrame([[4, 5, 6]], ["col1", "col2", "col0"])
>>> df1.union(df2).show()
+----+----+----+
|col0|col1|col2|
+----+----+----+
| 1| 2| 3|
| 4| 5| 6|
+----+----+----+
unionByName(self, other): (推荐!)
与SQL中的UNION ALL
and UNION DISTINCT
不同,本方法通过列名解析列(而不是位置)。
例:两表中列名同为"col0"的会合并为新的一列。
>>> df1 = spark.createDataFrame([[1, 2, 3]], ["col0", "col1", "col2"])
>>> df2 = spark.createDataFrame([[4, 5, 6]], ["col1", "col2", "col0"])
>>> df1.unionByName(df2).show()
+----+----+----+
|col0|col1|col2|
+----+----+----+
| 1| 2| 3|
| 6| 4| 5|
+----+----+----+
(3) intersect(oter): 两表取交集
def intersect(self, other): 返回新的DataFrame,只包含同时在两表中出现的行。等同于SQL中的INTERSECT。、
注意:如果df1中有两行完全一致,df2中也有这两行且完全一致,在最后的结果中,之后出现一次该行。
def intersectAll(self, other):
如果df1中有两行完全一致,df2中也有这两行且完全一致,在最后的结果中会出现两次该行。
例:
>>> df1 = spark.createDataFrame([("a", 1), ("a", 1), ("b", 3), ("c", 4)], ["C1", "C2"])
>>> df2 = spark.createDataFrame([("a", 1), ("a", 1), ("b", 3)], ["C1", "C2"])
>>> df1.intersectAll(df2).sort("C1", "C2").show()
+---+---+
| C1| C2|
+---+---+
| a| 1|
| a| 1|
| b| 3|
+---+---+
(4) 排除另一个表中包含的行
def subtract(self, other):返回一个新的DataFrame,会排除掉本df中有,且other中也有的行,即只留下本df中独有的行,相当于SQL中的 EXCEPT DISTINCT
。
2.2.6 数据预处理
(1)去除重复的行
def dropDuplicates(self, subset=None):
返回新的DataFrame,删除原表中重复的行,当subset=None时,除非两行的所有列的值均相同,才会被删除。也可以用subset参数指定检测的列,如只检测某一列,这一列有重复值,就会发生删除。
>>> from pyspark.sql import Row
>>> df = sc.parallelize([ \\
... Row(name='Alice', age=5, height=80), \\
... Row(name='Alice', age=5, height=80), \\
... Row(name='Alice', age=10, height=80)]).toDF()
>>> df.dropDuplicates().show()
+---+------+-----+
|age|height| name|
+---+------+-----+
| 5| 80|Alice|
| 10| 80|Alice|
+---+------+-----+
>>> df.dropDuplicates(['name', 'height']).show()
+---+------+-----+
|age|height| name|
+---+------+-----+
| 5| 80|Alice|
+---+------+-----+
(2) dropna
def dropna(self, how=‘any’, thresh=None, subset=None):
删除原df中包含空值的行,返回一个新的DataFrame。
DataFrame.dropna 与 DataFrameNaFunctions.drop 方法等同。
how:
‘any’:只有某行包含一个空值,就删除该行;
‘all’:某行全部是空值才会删除该行。
thresh: int, 默认为None。表示如果某行的非空值小于thresh个,就会删除该行。设置thresh后,how参数将会失效。
subset: string列表,指定考虑那些列名。
>>> df4.dropna().show()
>>> df4.na.drop().show()
+---+------+-----+
|age|height| name|
+---+------+-----+
| 10| 80|Alice|
+---+------+-----+
(3) fillna
def fillna(self, value, subset=None):
将表中的所有空值填充为value参数指定的值。
df.fillna()与df.na.fill()等同,相当于 DataFrame.fillna
and DataFrameNaFunctions.fill
。
value: 可选:int, long, float, string, bool or dict. 用于替换空值的值。
如果value设定为字典dict,subset参数将会被忽略,表示某一列有缺失时为该列填充什么值,例:{‘col_1’ : 1, ‘col_2’ : 0}。
subset: 考虑哪些列。list of string
>>> df4.na.fill(50).show()
+---+------+-----+
|age|height| name|
+---+------+-----+
| 10| 80|Alice|
| 5| 50| Bob|
| 50| 50| Tom|
| 50| 50| null|
+---+------+-----+
>>> df5.na.fill(False).show()
+----+-------+-----+
| age| name| spy|
+----+-------+-----+
| 10| Alice|false|
| 5| Bob|false|
|null|Mallory| true|
+----+-------+-----+
>>> df4.na.fill({'age': 50, 'name': 'unknown'}).show()
+---+------+-------+
|age|height| name|
+---+------+-------+
| 10| 80| Alice|
| 5| null| Bob|
| 50| null| Tom|
| 50| null|unknown|
+---+------+-------+
(4)replace方法
def replace(self, to_replace, value=_NoValue, subset=None):
将原df中的某些值替换成其它的值,返回替换后的DataFrame。
DataFrame.replace 和 DataFrameNaFunctions.replace等价。
to_replace: bool, int, long, float, string, list or dict,想被替代的值。
若to_replace设置为dict,参数value将会被忽略,dict的键指定要被替换的值,dict的值指定要替换成什么值,如{‘100’: 0, ‘888’:999},将所有100都换成0,所有888换成999.
value: bool, int, long, float, string, list or None,想要替换成的值。
subset: list of string要考虑哪些列。
>>> df4.na.replace(10, 20).show()
+----+------+-----+
| age|height| name|
+----+------+-----+
| 20| 80|Alice|
| 5| null| Bob|
|null| null| Tom|
|null| null| null|
+----+------+-----+
>>> df4.na.replace('Alice', None).show()
+----+------+----+
| age|height|name|
+----+------+----+
| 10| 80|null|
| 5| null| Bob|
|null| null| Tom|
|null| null|null|
+----+------+----+
>>> df4.na.replace({'Alice': None}).show()
+----+------+----+
| age|height|name|
+----+------+----+
| 10| 80|null|
| 5| null| Bob|
|null| null| Tom|
|null| null|null|
+----+------+----+
>>> df4.na.replace(['Alice', 'Bob'], ['A', 'B'], 'name').show()
+----+------+----+
| age|height|name|
+----+------+----+
| 10| 80| A|
| 5| null| B|
|null| null| Tom|
|null| null|null|
+----+------+----+
(5)distinct方法
def distinct(self):
删除df中重复的行,返回删除后的新DataFrame。
>>> df.distinct().count() # 计算不重复的行有几行
2
2.2.7 排序方法
(1)sortWithinPartitions
**def sortWithinPartitions(self, *cols, kwargs):
df的每个分区分别在自己分区范围内排序,返回df排序的结果。
cols: 要排序的列名,Column或字符串组成的list。
ascending: 是否升序?默认True。可选:boolean 或list of boolean。
如果ascending参数输入为list,则该list的长度必须与cols的长度相同,对应每一列按照什么顺序排序。
>>> df.sortWithinPartitions("age", ascending=False).show()
+---+-----+
|age| name|
+---+-----+
| 2|Alice|
| 5| Bob|
+---+-----+
**def sort(self, *cols, kwargs):
排序,忽略分区,所有列一起排序。
cols: 要排序的列名,Column或字符串组成的list。
ascending: 是否升序?默认True。可选:boolean 或list of boolean。
>>> df.sort(df.age.desc()).collect()
[Row(age=5, name=u'Bob'), Row(age=2, name=u'Alice')]
>>> df.sort("age", ascending=False).collect()
[Row(age=5, name=u'Bob'), Row(age=2, name=u'Alice')]
>>> df.orderBy(df.age.desc()).collect()
[Row(age=5, name=u'Bob'), Row(age=2, name=u'Alice')]
>>> from pyspark.sql.functions import *
>>> df.sort(asc("age")).collect()
[Row(age=2, name=u'Alice'), Row(age=5, name=u'Bob')]
>>> df.orderBy(desc("age"), "name").collect()
[Row(age=5, name=u'Bob'), Row(age=2, name=u'Alice')]
>>> df.orderBy(["age", "name"], ascending=[0, 1]).collect()
[Row(age=5, name=u'Bob'), Row(age=2, name=u'Alice')]
2.2.8 数据类型转换相关的方法
(1) toPandas
def toPandas(self):
将本df转换为pandas的df并返回。
注意:这个方法用的时候,df一定不能太大,因为所有的存储都是在本机的内存上。
>>> df.toPandas() # doctest: +SKIP
age name
0 2 Alice
1 5 Bob
(2) toJSON
def toJSON(self, use_unicode=True):
将df转换为包含字符串的RDD类型,原df中的每一行会转变成一个JSON格式的字符串,存成RDD中的一个元素。
>>> df.toJSON().first()
u'{"age":2,"name":"Alice"}'
2.2.9 统计类方法
(1) corr
def corr(self, col1, col2, method=None):
计算df中两列的皮尔森相关系数,返回double值。DataFrame.corr 等同于 DataFrameStatFunctions.corr。
col1: The name of the first column
col2: The name of the second column
method: 求相关系数的方法,目前只支持 “pearson”。
(2) cov
def cov(self, col1, col2):
计算给定两列的样本协方差,返回double值。DataFrame.cov 等同于DataFrameStatFunctions.cov。
col1: The name of the first column
col2: The name of the second column
(3) approxQuantile: 求某列的分位数
def approxQuantile(self, col, probabilities, relativeError):
2.2.10 其它方法
(1)每行执行函数
def foreach(self, f):
对df的每一行执行函数f , 等同于df.rdd.foreach()
.
>>> def f(person):
... print(person.name)
>>> df.foreach(f)
def foreachPartition(self, f):
对df的每一个分区执行函数f,等同于 df.rdd.foreachPartition()
.
>>> def f(people):
... for person in people:
... print(person.name)
>>> df.foreachPartition(f)
(2)增加列、修改列名
def withColumn(self, colName, col): 增加一列或修改现有列的内容。
colName: string, 新增列的列名.
col: 新增列的值如何设置,用Column
表达式设定如何设置新列的值。col表达式必须是在调用本方法的df上进行操作,如果调用了其它的df会报错。
见示例。
>>> df.withColumn('age2', df.age + 2).collect()
[Row(age=2, name=u'Alice', age2=4), Row(age=5, name=u'Bob', age2=7)]
如果此时df中已有一列名为’age2’,则上面的操作实际为修改’age2’列的内容。
def withColumnRenamed(self, existing, new): 修改df中的某列的列名,返回新的df。
如果existing不存在,本方法相当于空操作,不会报错。
existing: string, name of the existing column to rename.
new: string, new name of the column.
>>> df.withColumnRenamed('age', 'age2').collect()
[Row(age2=2, name=u'Alice'), Row(age2=5, name=u'Bob')]
(3)重新设定分区
def repartition(self, numPartitions, *cols):
将df按照指定的分区个数重新分区。分区方式为哈希分区。
numPartitions: 无默认参数,必须赋值,不赋值会报错。
1) int值,指定分区个数;
2) string,列名,指定用哪一列作为分区(类似与SQL中根据字段分区);
查询DataFrame的分区个数的方法: df.rdd.getNumPartitions()
>>> df.repartition(10).rdd.getNumPartitions()
10
>>> data = df.union(df).repartition("age")
>>> data.show()
+---+-----+
|age| name|
+---+-----+
| 5| Bob|
| 5| Bob|
| 2|Alice|
| 2|Alice|
+---+-----+
>>> data = data.repartition(7, "age") # 划分成7个分区,并将age作为分区的列
>>> data.show()
+---+-----+
|age| name|
+---+-----+
| 2|Alice|
| 5| Bob|
| 2|Alice|
| 5| Bob|
+---+-----+
>>> data.rdd.getNumPartitions()
7
>>> data = data.repartition("name", "age")
>>> data.show()
+---+-----+
|age| name|
+---+-----+
| 5| Bob|
| 5| Bob|
| 2|Alice|
| 2|Alice|
+---+-----+
def repartitionByRange(self, numPartitions, *cols):
将df按照指定的分区个数重新分区。分区方式为范围分区,即根据某列值的大小,大致均匀的分成几份,以此将表分成几个区。默认顺序是升序排列。
(不同分区方式的区别和介绍参考博客:https://blog.csdn.net/qq_33813365/article/details/78143492)
numPartitions: 无默认参数,必须赋值,不赋值会报错。
1) int值,指定分区个数;
2) string,列名,指定用哪一列作为分区(类似与SQL中根据字段分区);
注意:必须至少有一个分区表达式,即至少要指定数量或列名中的一个。
When no explicit sort order is specified, “ascending nulls first” is assumed.
>>> df.repartitionByRange(2, "age").rdd.getNumPartitions()
2
>>> df.show()
+---+-----+
|age| name|
+---+-----+
| 2|Alice|
| 5| Bob|
+---+-----+
>>> df.repartitionByRange(1, "age").rdd.getNumPartitions()
1
>>> data = df.repartitionByRange("age")
>>> df.show()
+---+-----+
|age| name|
+---+-----+
| 2|Alice|
| 5| Bob|
+---+-----+
3. DataFrameReader常用方法
3.1 text方法
作用:从文本文件中读入数据,返回DataFrame对象,列名为‘value’。
定义: text(self, paths, wholetext=False, lineSep=None):
---------------------------------------------- 参数列表 ----------------------------------------------
paths: string 或 list of strings,文件的路径;
wholetext: 默认False,表示文件中的每一行当做DataFrame中的一行 ; True:将单个文件的所有内容设定为DataFrame的一行。
lineSep: 设置可以识别的行分隔符,当默认为None时,可以识别的有:\r
, \r\n
and \n
。
例子:
>>> df = spark.read.text('python/test_support/sql/text-test.txt')
>>> df.collect()
[Row(value=u'hello'), Row(value=u'this')]
>>> df = spark.read.text('python/test_support/sql/text-test.txt', wholetext=True)
>>> df.collect()
[Row(value=u'hello\\nthis')]
3.2 csv方法
从csv文件中读取数据,返回DataFrame对象。
定义:
csv(self, path, schema=None, sep=None, encoding=None, quote=None, escape=None,
comment=None, header=None, inferSchema=None, ignoreLeadingWhiteSpace=None,
ignoreTrailingWhiteSpace=None, nullValue=None, nanValue=None, positiveInf=None,
negativeInf=None, dateFormat=None, timestampFormat=None, maxColumns=None,
maxCharsPerColumn=None, maxMalformedLogPerPartition=None, mode=None,
columnNameOfCorruptRecord=None, multiLine=None, charToEscapeQuoteEscaping=None,
samplingRatio=None, enforceSchema=None, emptyValue=None):
---------------------------------------------- 参数列表 ----------------------------------------------
path: string, or list of strings, or RDD of Strings storing CSV rows,文件所在路径。
schema: 用来指定列名或列的数据类型。传入类型:pyspark.sql.types.DataType、datatype string 或 字符串列表表示列名。示例:
1)指定列名:schema=[‘name’, ‘age’]
2)同时指定列名和数据类型:“a: string, b: int”
3)同时指定列名和数据类型
sep: 指定数据之间的分隔符,默认为逗号’,’
encoding: 指定CSV文件的解码方式,默认为’UTF-8
’。
header: 是否将CSV文件的第一行当做DataFrame的列名,默认False。
ignoreLeadingWhiteSpace: 是否忽略数据开头的空格?默认False不忽略。
ignoreTrailingWhiteSpace:是否忽略数据末尾的空格?默认False不忽略。
nullValue: 设定表示空值的字符串,默认为空字符串’’。
nanValue: 设定表示非数字型数据的字符串,默认为’NaN’。
示例:
>>> df = spark.read.csv('python/test_support/sql/ages.csv')
>>> df.dtypes
[('_c0', 'string'), ('_c1', 'string')]
>>> sc = spark.sparkContext
>>> rdd = sc.textFile('python/test_support/sql/ages.csv')
>>> df2 = spark.read.csv(rdd)
>>> df2.dtypes
[('_c0', 'string'), ('_c1', 'string')]
3.3 table方法
将指定数据库的某个表中的数据读取为DataFrame对象并返回。
定义: def table(self, tableName):
tableName: string, 表的名称。
例程:
>>> df = spark.read.parquet('python/test_support/sql/parquet_partitioned')
>>> df.createOrReplaceTempView('tmpTable') # 创建一个临时的表
>>> spark.read.table('tmpTable').dtypes
[('name', 'string'), ('year', 'int'), ('month', 'int'), ('day', 'int')]
4. DataFrameWriter
4.1 常用方法
4.1.1 csv
定义:
csv(self, path, mode=None, compression=None, sep=None, quote=None, escape=None,
eader=None, nullValue=None, escapeQuotes=None, quoteAll=None, dateFormat=None,
timestampFormat=None, ignoreLeadingWhiteSpace=None, ignoreTrailingWhiteSpace=None,
charToEscapeQuoteEscaping=None, encoding=None, emptyValue=None)
将DataFrame保存到csv文件中。
path: 要存放的文件路径和文件名
mode: 如果文件已经存在,选择哪种模式写入数据:
参数可选值 | 效果 |
---|---|
‘error’ or ‘errorifexists’ (默认) | 抛出异常 |
‘append’ | 在已有数据后面接着写入新数据 |
‘overwrite’ | 覆盖原有数据 |
‘ignore’ | 忽略此次操作,即不写入数据 |
sep: 分隔符,默认是逗号’,’。
header: boolean,是否将列名写入文件,默认False;
4.1.2 saveAsTable
定义:saveAsTable(self, name, format=None, mode=None, partitionBy=None, **options)
将DataFrame保存到数据库的某个表中。注意当mode为overwrite覆盖时,不会自动选择覆盖某个分区,而是会把某个表的内容全部删除!!!如果需要覆盖某个分区的功能,必须要配置以下参数:
ss.conf.set('hive.exec.dynamic.partition', 'true')
ss.conf.set('hive.exec.dynamic.partition.mode', 'nonstrict')
ss.conf.set('spark.sql.sources.partition', verwriteMode','dynamic')
name : 表名
format: the format used to save
mode: 存放的模式,有以下4种模式:
参数可选值 | 效果 |
---|---|
‘error’ or ‘errorifexists’ (默认) | 抛出异常 |
‘append’ | 在已有数据后面接着写入新数据 |
‘overwrite’ | 覆盖原有数据,且不要求表结构一样。(慎用!如果不设置参数,会删除全部原数据!) |
‘ignore’ | 忽略此次操作,即不写入数据 |
partitionBy: 分区的列的名称
4.1.3 text方法
定义:text(self, path, compression=None, lineSep=None)
将DataFrame的内容存放到一个文本文件中。
path: 存放文件的路径,在HDFS中的路径。
compression: 压缩方式,可选:bzip2, gzip, lz4, snappy and deflate
lineSep: 行与行之间的分隔符,默认为 ’ \n ’