草庐IT

对比Pandas,学习PySpark大数据处理

云朵君 2023-03-28 原文
​常有优势的技能。如果你已经熟悉运用 Python 和 pandas 做常规数据处理,并且想学习处理大数据,那么熟悉 PySpark,并将用其做数据处理,将会是一个不错的开始。PySpark是一种适用于 Apache Spark 的 Python API,一种流行的大数据开源数据处理引擎。

本文的前提是,假设读者在 Python 中熟练使用 pandas 操作数据。

数据集

从导包开始。在 PySpark 中,需要创建一个 Spark 会话 SparkSession。创建 Spark 会话后,可以从以下位置访问 Spark Web 用户界面 (Web UI):http://localhost:4040/。下面定义的应用程序名称appName为“PyDataStudio”,将显示为 Web UI 右上角的应用程序名称。本文将不会使用 Web UI,但是,如果您有兴趣了解更多信息,请查看官方文档[1]。

import pandas as pd
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('PyDataStudio').getOrCreate()

我们将在这篇文章中使用企鹅数据集[2]。使用下面的脚本,我们将penguins.csv数据的修改版本保存在工作目录中。

from seaborn import load_dataset
(load_dataset('penguins')
.drop(columns=['bill_length_mm', 'bill_depth_mm'])
.rename(columns={'flipper_length_mm': 'flipper',
'body_mass_g': 'mass'})
.to_csv('penguins.csv', index=False))

看一下两个库之间的语法比较。为了简洁,我们仅保留显示 PySpark 输出。

基本使用

两个库的数据对象都称为 DataFrame:pandas DataFrame vs PySpark DataFrame。

导入数据并检查其形状

# pandas
df = pd.read_csv('penguins.csv')
df.shape
# PySpark
df = spark.read.csv('penguins.csv', header=True, inferSchema=True)
df.count(), len(df.columns)
(344, 5)
使用 PySpark 导入数据时,指定header=True​数据类型用第一行作标题,并设置inferSchema=True​。可以尝试不使用这些选项导入并检查 DataFrame 及其数据类型(类似于 pandas 使用df.dtype 检查 PySpark DataFrames 的数据类型)。

与 pandas DataFrame 不同,PySpark DataFrame 没有像.shape可以直接查看数据的形状。所以要得到数据形状,我们分别求行数和列数。

检查有关数据的高级信息

# pandas
df.info()
# PySpark
df.printSchema()
root
|-- species: string (nullable = true)
|-- island: string (nullable = true)
|-- flipper: double (nullable = true)
|-- mass: double (nullable = true)
|-- sex: string (nullable = true)
虽然此方法不会提供与df.info()相同的输出,但它是最接近的内置方法之一。

查看数据的前几行

# pandas
df.head()
# PySpark
df.show(5)
+-------+---------+-------+------+------+
|species| island|flipper| mass| sex|
+-------+---------+-------+------+------+
| Adelie|Torgersen| 181.0|3750.0| Male|
| Adelie|Torgersen| 186.0|3800.0|Female|
| Adelie|Torgersen| 195.0|3250.0|Female|
| Adelie|Torgersen| null| null| null|
| Adelie|Torgersen| 193.0|3450.0|Female|
+-------+---------+-------+------+------+
only showing top 5 rows
默认情况下,df.show()​默认显示前 20 行。PySpark DataFrame 实际上有一个名为.head()​的方法,可以查看前几行的数据,并以row对象形式打印出。运行df.head(5)提供如下输出:

df.head(5)

.show()​方法的输出更简洁,因此在查看数据集的top行时用.show()。

选择列

# pandas
df[['island', 'mass']].head(3)
# PySpark
df[['island', 'mass']].show(3)
+---------+------+
| island| mass|
+---------+------+
|Torgersen|3750.0|
|Torgersen|3800.0|
|Torgersen|3250.0|
+---------+------+
only showing top 3 rows
虽然可以在这里使用的是类似于 pandas 的语法,而在 PySpark 中默认使用如下代码片段所示的方法选择列:

df.select('island', 'mass').show(3)
df.select(['island', 'mass']).show(3)

过滤

根据条件过滤数据

