《Spark 先知先觉》DataFrame转换操作

例子:将原始类型转处理布尔类型换为Spark 类型,使用 lit 函数
函数:lit()
用例:lit 函数:把其他语言的类型转换为与其相对应的Spark表示

    // lit 函数:把其他语言的类型转换为与其相对应的Spark表示
    df.select(lit(5),lit("five"),lit(5.0)).show()

处理布尔类型

例子:布尔语句由四个要素组成:and,or,true 和 false
函数:and,or,true,false
用例:基于零售数据来说明处理布尔类型的方法,可以在其中指定等于、小于或大于:

df.where(col("InvoiceNo").equalTo(536365))
      .select("InvoiceNo", "Description")
      .show(5, false)

例子:相等条件或者不相等条件
函数:相等:=== 或 equalTo
不相等:=!= 或not
用例:在spark 中,如果想通过相等条件来进行过滤,应该使用 ===(等于) 或者 =!=(不等于)符号,还可以使用not 或者equalTo 方法来实现。

    df.where(col("InvoiceNo") === 536365)
      .select("InvoiceNo", "Description")
      .show(5, false)

例子:顺序执行的过滤器
用例:在spark 中最好是以链式连接的方式组合起来,形成顺序执行的过滤器

val priceFilter = col("UnitPrice") > 600
val descripFilter = col("Description").contains("POSTAGE")    
df.where(col("StockCode").isin("DOT")).where(priceFilter.or(descripFilter)).show()

例子:设定一个Boolean 类型的列
用例:布尔表达式不一定非要在过滤器中使用,想要过滤DataFrame ,也可以设定一个Boolean类型的列

	println("boolean 列:")
    val DOTCodeFilter = col("StockCode") === "DOT"
    df.withColumn("isExpensive", DOTCodeFilter.and(priceFilter.or(descripFilter)))
      .where("isExpensive")
      .select("unitPrice", "isExpensive")
      .show(5)

下面两个等价:

    //下面两个等价:
    println("下面两个等价:")
    df.withColumn("isExpansive", not(col("UnitPrice").leq(250)))
      .filter("isExpansive")
      .select("Description", "UnitPrice")
      .show(5)

    df.withColumn("isExpansive", expr("NOT UnitPrice <= 250"))
      .filter("isExpansive")
      .select("Description", "UnitPrice")
      .show(5)

处理数值类型

例子:计算
函数:pow() 平方函数
用例:计算(当前数量* 单位数量)的平方 + 5

    // 计算(当前数量* 单位数量)的平方 + 5
    println("pow() 函数:对指定的列进行幂运算")
    var fabricatedQuantity = functions.pow(col("Quantity") * col("UnitPrice"), 2)+5
    df.select(expr("CustomerId"),fabricatedQuantity.alias("readQuantity")).show(2)//给fabricatedQuantity一个别名

    // 使用SQL 等价代替
    df.selectExpr("CustomerID","(POWER((Quantity * UnitPrice),2) + 5) as readQuantity")

例子:处理四舍五入的情况
函数:round 函数会向上取整,bround 函数进行向下取整
用例: 将四舍五入到小数点后一位,在默认情况下,如果恰好位于两个数字之间,则round 函数会向上取整,也可以通过bround 函数进行向下取整。

    println("处理四舍五入的情况:")
    // 将四舍五入到小数点后一位
    df.select(round(col("UnitPrice"),1).alias("rounded"),col("UnitPrice")).show(5)
    // 在默认情况下,如果恰好位于两个数字之间,则round 函数会向上取整,
    // 也可以通过bround 函数进行向下取整
    df.select(round(lit("2.5")), bround(lit("2.5"))).show(2)

例子:计算相关性
函数:corr()
用例:计算两列的相关性 例如,可以通过两列的Pearson 相关系数来查看是个东西越便宜买的越多。

    //计算两列的相关性 例如,可以通过两列的Pearson 相关系数来查看是个东西越便宜买的越多
    println("计算两列的相关性:")
    df.stat.corr("Quantity","UnitPrice")
    df.select(corr("Quantity","UnitPrice")).show(5)

