spark SQL

1. Spark下创建Dataframe

一般是通过SparkSession 导入数据来创建的。dataframe可以通过访问文件系统或创建RDD来获得。

创建RDD来生成dataframe数据:

调用spark.read.json()方法可以实现RDD到dataframe的转换,而且是直接执行的,但是创建临时表createOrReplaceTempView() 操作只有执行到dataframe动作时,创建临时表才会执行。

2. DataFrame查询和字段类型设置

spark 中的dataframe与pandas中的dataframe具有较大的不同,spark中的dataframe除了支持api调用操作之外,还支持通过编写SQL的方法执行操作。

2.1 查询:

# 通过API查询  -->  df.show()

# 通过编写SQL查询  -->  spark.sql('select * from df').show()    可定义参数num控制返回数据大小

2.2 指定dataframe的字段类型

指定模式(手动指定) & 反推断模式(默认指定)

调用printSchema() 方法查看dataframe的数据结构;指定字段的数据类型就需要调用StructType和StructField(通过Spark Sql 来引入)

2.3 筛选查询操作

dataframe方法进行筛选,也可用SQL语句。

#使用自带的方法      student.select('age', 'name', 'id').filter('id == 1').show()

# 或者                       student.select(student.age, ​​​​​​​​​​​​​​student.id).filter(student.id==1).show()

#SQL查询                 spark.sql('select * from student where id=1').show()

2.4 查

# 查行数                           df.count()
# 取别名                           df.select(df.age.alias('age_v'),'name')
# 查询某列为null的行       from pyspark.sql.functions import isnull

                                         df = df.filter(isnull("col_a"))

#查询唯一值                    df.select('columns').distinct().show()

#获取元素列名                 Row(age=11, name='Alice').columns

#选择多列                        df["name"]  或 df.name; df.select(“name”) ;df.select(df[‘name’], df[‘age’]+1) ;

                                        df.select(df.a, df.b, df.c)  或 df.select(df["a"], df["b"], df["c"])

#select方法重载              df.select(df( "id" ), df( "id") + 1 ).show( false)    同时显示id列和id+1列

#排序                              df.orderBy(df.age.desc()).show(5)

#when和between            from pyspark.sql import functions as F

                                       df.select(df.name, F.when(df.age > 4, 1).when(df.age < 3, -1).otherwise(0)).show()

                                       df.select(df.name, df.age.between(22, 24)).show()

2.5 增

新增DataFrame

新增列       df.withColumn('Purchase_new', df.Purchase /2.0).select('Purchase','Purchase_new').show(5)

修改列名    df.withColumnRenamed( "id" , "idx" )

2.6 删——删除列、空值,填充NA,去重

#删除列        df.drop('age').collect()   或者  df.drop(df.age).collect()

#删除空值    df = df.na.drop() # 删除任何列包含na的行  ;       df = df.dropna(subset=['col1', 'col2']) # 删掉col1或col2中任一一列包含na的行

#填充NA      df.fillna(-1)

#去重          df.distinct()  #返回不包含重复行的dataframe  ;    df.select('Age','Gender').dropDuplicates().show() # 指定字段去重

3. 合并(join/union)、分割(行转列explode)、统计

join      join 操作与pandas中的merge操作相似,需要注意拼接时坐标为主还是右表为主,是内连接还是外连接。

并、交、差、去重         差集:subtract(),交集:intersect(),并集:union()就可以实现dataframe里的数据的比较。

#差集      newDF = sentenceDF1.select("sentence").subtract(sentenceDF.select("sentence"))                             newDF.show()

#交集      newDF = sentenceDF1.select("sentence").intersect(sentenceDF.select("sentence"))                            newDF.show()

#并集      newDF = sentenceDF1.select("sentence").union(sentenceDF.select("sentence"))                                 newDF.show()

#并集+去重      newDF = sentenceDF1.select("sentence").union(sentenceDF.select("sentence")).distinct()         newDF.show()

分割:行转列           根据某个字段内容进行分割,然后生成多行

#分割          df.explode( "c3" , "c3_" ){time: String => time.split( " " )}

统计​​​​​​​

# 统计频数                        df.stat.freqItems(Seq ("c1") , 0.3).show()

# 交叉分析                        df.crosstab('Age', 'Gender').show()

# groupby()方法           df.groupby('Age').agg({'Purchase': 'mean'}).show()

# 分组汇总                        df.groupby('Age').count().show()

# 混合应用                        from pyspark.sql import functions       
                                         df.groupBy(“A”).agg(functions.avg(“B”), functions.min(“B”), functions.max(“B”)).show()

整合后GroupedData类型可用的方法(均返回DataFrame类型):

avg(*cols)         计算每组中一列或多列的平均值
count()              计算每组中一共有多少行,返回DataFrame有2列,一列为分组的组名,另一列为行总数
max(*cols)        计算每组中一列或多列的最大值
mean(*cols)      计算每组中一列或多列的平均值
min(*cols)         计算每组中一列或多列的最小值
sum(*cols)        计算每组中一列或多列的总和

函数应用

# 每一列应用函数      df.foreach(f) 或 df.rdd.foreach(f)