# pandas
df[df['species']=='Gentoo'].head()
# PySpark
df[df['species']=='Gentoo'].show(5)
+-------+------+-------+------+------+
|species|island|flipper| mass| sex|
+-------+------+-------+------+------+
| Gentoo|Biscoe| 211.0|4500.0|Female|
| Gentoo|Biscoe| 230.0|5700.0| Male|
| Gentoo|Biscoe| 210.0|4450.0|Female|
| Gentoo|Biscoe| 218.0|5700.0| Male|
| Gentoo|Biscoe| 215.0|5400.0| Male|
+-------+------+-------+------+------+
only showing top 5 rows
两个库之间的语法几乎相同。要获得相同的输出,还可以使用:

df.filter(df['species']=='Gentoo').show(5) df.filter("species=='Gentoo'").show(5)
下面显示了一些常见的过滤器比较:

# pandas
df[df['species'].isin(['Chinstrap', 'Gentoo'])].head()
df[df['species'].str.match('G.')] .head()
df[df['flipper'].between(225,229)].head()
df[df['mass'].isnull()].head()1b df.loc[df['species']!='Gentoo'].head()
df[~df['species'].isin(['Chinstrap', 'Gentoo'])].head()
df[-df['species'].str.match('G.')].head()
df[~df['flipper'].between(225,229)].head()
df[df['mass'].notnull()].head()6 df[(df['mass']<3400) & (df['sex']=='Male')].head()
df[(df['mass']<3400) | (df['sex']=='Male')].head()

# PySpark
df[df['species'].isin(['Chinstrap', 'Gentoo'])].show(5)
df[df['species'].rlike('G.')].show(5)
df[df['flipper'].between(225,229)].show(5)
df[df['mass'].isNull()].show(5)1b df[df['species']!='Gentoo'].show(5)
df[~df['species'].isin(['Chinstrap', 'Gentoo'])].show(5)
df[~df['species'].rlike('G.')].show(5)
df[~df['flipper'].between(225,229)].show(5)
df[df['mass'].isNotNull()].show(5)
df[(df['mass']<3400) & (df['sex']=='Male')].show(5)
df[(df['mass']<3400) |(df[ 'sex']=='Male')].show(5)
虽然~和-​在 pandas 中都可以作为否定,但在 PySpark 中仅有~能作为有效的否定。

排序

对数据进行排序并检查mass最小的 5 行:

# pandas
df.nsmallest(5, 'mass')
# PySpark
df[df['mass'].isNotNull()].orderBy('mass').show(5)
+---------+------+-------+------+------+
| species|island|flipper| mass| sex|
+---------+------+-------+------+------+
|Chinstrap| Dream| 192.0|2700.0|Female|
| Adelie|Biscoe| 184.0|2850.0|Female|
| Adelie|Biscoe| 181.0|2850.0|Female|
| Adelie|Biscoe| 187.0|2900.0|Female|
| Adelie| Dream| 178.0|2900.0|Female|
+---------+------+-------+------+------+
only showing top 5 rows
Pandas的.nsmallest()和.nlargest()​方法会自动排除缺失值。而 PySpark 没有等效的方法。为了获得相同的输出,首先过滤掉缺失mass的行,然后对数据进行排序并查看前 5 行。如果没有删除数据,可以简写为:

df.orderBy(‘mass’).show(5).sort()
代替的另一种排序方式.orderBy():

# pandas
df.nlargest(5, 'mass')
# PySpark
df.sort('mass', ascending=False).show(5)
+-------+------+-------+------+----+
|species|island|flipper| mass| sex|
+-------+------+-------+------+----+
| Gentoo|Biscoe| 221.0|6300.0|Male|
| Gentoo|Biscoe| 230.0|6050.0|Male|
| Gentoo|Biscoe| 220.0|6000.0|Male|
| Gentoo|Biscoe| 222.0|6000.0|Male|
| Gentoo|Biscoe| 229.0|5950.0|Male|
+-------+------+-------+------+----+
only showing top 5 rows
这些语法的变体也是等效的:

df.sort(df['mass'].desc()).show(5)
df.orderBy('mass', ascending=False).show(5)
df.orderBy(df['mass'].desc( )).show(5)
按多列排序,如下所示:

# pandas
df.sort_values(['mass', 'flipper'], ascending=False).head()
# PySpark
df.orderBy(['mass', 'flipper'], ascending=False).show(5)
+-------+------+-------+------+----+
|species|island|flipper| mass| sex|
+-------+------+-------+------+----+
| Gentoo|Biscoe| 221.0|6300.0|Male|
| Gentoo|Biscoe| 230.0|6050.0|Male|
| Gentoo|Biscoe| 222.0|6000.0|Male|
| Gentoo|Biscoe| 220.0|6000.0|Male|
| Gentoo|Biscoe| 229.0|5950.0|Male|
+-------+------+-------+------+----+
only showing top 5 rows
在 PySpark 中,可以在将所有列分别传参数,而不需要写成列表的形式

