spark- Dataframe基本操作-查询

前言: DataFrame需要重点关注的是如何取使用,利用DataFrame来解决实际业务中的数据问题。熟练掌握DataFrame的各种api的使用就像相当于手握一把非常重要且高效的利器,实际数据工程可以大量的被用到。 本文是对DataFrame概念和过去实际工作中用到过的DataFrame中关于数据查看的一个回忆性总结。

目录

DataFrame概念(了解即可) 

DataFrame的优点(了解即可)

查询相关操作

.show() 显示头n 行

.printSchema()  打印表概要,

.count()  查询统计表中数据行数 

.distinct() 行去重和.dropDuplicates按指定列去重

.limit() 获取前n行并得到新的DataFrame 

.collect()  获取所有数据到数组

.head(num) 以及.take(num)  获取前num行记录

.sample() 采样

.select() 选择列数据

.selectExpr() 选择数据

.unionByName 两个DataFrame根据列名进行合并。  

.describe() 查看数据的统计分布

.summary统计数据分布

withColumn中,df.column.cast('type')数据类型转换



DataFrame概念(了解即可) 

  • DataFrame是从Spark 1.3版本开始引入的。从Spark 2.0开始,DataFrame和DataSet的API合并在一起,实现了跨库统一成为一套API。这样,开发人员的学习成本就降低了。只需要学习一个High Level的、类型安全的DataSet API就可以了
  • 通过DataFrame可以简化Spark程序的开发,让Spark处理结构化数据变得更简单。DataFrame可以使用SQL的方式来处理数据。例如:业务分析人员可以基于编写Spark SQL来进行数据开发,而不仅仅是Spark开发人员。
  • DataFrame和RDD有一些共同点,也是不可变的分布式数据集。但与RDD不一样的是,DataFrame是有schema的,有点类似于关系型数据库中的,每一行的数据都是一样的,因为。有了schema,这也表明了DataFrame是比RDD提供更高层次的抽象。
  • DataFrame支持各种数据格式的读取和写入,例如:CSV、JSON、AVRO、HDFS、Hive表。
  • DataFrame底层使用Catalyst进行优化。

DataFrame的优点(了解即可)

  • 因为DataFrame是有统一的schema的,所以序列化和反序列无需存储schema。这样节省了一定的空间。
  • DataFrame存储在off-heap(堆外内存)中,由操作系统直接管理(RDD是JVM管理),可以将数据直接序列化为二进制存入off-heap中。操作数据也是直接操作off-heap。

查询相关操作

样例数据,简单建一个DataFrame 