例子:计算一列或一组列的汇总统计信息;
函数:describe()
用例:计算一列或一组列的汇总统计信息;包含:计数,平均值,标准差,最小值和最大值。

    //计算一列或一组列的汇总统计信息;
    println("计算一列或一组列的汇总统计信息")
    // 包含:计数,平均值,标准差,最小值和最大值
    df.describe().show()

例子:精确聚合操作
函数:approxQuantile()
用例:如果需要这些精确的数字,也可以通过导入函数并在所在列上应用来实现聚合操作
,StatFunction 包中封装了各种计算的DataFrame 方法,比如,可以使用 approxQuantile 方法来计算数据的精确分位数或近似分位数。

 println("计算数据的精确分位数或近似分位数")
    val colName = "UnitPrice"
    val quantileProbs = Array(0.5)
    val relError = 0.05
    df.stat.approxQuantile("UnitPrice", quantileProbs, relError) // 2.51

例子:查看交叉列表或频繁项:
函数:crosstab() 查看交叉列表,freqItems() 查看频繁项
用例:

    //查看交叉列表或频繁项:
    println("查看交叉列表或频繁项:")
    df.stat.crosstab("StockCode", "Quantity").show() // 交叉列表
    df.stat.freqItems(Seq("StockCode", "Quantity")).show() // 频繁项

处理字符串类型

例子:initcap 函数会将给定字符串中空格分隔的每个单词首字母大写
函数:initcap()
用例:

    // initcap 函数会将给定字符串中空格分隔的每个单词首字母大写
    println("initcap 函数会将给定字符串中空格分隔的每个单词首字母大写")
    df.select(initcap(col("Description"))).show(2,false)

例子:将字符串转为大写或小写
函数:lower() 小写 ,upper() 大写
用例:

    // 将字符串转为大写或小写
    println("将字符串转为大写或小写")
    df.select(col("Description"),
      lower(col("Description").alias("小写")),
      upper(lower(col("Description")).alias("大写"))).show(2)

例子:删除字符串周围的空格或者在其周围添加空格
函数:lpad,ltrim,rpad,rtrim,trim
用例: 删除字符串周围的空格或者在其周围添加空格,可以使用lpad,ltrim,rpad,rtrim,trim

    println("删除字符串周围的空格或者在其周围添加空格,可以使用lpad,ltrim,rpad,rtrim,trim")
    df.select(
      ltrim(lit("    HELLO    ")).as("ltrim"),
      rtrim(lit("    HELLO    ")).as("rtrim"),
      trim(lit("    HELLO    ")).as("trim"),
      lpad(lit("HELLO"), 3, " ").as("lp"),
      rpad(lit("HELLO"), 10, " ").as("rp")).show(2)
    // 注意:如果lpad 或rpad方法输入的数值参数小于字符串长度,他将从字符串的右侧删除字符

处理日期和时间戳类型

处理日期和时间戳类型 Spark
通过显示的关注两种时间相关信息来简化这个问题,分别是专门正对日历日期的date,以及包括日期和时间信息的timestamp
当设置inferSchema 为true 的时候,Spark可以自动推理出日期和时间戳数据类型

// 获取当前的日期和当前的时间戳
    val dateDF = spark.range(10)
      .withColumn("today", current_date())
      .withColumn("now", current_timestamp())
    dateDF.createOrReplaceTempView("dateTable")

例子:增加天数,减去天数
函数:date_sub() 减去天数,date_add() 增加天数
用例:现在有一个简单的DataFrame 可以使用,从今天起增加和减去5天,这些函数读取一列,然后将添加或减去的天数作为参数

    // 现在有一个简单的DataFrame 可以使用,从今天起增加和减去5天,这些函数读取一列,然后将添加或减去的天数作为参数
    println("读取一列,然后将添加或减去的天数作为参数")
    dateDF.select(date_sub(col("today"),5),date_add(col("today"),5)).show(1)

