PySpark筆記(三):DataFrame

lvxfcjf發表於2021-09-09

DataFrame是在Spark 1.3中正式引入的一種以RDD為基礎的不可變的分散式資料集,類似於傳統資料庫的二維表格,資料在其中以列的形式被組織儲存。如果熟悉Pandas,其與Pandas DataFrame是非常類似的東西。

DataFrame API受到R和Python(Pandas)中的資料框架的啟發,但是從底層開始設計以支援現代大資料和資料科學應用程式。作為現有RDD API的擴充套件,DataFrame具有以下功能:

  • 能夠從單檯膝上型電腦上的千位元組資料擴充套件到大型群集上的PB級資料

  • 支援各種資料格式和儲存系統

  • 透過Spark SQL Catalyst最佳化器實現最先進的最佳化和程式碼生成

  • 透過Spark無縫整合所有大資料工具和基礎架構

  • Python,Java,Scala和R的API(透過SparkR開發)

  • 對於熟悉其他程式語言資料框架的新使用者,此API應該讓他們感到賓至如歸。對於現有的Spark使用者,此擴充套件API將使Spark更易於程式設計,同時透過智慧最佳化和程式碼生成來提高效能。

透過DataFrame與Catalyst最佳化器,現有的Spark程式遷移到DataFrame時效能得到改善。由於最佳化器生成用於執行的JVM位元組碼,因此Python使用者將體驗到與Scala和Java使用者相同的高效能。


圖片描述

performance.png

建立DataFrame

Spark中有兩種方式可以將資料從RDD轉化為DataFrame:反射推斷或者程式設計指定。反射推斷是Spark應用程式自動識列的型別,然後透過Spark SQL將行物件的RDD轉換為DataFrame。程式設計指定則是在執行之前,人工從Spark SQL中引入資料型別分配給不同的列。

使用資料結構:

圖片描述

data


普通讀取csv為DataFrames資料。

# 讀取csv為DataFrametraffic = spark.read.csv('E:DocumentsDesktopdata.csv', header='true')# 建立臨時表traffic.createOrReplaceTempView("traffic")# 顯示前10行traffic.show(10)

圖片描述

show

列印表結構,可以看出Spark自動將所有列推斷為string,這不是我們想要的型別。

traffic.printSchema()

圖片描述

schema

透過pandas輔助讀取csv。

import pandas as pd 

df = pd.read_csv('E:DocumentsDesktopdata.csv') 
traffic = spark.createDataFrame(df)
traffic.createOrReplaceTempView("traffic")
traffic.printSchema()

圖片描述

schema

反射推斷

traffic = spark.read.csv('E:DocumentsDesktopdata.csv', header='true', inferSchema='true')
traffic.createOrReplaceTempView("traffic")
traffic.show(10)
traffic.printSchema()

inferSchema屬性用來指示是否使用自動推斷,預設為False。

圖片描述

schema

程式設計指定

儘管自動推斷比較方便,如果啟用了inferSchema,則函式將資料全部讀入以確定輸入模式。要避免遍歷整個資料一次,應該使用模式明確指定模式。

StructField(field, data_type=None, nullable=True, metadata=None)

  • field – Either the name of the field or a StructField object

  • data_type – If present, the DataType of the StructField to create

  • nullable – Whether the field to add should be nullable (default True)

  • metadata – Any additional metadata (default None)

from pyspark.sql.types import *# 指定DataFrame每個列的模式schema = StructType([... StructField("detectorid", IntegerType()),... StructField("starttime",StringType()),... StructField("volume", IntegerType()),... StructField("speed", FloatType()),... StructField("occupancy", FloatType())])# 使用指定模式讀入traffic = spark.read.csv('E:DocumentsDesktopdata.csv', header='true', schema=schema)
traffic.createOrReplaceTempView("traffic")
traffic.show(10)
traffic.printSchema()

圖片描述

schema

DataFrame查詢

常用API

select()
投影一組表示式並返回一個新的DataFrame。
引數:cols - 列名稱(字串)或表示式(列)的列表。 如果其中一個列名是'*',則該列將展開以包含當前DataFrame中的所有列。

>>> traffic.select("speed").show(5)
+-----+|speed|+-----+|56.52||53.54||54.64||54.94||51.65|+-----+
only showing top 5 rows

filter()
使用給定的條件過濾行。where()是filter()的別名。
引數:condition - 型別的一列.BooleanType或一個SQL表示式的字串。