sc = spark.sparkContext 
# 创建一个SparkDataFrame
rdd = sc.parallelize([("Sam", 28, 88, "M"),
                      ("Flora", 28, 90, "F"),
                      ("Run", 1, 60, None),
                      ("Peter", 55, 100, "M"),
                      ("Mei", 54, 95, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"]) # 创建DataFrame的一种方式,用rdd.toDF 来建

.show() 显示头n 行

DataFrame.show( num)  以表格的形式显示头num行,函数返回值为NoneType 。 

tmp = test_exp_data.show(5)
print(type(tmp)) # 返回结果为 <class 'NoneType'>.
输出:
+-----+---+-----+----+
| name|age|score| sex|
+-----+---+-----+----+
|  Sam| 28|   88|   M|
|Flora| 28|   90|   F|
|  Run|  1|   60|null|
|Peter| 55|  100|   M|
|  Mei| 54|   95|   F|
+-----+---+-----+----+

<class 'NoneType'>

.printSchema()  打印表概要,

以树的形式显示表中各个列的数据结构 ,返回类型为None

print(test_exp_data.printSchema())

输出:

root
 |-- name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- score: long (nullable = true)
 |-- sex: string (nullable = true)

也可以直接输出,不用括号,也不会报错如

print(test_exp_data.printSchema)

.count()  查询统计表中数据行数 

返回一个int类型结果值 

print(test_exp_data.count())
tmp  = test_exp_data.count()
print(type(tmp)) # <class 'int'>

输出: 

5
<class 'int'>

.distinct() 行去重和.dropDuplicates按指定列去重

.distinct() 去掉重复的行,只保留第一次出现的行,得到不同的行,返回类型为DataFrame

### 去重
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
                      ("Flora", 28, 90.55, "F"),
                      ("Flora", 28, 90.55, "F"),
                      ("Flora", 45, 99.5, "F"),
                      ("Mey", 1, None, "M"),
                      ("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
#test_exp_data.show()
### .distinct()对数据集去重,去掉重复的行
test_exp_data.distinct().show()

结果: 

+-----+---+-----+---+
| name|age|score|sex|
+-----+---+-----+---+
|  Sam| 28|88.52|  M|
|Flora| 28|90.55|  F|
|Flora| 45| 99.5|  F|
|  Mey|  1| null|  M|
|Chery|  7|80.23|  F|
+-----+---+-----+---+

.dropDuplicates按指定列去重

.dropDuplicates 按指定列去重,#对于改列的不同值,只保留在第一次出现的行 
test_exp_data.dropDuplicates(['sex']).show() 

结果: 

+-----+---+-----+---+
| name|age|score|sex|
+-----+---+-----+---+
|Flora| 28|90.55|  F|
|  Sam| 28|88.52|  M|
+-----+---+-----+---+

.limit() 获取前n行并得到新的DataFrame 

limit方法获取指定DataFrame的前n行记录,得到一个新的DataFrame对象。

tmp = test_exp_data.limit(4)
print(type(tmp)) # DataFrame
tmp.show(2)

输出 

<class 'pyspark.sql.dataframe.DataFrame'>
+-----+---+-----+---+
| name|age|score|sex|
+-----+---+-----+---+
|  Sam| 28|   88|  M|
|Flora| 28|   90|  F|
+-----+---+-----+---+

.collect()  获取所有数据到数组

不同于前面的show方法,这里的collect方法会将DF中的所有数据都获取到,并返回一个list。

print(test_exp_data.collect())
tmp= test_exp_data.collect()
print(type(tmp))

输出: 

[Row(name='Sam', age=28, score=88, sex='M'), Row(name='Flora', age=28, score=90, sex='F'), Row(name='Run', age=1, score=60, sex=None), Row(name='Peter', age=55, score=100, sex='M'), Row(name='Mei', age=54, score=95, sex='F')]
<class 'list'>

.head(num) 以及.take(num)  获取前num行记录

两个函数功能都是获取前num行记录汇总到一个list中。list中的每个元素都是一个row结构。

tmp = test_exp_data.head(3)
print(tmp)
print(type(tmp))  ## list 
print(type(tmp[0]))

tmp = test_exp_data.take(3)
print(tmp)
print(type(tmp))  # <class 'list'>
print(type(tmp[0]))

输出: 

[Row(name='Sam', age=28, score=88, sex='M'), Row(name='Flora', age=28, score=90, sex='F'), Row(name='Run', age=1, score=60, sex=None)]
<class 'list'>
<class 'pyspark.sql.types.Row'>

另一个输出完全一模一样。 

.sample() 采样

df.sample(fraction=float_num) ,按fraction比例对行进行随机采样

print(test_exp_data.count())
samp = test_exp_data.sample(fraction=0.5)
print(samp.count())

输出:

5
3

.select() 选择列数据

选择的列数据构成一个新的dataframe返回。 可以有如下三种表示方法来选 。且都可以进行数据运算。 

test_exp_data.select("name").show(1)
test_exp_data.select(test_exp_data.name).show(1)
test_exp_data.select(test_exp_data['name']).show(1)

都是输出:

+----+
|name|
+----+
| Sam|
+----+

选择多列的表示方式。注意第一种如果是单独只有列名时需要用list拼起来

test_exp_data.select(["name",'score']).show(1) # 选择多个列,可以是由string类型列名组成的list。注意要用list表示
test_exp_data.select(test_exp_data.name,test_exp_data.score).show(1) #也可以是df中逐个带着列名
test_exp_data.select(test_exp_data["name"],test_exp_data["score"]).show(1) #也可以是df中逐个带着列名

都是输出

+----+-----+
|name|score|
+----+-----+
| Sam|   88|
+----+-----+

另外,可以基于某列直接进行数据运算(数据类型要为非string) 

test_exp_data.select(test_exp_data["name"],test_exp_data["score"]+1).show(1) # df中逐个带着列的数据还可以进行运算操作
test_exp_data.select(test_exp_data.name,test_exp_data.score+1).show(1)

.selectExpr() 选择数据

selectExpr() 也可以选择数据并进行更加复杂的数据处理,直接选择的语句中就处理了。selectExpr方法本质与select方法中使用expr函数是一样的,可以直接对指定字段调用UDF函数,或者指定别名等。传入String类型参数,得到DataFrame对象。

如下实例:里面用as 重命名、用round四舍五入并指定保留小数位; 

# 创建一个SparkDataFrame
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
                      ("Flora", 28, 90.55, "F"),
                      ("Run", 1, 60, None),
                      ("Peter", 55, 100, "M"),
                      ("Mei", 54, 95, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.selectExpr('name as new_name','round(score)','round(score,1)').show(3) # 第一个处理是起新命名,第二个是直接调用round函数进行四舍五入处理默认不保留小数位,第三个是保留一位小数

输出: 

+--------+---------------+---------------+
|new_name|round(score, 0)|round(score, 1)|
+--------+---------------+---------------+
|     Sam|           89.0|           88.5|
|   Flora|           91.0|           90.5|
|     Run|           null|           null|
+--------+---------------+---------------+

.unionByName 两个DataFrame根据列名进行合并。  

rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
                      ("Flora", 28, 90.55, "F"),
                      ("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.show()#df1 

+-----+---+-----+---+
| name|age|score|sex|
+-----+---+-----+---+
|  Sam| 28|88.52|  M|
|Flora| 28|90.55|  F|
|Chery|  7|80.23|  F|
+-----+---+-----+---+

rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
                      ("Flora", 28, 90.55, "F"),
                      ("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.show()# df2

+---+------+-----+---+
|age|  name|score|sex|
+---+------+-----+---+
|  7|Chery2|80.23|  F|
| 28|  Sam2|88.52|  M|
+---+------+-----+---+

## 两个df 根据列名进行合并
merge = test_exp_data.unionByName(test2).show()

结果: 

+------+---+-----+---+
|  name|age|score|sex|
+------+---+-----+---+
|   Sam| 28|88.52|  M|
| Flora| 28|90.55|  F|
| Chery|  7|80.23|  F|
|Chery2|  7|80.23|  F|
|  Sam2| 28|88.52|  M|
+------+---+-----+---+

.describe() 查看数据的统计分布

返回关于列的统计分布(个数统计count、数值均值mean、标准差stddev、最小值min、最大值max),结果展现形式为dataframe类型,可以用show查看。注意字符串类型的列并不会报错!且Min 和max会按照字典序进行排序 。

对于pyspark的dataframe的describe函数并不能统计出对应的分位数,如果想统计对应的百分位数,可以转换为pandas的dataframe后再通过参数percentiles去统计。 

rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
                      ("Flora", 28, 90.55, "F"),
                      ("Mey", 1, None, "M"),
                      ("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.describe().show()

输出:

+-------+-----+------------------+-----------------+----+
|summary| name|               age|            score| sex|
+-------+-----+------------------+-----------------+----+
|  count|    4|                 4|                3|   4|
|   mean| null|              16.0|86.43333333333334|null|
| stddev| null|14.071247279470288|5.467287566365362|null|
|    min|Chery|                 1|            80.23|   F|
|    max|  Sam|                28|            90.55|   M|
+-------+-----+------------------+-----------------+----+

也可以选择某列单独进行统计

test_exp_data.select('score').describe().show()

想统计百分位数,.toPandas().describe(percentiles=[....])

test_exp_data.toPandas().describe(percentiles=[0.0,0.01,0.2,0.5,0.90,1.0])
             age      score
count   4.000000   3.000000
mean   16.000000  86.433333
std    14.071247   5.467288
min     1.000000  80.230000
0%      1.000000  80.230000
1%      1.180000  80.395800
20%     4.600000  83.546000
50%    17.500000  88.520000
90%    28.000000  90.144000
100%   28.000000  90.550000
max    28.000000  90.550000

关于百分位数的概念:第p百分位数(p%分位数)值满足:有p%的观察值小于或等于该值,至少有(100-p)%的观察值大于或等于该值。注意0%分位数是这组值中的最小值,100%分位数是这组值中的最大值。

 分位数的概念如

.summary统计数据分布

功能类似describe,多了25%,50%,75%分位数,结果返回仍然是一个dataframe

test_exp_data.summary().show()

结果显示: 

+-------+------------------+-----------------+
|summary|               age|            score|
+-------+------------------+-----------------+
|  count|                 4|                3|
|   mean|              16.0|86.43333333333334|
| stddev|14.071247279470288|5.467287566365362|
|    min|                 1|            80.23|
|    25%|                 1|            80.23|
|    50%|                 7|            88.52|
|    75%|                28|            90.55|
|    max|                28|            90.55|
+-------+------------------+-----------------+

withColumn中,df.column.cast('type')数据类型转换

如: flash_res = flash_res.withColumn("label_float",flash_res.label.cast('float'))

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 1. Spark SQL RDD基本操作Spark SQL RDD是一种分布式数据集,可以通过Spark SQL API进行操作。基本操作包括创建RDD、转换RDD、持久化RDD、计算RDD等。可以使用Spark SQL RDD API中的函数进行操作,如map、filter、reduce等。 2. RDD-DataFrame:RDD和DataFrameSpark SQL中的两种数据结构。RDD是弹性分布式数据集,而DataFrame是一种结构化数据集。可以通过将RDD转换为DataFrame来进行数据分析和处理。可以使用Spark SQL中的API将RDD转换为DataFrame,如toDF、createDataFrame等。 3. API MySQL:API MySQL是一种用于访问MySQL数据库的应用程序接口。可以使用API MySQL来连接MySQL数据库并进行数据操作,如查询、插入、更新、删除等。在Spark SQL中,可以使用API MySQL来读取和写入MySQL数据库中的数据。可以使用Spark SQL中的API来连接MySQL数据库,如JDBC、ODBC等。 ### 回答2: Spark SQL中RDD是一种基础数据结构,它是Resilient Distributed Dataset的简称,即弹性分布式数据集。RDD具有不可变性、分区性和良好的容错性,可以通过多种方式创建。RDD的基本操作包括转换操作和行动操作。转换操作是指基于源数据生成一个新的RDD,而不改变源数据。常见的转换操作包括map、filter和reduceByKey等。行动操作是指触发数据的计算并返回结果。常见的行动操作包括collect、count和reduce等。RDD的优势在于能够在内存中处理海量数据,提高处理速度和效率。 RDD与DataFrameSpark SQL的两种核心数据结构。DataFrame是一个二维表格式的数据集合,可以通过多种方式创建,包括从RDD转换而来、读取外部数据源等。与RDD相比,DataFrame有更丰富的API支持和更高的性能优化,同时也提供了SQL查询等类似于关系型数据库的操作。DataFrame基本操作包括列选择、过滤、聚合等。 在使用Spark SQL时,还需要连接外部数据源进行数据读取和写入。常见的外部数据源包括MySQL等关系型数据库。Spark SQL可以通过多种方式连接MySQL,包括使用JDBC和使用DataFrame API。使用JDBC需要在代码中明确连接MySQL的URL、用户名和密码等信息,使用DataFrame API可以通过定义schema和指定数据源路径等方式进行数据读取和写入。连接MySQL需要注意代码的安全性和性能问题。 综上所述,Spark SQL中RDD、DataFrame和连接外部数据源的API都是使用Spark进行大数据处理的重要组成部分。熟练掌握这些基本操作和API可以提高数据分析和处理的效率和可靠性。 ### 回答3: Spark SQL RDD基本操作Spark SQL中,RDD操作是非常基础且非常重要的。Spark SQL RDD的操作可以通过直接调用RDD的API实现,常见的RDD操作有filter、map、reduce等。 1. filter:用于筛选符合条件的元素,过滤掉其余的元素。例如,过滤并输出RDD中包含“spark”的元素: rdd.filter(lambda x: "spark" in x).collect() 2. map:用于将每个元素按照一定的规则进行映射,例如将RDD中的每个元素都变成大写: rdd.map(lambda x: x.upper()).collect() 3. reduce:用于按照规定的操作对RDD进行迭代归约,例如对RDD中的元素进行相加求和: rdd.reduce(lambda x, y: x+y) RDD-DataFrame Spark SQL支持RDD与DataFrame的相互转换。RDD是Spark的最基本数据结构之一,DataFrame是一种用于处理结构化数据的API,基于RDD开发而成。 使用RDD创建DataFrame,需要先将RDD映射为Row类型,再通过StructType定义的schema将Row映射为DataFrame。例如: from pyspark.sql import Row from pyspark.sql.types import StructType, StructField, StringType rdd = sc.parallelize([(1, "John"), (2, "Andy"), (3, "Smith")]) row_rdd = rdd.map(lambda x: Row(id=x[0], name=x[1])) schema = StructType([StructField("id", StringType(), True), StructField("name", StringType(), True)]) df = spark.createDataFrame(row_rdd, schema) 使用DataFrame创建RDD,可以使用rdd属性直接将DataFrame转换为RDD。例如: rdd = df.rdd API MySQL Spark SQL可以通过连接MySQL数据库获取数据并进行处理,有两种方法:JDBC和Spark SQL官方提供的DataFrame API。使用JDBC需要先进行MySQL的配置,然后通过JDBC连接到MySQL数据库并读取数据,例如: from pyspark.sql import SparkSession spark = SparkSession.builder.appName("MySQLRead").getOrCreate() url = "jdbc:mysql://localhost:3306/mydatabase" properties = {"user": "root", "password": "xxx"} query = "(select * from mytable) as mytable" df = spark.read.jdbc(url=url, table=query, properties=properties) 而使用Spark SQL官方提供的DataFrame API,可以使用read.format连同jdbc并指定数据库地址、用户名、密码等参数,例如: from pyspark.sql import SparkSession spark = SparkSession.builder.appName("MySQLRead").getOrCreate() df = spark.read.format("jdbc"). \ option("url", "jdbc:mysql://localhost:3306/mydatabase"). \ option("user", "root"). \ option("password", "xxx"). \ option("dbtable", "(select * from mytable) as mytable"). \ load() 两种方法均可以完成对MySQL数据库的读取和数据处理。 总结 Spark SQL的RDD操作、RDD-DataFrame转换以及MySQL API均为Spark SQL的基本操作。可以利用这些基本操作实现Spark SQL中的数据处理、计算和分析等功能。同时,Spark SQL还提供了丰富的API和函数库,可以根据具体需求在其基础上进行拓展和应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值