例子:查看两个日期之间的间隔时间
函数: datediff()
用例:查看两个日期之间的间隔时间,可以使用datediff 函数来完成,返回两个日期之间的天数,该函数返回两个日期之间的天数,由于每个月的天数不用,还有一个months_between 函数,它可以给出两个日期之间相隔的月数

    println("查看两个日期之间的间隔时间,可以使用datediff 函数来完成,返回两个日期之间的天数:")
    dateDF.withColumn("week_age",date_sub(col("today"),7))
      .select(datediff(col("week_age"),col("today")))
      .show(1)

    //查看两个日期之间间隔的月数
    println("查看两个日期之间间隔的月数")
    dateDF.select(
      to_date(lit("2016-01-01")).alias("start"),
      to_date(lit("2017-05-22")).alias("end"))
      .select(months_between(col("start"), col("end"))).show(1)

例子:指定的格式将字符串转为日期格式
函数:to_date()
用例:

    //to_date 函数,该函数以指定的格式将字符串转为日期格式
    println("to_date 函数,该函数以指定的格式将字符串转为日期格式")
    spark.range(5).withColumn("date", lit("2017-01-01"))
      .select(to_date(col("date"))).show(1)

例子:Spark 无法解析日期,
函数:to_date 和 to_timestamp 前者可以选择一种日期格式,而后者则强制要求使用一种日期格式
用例:

    // Spark 无法解析日期,
    dateDF.select(to_date(lit("2016-20-12")), to_date(lit("2017-12-11"))).show(1)

    //修复这个功能,将使用两个函数来解决此问题,to_date 和 to_timestamp 前者可以选择一种日期格式,而后者则强制要求使用一种日期格式
    // to_date 可选择一种日期格式
    val dateFormat = "yyyy-dd-MM"
    val cleanDateDF = spark.range(1).select(
      to_date(lit("2017-12-11"), dateFormat).alias("date"),
      to_date(lit("2017-20-12"), dateFormat).alias("date2"))
    cleanDateDF.createOrReplaceTempView("dateTable2")

    // to_timestamp 强制要求使用一种日期格式
    cleanDateDF.select(to_timestamp(col("date"), dateFormat)).show()

例子:比较
函数:
用例:

    // 在以正确的格式和类型获取了日期或时间戳之后,他们之间的比较实际上很简单,只需要确保使用同一种日期/时间戳类型,或者根据 yyyy-MM-dd 这个正确格式来指定字符串
    cleanDateDF.filter(col("date2") > lit("2017-12-12")).show()

    // 另一个也要说明,也可以将他设置为一个字符串,这样spark 可以将它解释为文本
    cleanDateDF.filter(col("date2") > "'2017-12-12'").show()

处理数据中的空值

例子:合并
函数:coalesce 函数,实现从一组列中选择第一个非空值
用例:

    println("coalesce 函数,实现从一组列中选择第一个非空值")
    df.select(coalesce(col("Description"),col("CustomerId"))).show()

例子:删除
函数:drop()
用例:用于删除包含null 的行,默认删除包含null 的行。 若指定any 作为参数,当存在一个值是null时,就删除该行,若指定 all 为参数,只有当所有的值为null 或NaN 时才能删除该行。

    df.na.drop()
    df.na.drop("any")
    spark.stop()

    df.na.drop("all")

    // 指定列进行删除空值操作
    // 通过指定某几列,来对这些列进行删除空值操作
    df.na.drop("all", Seq("StockCode", "InvoiceNo"))

例子:fill() 填充
函数:fill()
用例:可以用一组值填充一列或多列,可以通过指定一个映射(即一个特定值和一组列)来完成此操作。

    //替换某字符串类型列中的所有null 值为某一字符串
    df.na.fill("All Null values become this string")
    //对于Integer 类型的列,可以使用df.na.fill(5:Integer) 来实现
    // 对于Double 类型的列,可以使用df.na.fill(5:Double) 来实现
    df.na.fill(5, Seq("StockCode", "InvoiceNo"))
    // 想要指定多列,需传入一个列名的数组,
    val fillColValues = Map("StockCode" -> 5, "Description" -> "No Value")
    df.na.fill(fillColValues)

例子:替换
函数:replace()
用例:常见的用例:是根据当前值替换某列中的所有值,唯一的要求是替换之与原始值的类型相同。

    println("replace")
    df.na.replace("Description", Map("" -> "UNKNOWN"))

处理负责数据类型