df.orderBy('mass', 'flipper', ascending=False).show(5)
要按多列但按不同方向排序:

# pandas
df.sort_values(['mass', 'flipper'], ascending=[True, False]).head()
# PySpark
df[df['mass'].isNotNull()]\
.sort('mass', 'flipper', ascending=[True, False]).show(5)
+---------+---------+-------+------+------+
| species| island|flipper| mass| sex|
+---------+---------+-------+------+------+
|Chinstrap| Dream| 192.0|2700.0|Female|
| Adelie| Biscoe| 184.0|2850.0|Female|
| Adelie| Biscoe| 181.0|2850.0|Female|
| Adelie|Torgersen| 188.0|2900.0|Female|
| Adelie| Biscoe| 187.0|2900.0|Female|
+---------+---------+-------+------+------+
only showing top 5 rows
pyspark的另一种写法

df[df['mass'].isNotNull()]\
.orderBy(df['mass'].asc(), df['flipper'].desc()).show(5)

聚合

现在,看几个聚合数据的示例。

简单的聚合

二者方法类似:

# pandas
df.agg({'flipper': 'mean'})
# PySpark
df.agg({'flipper': 'mean'}).show()
+------------------+
| avg(flipper)|
+------------------+
|200.91520467836258|
+------------------+

多个聚合

需要采用不同的方法:

# pandas
df.agg({'flipper': ['min', 'max']})
# PySpark
from pyspark.sql import functions as F
df.agg(F.min('flipper'), F.max('flipper')).show()
+------------+------------+
|min(flipper)|max(flipper)|
+------------+------------+
| 172.0| 231.0|
+------------+------------+

获取唯一值

# pandas
df['species'].unique()
# PySpark
df.select('species').distinct().show()
+---------+
| species|
+---------+
| Gentoo|
| Adelie|
|Chinstrap|
+---------+
要在列中获取多个不同的值:

# pandas
df['species'].nunique()
# PySpark
df.select('species').distinct().count()

按组聚合

到目前为止,PySpark 使用 camelCase 驼峰命名法来表示方法和函数。.groupBy()这也是如此。这是一个简单的按聚合分组的示例:

# pandas
df.groupby('species')['mass'].mean()
# PySpark
df.groupBy('species').agg({'mass': 'mean'}).show()
+---------+------------------+
| species| avg(mass)|
+---------+------------------+
| Gentoo| 5076.016260162602|
| Adelie| 3700.662251655629|
|Chinstrap|3733.0882352941176|
+---------+------------------+
这是一个聚合多个选定列的示例:

# pandas
df.groupby('species').agg({'flipper': 'sum',
'mass': 'mean'})
# PySpark
df.groupBy('species').agg({'flipper': 'sum',
'mass': 'mean'}).show()
+---------+------------+--------------+
| species|sum(flipper)| avg(mass)|
+---------+------------+--------------+
| Gentoo| 26714.0| 5076.01626016|
| Adelie| 28683.0| 3700.66225165|
|Chinstrap| 13316.0|3733.088235294|
+---------+------------+--------------+
如果我们不指定列,它将显示所有数字列的统计信息:

# pandas
df.groupby('species').mean()
# PySpark
df.groupBy('species').mean().show()
+---------+--------------+--------------+
| species| avg(flipper)| avg(mass)|
+---------+--------------+--------------+
| Gentoo| 217.186991869| 5076.01626016|
| Adelie|189.9536423841| 3700.66225165|
|Chinstrap| 195.823529411|3733.088235294|
+---------+--------------+--------------+
也可以将.mean()​替换为.avg()​,即可以使用df.groupBy(‘species’).avg().show()。

以上就是本文的所有内容,希望能够帮到你对 PySpark 语法有所了解。我们注意到,在基本任务方面,这两个库之间有很多相似之处。这使得在熟悉 pandas 工作知识的人更容易开始使用 PySpark,在处理小数据分析与挖掘后,遇到大数据分析与挖掘时,也能够轻松面对。

参考资料

[1]官方文档: https://spark.apache.org/docs/latest/web-ui.html

[2]企鹅数据集: https://github.com/mwaskom/seaborn-data/blob/master/penguins.csv

有关对比Pandas,学习PySpark大数据处理的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  4. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  5. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  6. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  7. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  8. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  9. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  10. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

随机推荐