一:缺失值的处理方式
1.常见的缺失值有两种
1.null, NaN 等特殊类型的值, 某些语言中 null 可以理解是一个对象, 但是代表没有对象, NaN 是一个数字, 可以代表不是数字
针对这一类的缺失值, Spark 提供了一个名为 DataFrameNaFunctions 特殊类型来操作和处理
2.“Null”, “NA”, " " 等解析为字符串的类型, 但是其实并不是常规字符串数据
针对这类字符串, 需要对数据集进行采样, 观察异常数据, 总结经验, 各个击破
2.常见的三种处理方式
1.丢弃/过滤
DataFrame.na.drop()
2.填充
DataFrame.na.fill()
3.替换
DataFrame.na.replace()
3.丢弃规则
1.any 一行中有任何一个是NaN/null就丢弃
2.all 只有一行中所有的都是NaN/null才丢弃
3.某些规则 针对某些列有NaN/null,是否丢弃该列
4.填充规则
1.针对所有列进行默认填充
2.针对特定的列
二:使用SparkSQL处理null 和NaN
class demo01 {
private val spark: SparkSession = SparkSession.builder().master("local[4]").appName("nan").getOrCreate()
import spark.implicits._
@Test
def demo01(): Unit ={
//因为自动推断字段类型可能识别NAN为String类型,不方便,这里使用指定schema的方式
val schema = StructType(List(
StructField("id",LongType),
StructField("year",IntegerType),
StructField("month",IntegerType),
StructField("day",IntegerType),
StructField("hour",IntegerType),
StructField("season",IntegerType),
StructField("pm",DoubleType)
))
//1.读取数据集
val source = spark.read
.option("header", true)
.schema(schema)
.csv("dataset/beijingpm_with_nan.csv")
//2.第一种方式:丢弃
/**
* 丢弃规则:
* 1.any 一行中有任何一个是NaN/null就丢弃
* 2.all 只有一行中所有的都是NaN/null才丢弃
* 3.某些规则 针对某些列有NaN/null,是否丢弃该列
*/
source.na.drop("any").show() //任何出现NaN/null就丢弃该行
source.na.drop().show() //同上.默认any
source.na.drop("all").show() //当所有的行都是NaN/null才丢弃
source.na.drop("any",List("year","month","day","hour")) //针对特定列任意出现NaN/null就丢弃该行
//3.第二种方式:填充
/**
* 填充规则
* 1.针对所有列进行默认填充
* 2.针对特定的列
*/
source.na.fill(0).show() //针对所有列填充为0
source.na.fill(0,List("year","month")).show() //只填充具体列
}
}
程序运行结果:
原始数据:
+---+----+-----+---+----+------+---+
| id|year|month|day|hour|season| pm|
+---+----+-----+---+----+------+---+
| 1|2010| 1| 1| 0| 4|NaN|
| 2|2010| 1| 1| 1| 4|NaN|
| 3|2010| 1| 1| 2| 4|NaN|
| 4|2010| 1| 1| 3| 4|NaN|
| 5|2010| 1| 1| 4| 4|NaN|
| 6|2010| 1| 1| 5| 4|NaN|
| 7|2010| 1| 1| 6| 4|NaN|
| 8|2010| 1| 1| 7| 4|NaN|
| 9|2010| 1| 1| 8| 4|NaN|
| 10|2010| 1| 1| 9| 4|NaN|
+---+----+-----+---+----+------+---+
only showing top 10 rows
(any规则)丢弃后的结果:
+-----+----+-----+---+----+------+----+
| id|year|month|day|hour|season| pm|
+-----+----+-----+---+----+------+----+
|26695|2013| 1| 17| 6| 4|25.0|
|26696|2013| 1| 17| 7| 4|22.0|
|26697|2013| 1| 17| 8| 4|20.0|
|26698|2013| 1| 17| 9| 4|24.0|
|26699|2013| 1| 17| 10| 4|27.0|
|26700|2013| 1| 17| 11| 4|29.0|
|26701|2013| 1| 17| 12| 4|31.0|
|26702|2013| 1| 17| 13| 4|27.0|
|26703|2013| 1| 17| 14| 4|39.0|
|26704|2013| 1| 17| 15| 4|53.0|
+-----+----+-----+---+----+------+----+
only showing top 10 rows
替换后的结果:
+---+----+-----+---+----+------+---+
| id|year|month|day|hour|season| pm|
+---+----+-----+---+----+------+---+
| 1|2010| 1| 1| 0| 4|0.0|
| 2|2010| 1| 1| 1| 4|0.0|
| 3|2010| 1| 1| 2| 4|0.0|
| 4|2010| 1| 1| 3| 4|0.0|
| 5|2010| 1| 1| 4| 4|0.0|
| 6|2010| 1| 1| 5| 4|0.0|
| 7|2010| 1| 1| 6| 4|0.0|
| 8|2010| 1| 1| 7| 4|0.0|
| 9|2010| 1| 1| 8| 4|0.0|
| 10|2010| 1| 1| 9| 4|0.0|
+---+----+-----+---+----+------+---+
only showing top 10 rows
三:SparlSQL处理异常字符串(NA / Null)
class demo02 {
private val spark: SparkSession = SparkSession.builder().master("local[4]").appName("nan").getOrCreate()
import spark.implicits._
@Test
def demo01(): Unit ={
val source = spark.read
.option("header", true)
.option("inferSchema", true)
.csv("dataset/BeijingPM20100101_20151231.csv")
source.show(10)
//1.丢弃
//只获取 不为 =!= "NA" 的数据
source.where('PM_Dongsi =!= "NA").show(10)
//2.替换
//2.1直接替换
//想要使用when,就需要导入functions的隐式转换
import org.apache.spark.sql.functions._
val df1 = source.select(
cols = 'No as "id", 'year, 'month, 'day, 'hour, 'season,
//如果东四 等于 NA,就替换成 Double类型的NaN (NA是字符串类型,但是NaN是Double类型的 not a number,两者类型不一致)
when('PM_Dongsi === "NA", Double.NaN)
//还需要统一该列的其他数据的类型
.otherwise('PM_Dongsi cast DoubleType)
//再指定新的列名
.as("pm")
)
df1.show(10)
df1.printSchema()
//2.2使用df.na.replace("指定列",Map("原始数据"->"替换后的数据"))进行替换,但是Map替换的方式类型不能变
//注意: Map()转换的时候原类型和转换后的类型必须一致
val df2 = source.na.replace(
"PM_Dongsi", Map("NA" -> "NaN", "Null" -> "null")
)
df2.show(10)
df2.printSchema()
}
}
程序运行结果
原始数据:
+---+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
| No|year|month|day|hour|season|PM_Dongsi|PM_Dongsihuan|PM_Nongzhanguan|PM_US_Post|DEWP|HUMI|PRES|TEMP|cbwd| Iws|precipitation|Iprec|
+---+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
| 1|2010| 1| 1| 0| 4| NA| NA| NA| NA| -21| 43|1021| -11| NW| 1.79| 0| 0|
| 2|2010| 1| 1| 1| 4| NA| NA| NA| NA| -21| 47|1020| -12| NW| 4.92| 0| 0|
| 3|2010| 1| 1| 2| 4| NA| NA| NA| NA| -21| 43|1019| -11| NW| 6.71| 0| 0|
| 4|2010| 1| 1| 3| 4| NA| NA| NA| NA| -21| 55|1019| -14| NW| 9.84| 0| 0|
| 5|2010| 1| 1| 4| 4| NA| NA| NA| NA| -20| 51|1018| -12| NW|12.97| 0| 0|
| 6|2010| 1| 1| 5| 4| NA| NA| NA| NA| -19| 47|1017| -10| NW| 16.1| 0| 0|
| 7|2010| 1| 1| 6| 4| NA| NA| NA| NA| -19| 44|1017| -9| NW|19.23| 0| 0|
| 8|2010| 1| 1| 7| 4| NA| NA| NA| NA| -19| 44|1017| -9| NW|21.02| 0| 0|
| 9|2010| 1| 1| 8| 4| NA| NA| NA| NA| -19| 44|1017| -9| NW|24.15| 0| 0|
| 10|2010| 1| 1| 9| 4| NA| NA| NA| NA| -20| 37|1017| -8| NW|27.28| 0| 0|
+---+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
only showing top 10 rows
丢弃后的结果:
PM_Dongsi 这一列不再出现 NA 等非法字符
+-----+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
| No|year|month|day|hour|season|PM_Dongsi|PM_Dongsihuan|PM_Nongzhanguan|PM_US_Post|DEWP|HUMI|PRES|TEMP|cbwd| Iws|precipitation|Iprec|
+-----+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
|26695|2013| 1| 17| 6| 4| 25| NA| 20| 34| -17| 56|1038| -10| NW| 4.92| 0| 0|
|26696|2013| 1| 17| 7| 4| 22| NA| 20| 33| -16| 52|1039| -8| NE| 4.92| 0| 0|
|26697|2013| 1| 17| 8| 4| 20| NA| 27| 33| -16| 45|1040| -6| NE| 8.94| 0| 0|
|26698|2013| 1| 17| 9| 4| 24| NA| 28| 34| -16| 38|1040| -4| NE|12.07| 0| 0|
|26699|2013| 1| 17| 10| 4| 27| NA| 15| 38| -16| 35|1040| -3| NE|16.09| 0| 0|
|26700|2013| 1| 17| 11| 4| 29| NA| 17| 38| -15| 33|1040| -1| NE|20.11| 0| 0|
|26701|2013| 1| 17| 12| 4| 31| NA| 31| 41| -17| 26|1038| 0| NE|23.24| 0| 0|
|26702|2013| 1| 17| 13| 4| 27| NA| 18| 37| -18| 21|1037| 2| NW| 1.79| 0| 0|
|26703|2013| 1| 17| 14| 4| 39| NA| 24| 45| -18| 21|1036| 2| cv| 0.89| 0| 0|
|26704|2013| 1| 17| 15| 4| 53| NA| 48| 71| -17| 21|1035| 3| SE| 1.79| 0| 0|
+-----+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
only showing top 10 rows
第一种替换方式的结果:和转换后的Schema信息
+---+----+-----+---+----+------+---+
| id|year|month|day|hour|season| pm|
+---+----+-----+---+----+------+---+
| 1|2010| 1| 1| 0| 4|NaN|
| 2|2010| 1| 1| 1| 4|NaN|
| 3|2010| 1| 1| 2| 4|NaN|
| 4|2010| 1| 1| 3| 4|NaN|
| 5|2010| 1| 1| 4| 4|NaN|
| 6|2010| 1| 1| 5| 4|NaN|
| 7|2010| 1| 1| 6| 4|NaN|
| 8|2010| 1| 1| 7| 4|NaN|
| 9|2010| 1| 1| 8| 4|NaN|
| 10|2010| 1| 1| 9| 4|NaN|
+---+----+-----+---+----+------+---+
only showing top 10 rows
PM_Dongsi 这一列的额数据类型由原来的 String类型转换成 Double类型
root
|-- id: integer (nullable = true)
|-- year: integer (nullable = true)
|-- month: integer (nullable = true)
|-- day: integer (nullable = true)
|-- hour: integer (nullable = true)
|-- season: integer (nullable = true)
|-- pm: **double** (nullable = true)
replace的替换方式的结果,使用Map进行指定字段内的多种类型的不同替换方式
+---+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
| No|year|month|day|hour|season|PM_Dongsi|PM_Dongsihuan|PM_Nongzhanguan|PM_US_Post|DEWP|HUMI|PRES|TEMP|cbwd| Iws|precipitation|Iprec|
+---+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
| 1|2010| 1| 1| 0| 4| NaN| NA| NA| NA| -21| 43|1021| -11| NW| 1.79| 0| 0|
| 2|2010| 1| 1| 1| 4| NaN| NA| NA| NA| -21| 47|1020| -12| NW| 4.92| 0| 0|
| 3|2010| 1| 1| 2| 4| NaN| NA| NA| NA| -21| 43|1019| -11| NW| 6.71| 0| 0|
| 4|2010| 1| 1| 3| 4| NaN| NA| NA| NA| -21| 55|1019| -14| NW| 9.84| 0| 0|
| 5|2010| 1| 1| 4| 4| NaN| NA| NA| NA| -20| 51|1018| -12| NW|12.97| 0| 0|
| 6|2010| 1| 1| 5| 4| NaN| NA| NA| NA| -19| 47|1017| -10| NW| 16.1| 0| 0|
| 7|2010| 1| 1| 6| 4| NaN| NA| NA| NA| -19| 44|1017| -9| NW|19.23| 0| 0|
| 8|2010| 1| 1| 7| 4| NaN| NA| NA| NA| -19| 44|1017| -9| NW|21.02| 0| 0|
| 9|2010| 1| 1| 8| 4| NaN| NA| NA| NA| -19| 44|1017| -9| NW|24.15| 0| 0|
| 10|2010| 1| 1| 9| 4| NaN| NA| NA| NA| -20| 37|1017| -8| NW|27.28| 0| 0|
+---+----+-----+---+----+------+---------+-------------+---------------+----------+----+----+----+----+----+-----+-------------+-----+
only showing top 10 rows
PM_Dongsi 替换后的类型还是String类型
root
|-- No: integer (nullable = true)
|-- year: integer (nullable = true)
|-- month: integer (nullable = true)
|-- day: integer (nullable = true)
|-- hour: integer (nullable = true)
|-- season: integer (nullable = true)
|-- PM_Dongsi: **string** (nullable = true)
|-- PM_Dongsihuan: string (nullable = true)
|-- PM_Nongzhanguan: string (nullable = true)
|-- PM_US_Post: string (nullable = true)
|-- DEWP: string (nullable = true)
|-- HUMI: string (nullable = true)
|-- PRES: string (nullable = true)
|-- TEMP: string (nullable = true)
|-- cbwd: string (nullable = true)
|-- Iws: string (nullable = true)
|-- precipitation: string (nullable = true)
|-- Iprec: string (nullable = true)