例子:处理结构体
函数:
用例:

    println("结构体:")
    // 用圆括号括起一组列来创建一个结构体
    df.selectExpr("(Description, InvoiceNo) as complex", "*")
    df.selectExpr("struct(Description, InvoiceNo) as complex", "*")
    
    val complexDF = df.select(struct("Description", "InvoiceNo").alias("complex"))
    complexDF.createOrReplaceTempView("complexDF")
    // 现在有一个包含complex 列的DataFrame ,我们可以像查询另一个DataFrame 一样查询它,唯一的区别是,使用”.“ 来访问或列方法getField 来实现
    complexDF.select("complex.Description")
    complexDF.select(col("complex").getField("Description"))

    // 还可以使用* 来查询结构体中的所有制,
    complexDF.select("complex.*")

例子:数组
函数:
用例:

  /**
     * 数组
     * 用例:使用当前数据,目标是读取Description 列中的每一个单词并将其转换成DataFrame 中的一行
     * 第一个操作是将Description 列转换为一个复杂类型,即数组
     */
    /**
     * split()
     * 使用split() ,并指定分隔符来执行此操作
     * 这个功能非常有用,因为spark 允许我们将这种复杂类型作为另一列来操作
     */
    df.select(split(col("Description")," ")).show(2)

    // 数组长度,
    df.select(size(split(col("Description")," "))).show(2) // 打印5 和 3

    /**
     *  array_contains()
     *  查询此数组是个包含某个值
     */
    df.select(array_contains(split(col("Description")," "),"WHITE")).show(2)


    /**
     * 若想将复杂类型转换为一系列行(数组中的每个值为一行),则需要使用explode 函数
     * explode函数输入参数为一个包含数组的列,并未该数组中的每个值创建一行(每行重复该值)
     */
    df.withColumn("splitted", functions.split(col("Description"), " "))
      .withColumn("exploded", explode(col("splitted")))
      .select("Description", "InvoiceNo", "exploded").show(2)

例子:map
函数:
用例:


    /**
     * map
     * map映射是通过map函数构建两列内容的键值对映射形式,然后,便可以想在数组中一样去选择他们
     */
    df.select(functions.map(col("Description"),col("InvoiceNo")).alias("complex_map")).show(2)

    // 可以使用正确的键值对他们进行查询。若键值不存在则返回null
    df.select(functions.map(col("Description"),col("InvoiceNo")).alias("complex_map"))
      .selectExpr("complex_map['WHITE METAL LANTERN']").show(2)

    //展开map类型,将其转换为列
    df.select(functions.map(col("Description"), col("InvoiceNo")).alias("complex_map"))
      .selectExpr("explode(complex_map)").show(2)

处理JSON 类型

例子:
函数:to_json()、 get_json_object
用例:

   //创建一个JSON 类型的列
    val jsonDF = spark.range(1).selectExpr(
      """
  '{"myJSONKey" : {"myJSONValue" : [1, 2, 3]}}' as jsonString
  """)

    // 无论是字典还是数组,均可以使用get_json_object 直接查询json 对象,如果此查询的json对象仅有一层嵌套,则可以使用json_tuple
    jsonDF.select(
      get_json_object(col("jsonString"), "$.myJSONKey.myJSONValue[1]") as "column",
      json_tuple(col("jsonString"), "myJSONKey")).show(2)
    // SQL 中的等价
    jsonDF.selectExpr(
      "json_tuple(jsonString, '$.myJSONKey.myJSONValue[1]') as column").show(2)

    /**
     * 使用to_json 函数将StructType 转换为JSON 字符串
     * 这个函数也可以接收参数的映射作为输入,这些映射与json 的数据源相同,还可以使用from_json 函数将json 数据解析出来
     * 这需要指定一个模式,也可以指定其他的映射
     */
    // 使用to_json 函数将StructType 转换为JSON 字符串
    df.selectExpr("(InvoiceNo, Description) as myStruct")
      .select(to_json(col("myStruct")))

    val parseSchema = new StructType(Array(
      new StructField("InvoiceNo",StringType,true),
      new StructField("Description",StringType,true)))
    df.selectExpr("(InvoiceNo, Description) as myStruct")
      .select(to_json(col("myStruct")).alias("newJSON"))
      .select(from_json(col("newJSON"), parseSchema), col("newJSON")).show(2)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值