pyspark常用類和方法總結:Session、DataFrame、DataFrameReader、DataFrameWriter

總結來自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類型中的一列和一行。

  1. RDD(Resilient Distributed Dataset),彈性分佈式數據集,集合內對象分佈在不同的節點之上,可以並行執行操作,是spark應用程序的基本數據結構。RDD中的元素類型是非結構化的,可以是任意JVM對象。

  2. 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 ’

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章