# 每一块应用函数     df.foreachPartition(f) 或 df.rdd.foreachPartition(f)

pandas与pyspark中的dataframe 相互转换

# spark 转换为pandas的dataframe                         pandas_df = spark_df.toPandas()

# pandas的dataframe转化为spark的dataframe      spark_df = sc.createDataFrame(pandas_df)

df与RDD的相互转换

# DF转换为RDD rdd_df = df.rdd

# RDD转换为DF df = rdd_df.toDF()

4. SQL操作

DataFrame注册为临时表

df.createOrReplaceTempView("df")

df.registerTempTable("hello")

DateFrame随机取样

DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)

n: 要抽取的行数,需为整数值
frac:抽取的比列,需为小数值,比方说我们想随机抽取30%的数据,则设置frac=0.3即可。
replace:抽样后的数据是否代替原DataFrame(),默认为False
weights:默认为等概率加权
random_state:随机种子,本质是一个控制器,设置此值为任意实数,则每次随机的结果是一样的
axis:抽取数据的行还是列,axis=0的时是抽取行,axis=1时是抽取列

缺失值处理

  • 查找缺失值

# 查找每行缺失的数据
df.rdd.map(lambda row: (row['id'], sum([c == None for c in row]))).collect()

这里先统计了每一行的缺失值个数,可以发现第三行缺失值个数最多,是4个,打印查看一下是否正确

df.where('id == 3').show()

  • 处理缺失值

对缺失值的处理有两种策略:删除和填充。对于缺失值占比较大的数据,一般直接移除,对数据的总体影响不会太大

# 查看缺失值占比
import pyspark.sql.functions as fn

df.agg(*[(1- (fn.count(c)/ fn.count('*'))).alias(c + 'missing') for c in df.columns]).show()

# count('*') 表示统计列的所有行数
# agg(*[]) 将该列表作为一组独立的参数传递给函数,可以理解为*arg

从结果可知,income列空值占比60%,所以我们可以删掉这一列

df_no_income = df.select([c for c in df.columns if c != 'income'])
删除行的重复值

# 删除row 的重复值
df_no_income.dropna(thresh=3).show()

# thresh 允许出现空值的最大次数

第三行删掉了,因为空值个数>=3

  • 填充空值

填充空值可以填充平均数、中间值、最大或者最小值等。

# 计算每一列的平均值,并生成为一个字典
# 计算均值时排除了gender列,因为是字符串,不能计算均值
means = df_no_income.agg(*[fn.mean(c).alias(c) for c in df_no_income.columns if c != 'gender']).toPandas().to_dict('records')[0]

# 填充‘gender’ 列的空值
means['gender'] = 'missing'

df_no_income.fillna(means).show()

这里有几个新知识点:
fillna() 参数接收一个字典,或者是单个值;
toPandas() 是把spark的df转换为pandas的df;
to_dict()是把df转换为字典,而参数 records 则指定了如下的格式:{'id':3.0, 'weight':142.25, 'height':5.7250000000000005, 'age':44.0, 'gender': 'missing'}

离群值

离群值:与样本数据显著偏离的数据,这些数据的存在,对机器学习建立模型是非常不友好的,所以在数据建模之前,会对这些数据做些处理,一般直接将离群值舍弃。

离群值的阈值选择有多种方式,均值、四分位数等等,最普遍的做法是下分位(Q1) - 1.5个分位差和上分位(Q3)+1.5个分位差,即:Q1 - 1.5IQR 和Q3 + 1.5IQR,其中IQR为Q3-Q1,Q3为第75个百分点,Q1为第25个百分点

5. 描述性统计

描述性统计是熟悉数据的最直接的方法之一,可以获知数据中的缺失观测数据、平均值、标准差、最值

# 导包和创建连接的代码略
# 加载数据类型模块
import pyspark.sql.types as typ

# 加载数据
fraud = sc.textFile('./ccFraud.csv')
header = fraud.first()

# 删除标题行 并将每个元素转化为整形
fraud = fraud.filter(lambda row: row != header).map(lambda row: [int(elem) for elem in row.split(',')])

指定DF的数据类型,是通过StructField() 方法和StructType() 方法实现的

fields = [*[typ.StructField(h[1:-1], typ.IntegerType(), True) for h in header.split(',')]]
schema = typ.StructType(fields)
# 创建DF
fraud_df = spark.createDataFrame(fraud, schema)

对数据进行统计性描述

## 使用describe()方法 对数据进行统计性描述
numerical = ['balance', 'numTrans', 'numIntlTrans']
desc = fraud_df.describe(numerical)
desc.show()

从以上数据中 可以看出:最大值是平均值的多倍,说明数据呈正偏态分布; 均值和标准差之比非常高(接近或者大于1)说明这是一个广泛的数据集

检查数据的相关性:
数据的相关性,pyspark中一般用corr()方法计算相关性,缺陷是只能计算两两的相关性。

n_numerical = len(numerical)

# 查看相关性
corr = [ ]

for i in range(0, n_numerical):

temp = [None] *i


for j in range(i , n_numerical):

temp.append(fraud_df.corr(numerical[i], numerical[j]))

corr.append(temp)

你可能感兴趣的:(码农日常,spark,sql,big,data)