>>> traffic.filter(traffic.speed > 50).show(5)
+----------+--------------+------+-----+---------+|detectorid|     starttime|volume|speed|occupancy|+----------+--------------+------+-----+---------+|    100625|2015/12/1 0:00|    48|56.52|     1.29||    100625|2015/12/1 0:15|    50|53.54|     1.48||    100625|2015/12/1 0:30|    25|54.64|     0.62||    100625|2015/12/1 0:45|    34|54.94|     0.85||    100625|2015/12/1 1:00|    23|51.65|      0.6|+----------+--------------+------+-----+---------+
only showing top 5 rows>>> traffic.where(traffic.volume > 50).show(5)
+----------+--------------+------+-----+---------+|detectorid|     starttime|volume|speed|occupancy|+----------+--------------+------+-----+---------+|    100625|2015/12/1 3:45|    61|57.62|     1.65||    100625|2015/12/1 4:00|    69| 56.7|     1.89||    100625|2015/12/1 4:15|    94|56.53|     2.69||    100625|2015/12/1 4:30|    87|55.53|     2.58||    100625|2015/12/1 4:45|   161|55.51|     4.62|+----------+--------------+------+-----+---------+
only showing top 5 rows

drop()
返回刪除指定列的新DataFrame。
引數:cols - 要刪除的列的字串名稱,要刪除的列或要刪除的列的字串名稱的列表。

>>> traffic.drop("speed").show(5)
+----------+--------------+------+---------+|detectorid|     starttime|volume|occupancy|
+----------+--------------+------+---------+
|    100625|2015/12/1 0:00|    48|     1.29||    100625|2015/12/1 0:15|    50|     1.48|
|    100625|2015/12/1 0:30|    25|     0.62||    100625|2015/12/1 0:45|    34|     0.85|
|    100625|2015/12/1 1:00|    23|      0.6|+----------+--------------+------+---------+
only showing top 5 rows

cache()
使用預設儲存級別(MEMORY_AND_DISK)持久儲存DataFrame。

traffic.cache()

collect()
以Row列表形式返回所有記錄。

traffic.collect()

show()
將前n行列印到控制檯。
引數:
n - 要顯示的行數。
truncate - 如果設定為True,則預設截斷超過20個字元的字串。 如果設定為大於1的數字,則截斷長字串以截斷長度並將其右對齊。

>>> traffic.show(5)
+----------+--------------+------+-----+---------+|detectorid|     starttime|volume|speed|occupancy|+----------+--------------+------+-----+---------+|    100625|2015/12/1 0:00|    48|56.52|     1.29||    100625|2015/12/1 0:15|    50|53.54|     1.48||    100625|2015/12/1 0:30|    25|54.64|     0.62||    100625|2015/12/1 0:45|    34|54.94|     0.85||    100625|2015/12/1 1:00|    23|51.65|      0.6|+----------+--------------+------+-----+---------+
only showing top 5 rows

count()
返回此DataFrame中的行數。

>>> traffic.count()17814

columns
以列表形式返回所有列名稱。

>>> traffic.columns
['detectorid', 'starttime', 'volume', 'speed', 'occupancy']

dtypes
將所有列名稱及其資料型別作為列表返回。

>>> traffic.dtypes
[('detectorid', 'int'), ('starttime', 'string'), ('volume', 'int'), ('speed', 'double'), ('occupancy', 'double')]

fillna()
替換的空值,別名na.fill()

引數:
value - int,long,float,string或dict。 用來替換空值的值。 如果值是字典,則子集將被忽略,並且值必須是從列名(字串)到替換值的對映。 替換值必須是int,long,float,boolean或string。
子集 - 要考慮的列名稱的可選列表。 子集中指定的不具有匹配資料型別的列將被忽略。 例如,如果value是一個字串,並且子集包含一個非字串列,則非字串列將被忽略。

>>> traffic.na.fill(10)>>> traffic.na.fill({'volume': 0, 'speed': '0'})

corr()
以雙精度值計算DataFrame的兩列的相關性。 目前只支援Pearson Correlation Coefficient。 DataFrame.corr()和DataFrameStatFunctions.corr()是彼此的別名。

引數:
col1 - 第一列的名稱
col2 - 第二列的名稱
方法 - 相關方法。 目前只支援“Pearson”

>>> traffic.corr("volume", "speed")
-0.588695158526705

cov()
計算給定列的樣本協方差(由它們的名稱指定)作為雙精度值。 DataFrame.cov()和DataFrameStatFunctions.cov()是別名。

引數:
col1 - 第一列的名稱
col2 - 第二列的名稱

>>> traffic.cov("volume", "speed")
-1166.285227777989

describe()
計算數字和字串列的統計資訊。
這包括count,mean,stddev,min和max。 如果未給出列,則此函式將計算所有數字或字串列的統計資訊。

>>> df.describe().show()
+-------+--------------+--------------+------------------+------------------+------------------+|summary|    detectorid|     starttime|            volume|             speed|         occupancy|
+-------+--------------+--------------+------------------+------------------+------------------+
|  count|         17814|         17814|             17814|             17737|             17814||   mean|      100627.5|          null|208.72779836083978| 45.94760105993146|13.775621421354007|
| stddev|1.707873064514|          null|  129.673023730382|15.010086497913619|13.391984211880049||    min|        100625|2015/12/1 0:00|                 0|              1.14|               0.0|
|    max|        100630|2015/12/9 9:45|               528|             69.33|             73.25|+-------+--------------+--------------+------------------+------------------+------------------+>>> traffic.describe(['speed']).show()
+-------+------------------+|summary|             speed|
+-------+------------------+
|  count|             17737||   mean| 45.94760105993146|
| stddev|15.010086497913619||    min|              1.14|
|    max|             69.33|+-------+------------------+

distinct()
返回包含此DataFrame中不同行的新DataFrame。

>>> traffic.distinct().count()17814

createOrReplaceGlobalTempView()
使用給定名稱建立或替換全域性臨時檢視。
此臨時檢視的生命週期與此Spark應用程式相關聯。

>>> traffic.createOrReplaceGlobalTempView("traffic")>>> df = spark.sql("select * from traffic")>>> df.count()17814

createOrReplaceTempView()
使用此DataFrame建立或替換本地臨時檢視。
此臨時表的生命週期與用於建立此DataFrame的SparkSession相關聯。

>>> traffic.createOrReplaceTempView("traffic")>>> df = spark.sql("select * from traffic")>>> df.count()17814

使用SQL查詢

由於建立了臨時表,我們可以對臨時表執行sql操作。

>>> spark.sql("select * from traffic where volume > 50 and speed > 50").show()
+----------+---------------+------+-----+---------+|detectorid|      starttime|volume|speed|occupancy|+----------+---------------+------+-----+---------+|    100625| 2015/12/1 3:45|    61|57.62|     1.65||    100625| 2015/12/1 4:00|    69| 56.7|     1.89||    100625| 2015/12/1 4:15|    94|56.53|     2.69||    100625| 2015/12/1 4:30|    87|55.53|     2.58||    100625| 2015/12/1 4:45|   161|55.51|     4.62||    100625| 2015/12/1 5:00|   203|55.41|     5.96||    100625| 2015/12/1 5:15|   185|55.14|     6.61||    100625| 2015/12/1 5:30|   308|52.39|     9.87||    100625| 2015/12/1 5:45|   343|51.01|    11.49||    100625|2015/12/1 10:15|   306| 50.6|    11.98||    100625|2015/12/1 10:30|   334|51.42|    11.53||    100625|2015/12/1 10:45|   349|52.67|    11.51||    100625|2015/12/1 11:00|   262|52.36|    10.54||    100625|2015/12/1 12:00|   255|52.47|     9.36||    100625|2015/12/1 12:15|   346|50.25|    13.44||    100625|2015/12/1 12:30|   367| 51.2|    12.47||    100625|2015/12/1 12:45|   330|52.78|    11.56||    100625|2015/12/1 13:00|   306|52.36|    12.01||    100625|2015/12/1 13:30|   371|50.28|    13.93||    100625|2015/12/1 13:45|   294|50.62|    12.92|+----------+---------------+------+-----+---------+
only showing top 20 rows

Dataset

除了DataFrame,Spark 1.6中還引入了Dataset API,其提供了一種型別安全的物件導向的程式設計介面,但是其只能在Java與Scala中使用。Python不能使用該API的原因是因為其本身不是一種型別安全的語言。在Spark 2.0中DataFrame API被整合入如Dataset API,DataFrame是Dataset未型別化API的一個別名。

未型別化的API:DataFrame = Dataset[Row]
型別化的API:Dataset[T]



作者:洛荷
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3486/viewspace-2818646/,如需轉載,請註明出處,否則將追究法律責任。

相關文章