如何将数据框的几列与其其他列进行比较

Posted

技术标签:

【中文标题】如何将数据框的几列与其其他列进行比较【英文标题】:How to compare few columns of a dataframe with its other columns 【发布时间】:2019-05-05 19:27:14 【问题描述】:

我在 spark 的数据框中有 8 列,

    名字_a, status_a, date_a, ID_a, 姓名_b, status_b, date_b, ID_b.

现在我想将前四列与后四列进行比较,即Name_aName_bstatus_astatus_b 等。我如何使用scala 语言在spark 中做到这一点?

【问题讨论】:

欢迎来到 Stack Overflow!请查看writing the perfect question 以帮助您提出一个好问题,从而获得一个好的答案。 【参考方案1】:

问题:我想将前四列与后四列进行比较 Name_a 和 Name_b、status_a 和 status_b 等列。如何 我可以用 scala 语言在 spark 中做到这一点吗?

选项 1: 以下是使用except 执行此操作的方法,您可以实现此目的...

将所有8列作为数据框 取数据框中的前 4 列并为其命名...这是您的第一个数据框 获取数据帧的最后 4 列,并使用与第一个数据帧相同的名称为其命名...这将成为您的第二个数据帧 使用except,您可以找到如下所示的差异,这是不言自明的......
package com.examples
import org.apache.log4j.Level, Logger
import org.apache.spark.internal.Logging
import org.apache.spark.sql.SparkSession

/**
  * @author : Ram Ghadiyaram
  */
object FindDataFrameColumnDifferences extends App with Logging 
  Logger.getLogger("org").setLevel(Level.WARN)

  case class Employee(Name_a: String, status_a: Int, date_a: String, ID_a: Int
                      , Name_b: String, status_b: Int, date_b: String, ID_b: Int)


  val spark: SparkSession = SparkSession.builder().appName(this.getClass.getName).master("local[*]").getOrCreate()
  //spark.sparkContext.setLogLevel("ERROR")

  import spark.implicits._
  val df = List(
    Employee("Ram", 1, "21-Mar-2019", 20048965, "Ram", 1, "21-Mar-2019", 20048965),
    Employee("Ram", 1, "21-Mar-2019", 20048965, "Ram", 1, "21-Mar-2019", 20048965),
    Employee("Mishy_tics", 1, "21-Mar-2019", 20048965, "Mishy", 1, "21-Mar-2019", 20048965),
    Employee("Mishy_tics", 1, "21-Mar-2019", 20048965, "tics", 1, "21-Mar-2019", 20048965)
  ).toDF
  logInfo("original dataframe with 8 columns")
  df.show(false)
  logInfo("Now take first 4 columns in the original dataframe and rename using alias ")
  val firstDataFrame = df.selectExpr("Name_a  as name", "status_a as status", "date_a as date", "ID_a  as id")
  logInfo("printing first dataframe ")
  firstDataFrame.show

  logInfo("Now take last 4 columns in the original dataframe and rename using alias ")
  val secondDataFrame = df.selectExpr("Name_b  as name", "status_b as status", "date_b as date", "ID_b  as id")
  logInfo("printing second dataframe ")
  secondDataFrame.show

  val columns = firstDataFrame.schema.fields.map(_.name)

  logInfo("first except second")
  var selectiveDifferences = columns.map(col => firstDataFrame.select(col).except(secondDataFrame.select(col)))

  // columns contains different values.
  selectiveDifferences.map(diff => 
    if (diff.count > 0) diff.show
  )

  selectiveDifferences = columns.map(col => secondDataFrame.select(col).except(firstDataFrame.select(col)))
  logInfo("second except first")

  // columns contains different values.
  selectiveDifferences.map(diff => 
    if (diff.count > 0) diff.show
  )

2019-05-05 19:10:05 WARN NativeCodeLoader:62 - 无法为您的平台加载 native-hadoop 库...在适用的情况下使用内置 java 类 2019-05-05 19:10:13 INFO FindDataFrameColumnDifferences:54 - 8 列的原始数据框 +---------+--------+------------+--------+------+- --------+-----------+--------+ |Name_a |status_a|date_a |ID_a |Name_b|status_b|date_b |ID_b | +---------+--------+------------+--------+------+- --------+-----------+--------+ |内存 |1 |2019 年 3 月 21 日|20048965|内存 |1 |2019 年 3 月 21 日|20048965| |内存 |1 |2019 年 3 月 21 日|20048965|内存 |1 |2019 年 3 月 21 日|20048965| |Mishy_tics|1 |2019 年 3 月 21 日|20048965|Mishy |1 |2019 年 3 月 21 日|20048965| |Mishy_tics|1 |2019 年 3 月 21 日|20048965|tics |1 |2019 年 3 月 21 日|20048965| +---------+--------+------------+--------+------+- --------+-----------+--------+ 2019-05-05 19:10:13 INFO FindDataFrameColumnDifferences:54 - 现在在原始数据框中取前 4 列并使用别名重命名 2019-05-05 19:10:14 INFO FindDataFrameColumnDifferences:54 - 打印第一个数据帧 +---------+------+------------+--------+ |名称|状态|日期|编号| +---------+------+------------+--------+ |公羊| 1|2019 年 3 月 21 日|20048965| |公羊| 1|2019 年 3 月 21 日|20048965| |Mishy_tics| 1|2019 年 3 月 21 日|20048965| |Mishy_tics| 1|2019 年 3 月 21 日|20048965| +---------+------+------------+--------+ 2019-05-05 19:10:14 INFO FindDataFrameColumnDifferences:54 - 现在取原始数据框中的最后 4 列并使用别名重命名 2019-05-05 19:10:14 INFO FindDataFrameColumnDifferences:54 - 打印第二个数据帧 +-----+------+------------+--------+ |名称|状态|日期|编号| +-----+------+------------+--------+ |公羊| 1|2019 年 3 月 21 日|20048965| |公羊| 1|2019 年 3 月 21 日|20048965| |迷糊| 1|2019 年 3 月 21 日|20048965| |抽动| 1|2019 年 3 月 21 日|20048965| +-----+------+------------+--------+ 2019-05-05 19:10:14 信息 FindDataFrameColumnDifferences:54 - 除了第二个 +----------+ |姓名| +----------+ |Mishy_tics| +----------+ 2019-05-05 19:10:29 INFO FindDataFrameColumnDifferences:54 - 第二个,除了第一个 +-----+ |姓名| +-----+ |迷糊| |抽动| +-----+

选项 2: - 另一种方法是在使用equi join/self join on name 和状态创建第一个包含 8 列的数据框之后......您可以找到它们之间的差异。

见:Joining Spark dataframes on the key

选项 2 是我觉得最简单的方式..

【讨论】:

Mishy 你试过这个吗? ,如果您还可以,请注意以所有者的身份接受答案并投票 其实我正在尝试做一个CDC进程,所以我想要Name_a,Status_a与Name_b,Status_b之间的区别。我也想同时捕获更新,而不是多个步骤 虽然我无法猜测你在做什么,但分成 2 个数据框使用第二种连接方法来找出差异......请正确地提出问题,并且格式非常重要从用户那里得到答案。其他人应该能够理解您的问题..请参阅如何格式化问题的帮助。并提供您想要实现的代码 sn-p .... 并且无法做到。否则将被视为低质量问题..【参考方案2】:

假设一条记录可以表示为:

Person(name: String, status: Boolean, date: String, id: Int)

在您的情况下,每一行都包含Persons 的双重记录。您可以将两个人排成一行,如下所示:

case class Person(name: String, status: Boolean, date: String, id: Int)
case class TuplePerson(a: Person, b: Person)

然后你可以使用数据集来比较a with b。完整代码如下:

case class Person(name: String, status: Boolean, date: String, id: Int)
case class TuplePerson(a: Person, b: Person)

val df = Seq(
(TuplePerson(Person("John", true,"15-05-2019", 54), Person("John", true,"15-05-2019", 54))),
(TuplePerson(Person("Sofia", true,"15-05-2019", 54),Person("John", true,"15-05-2019", 53))),
(TuplePerson(Person("John", true,"15-05-2019", 52), Person("John", true,"15-05-2019", 52))))
.toDS()

df.where($"a" === $"b").show(false)

输出:

+----------------------------+----------------------------+
|a                           |b                           |
+----------------------------+----------------------------+
|[John, true, 15-05-2019, 54]|[John, true, 15-05-2019, 54]|
|[John, true, 15-05-2019, 52]|[John, true, 15-05-2019, 52]|
+----------------------------+----------------------------+

或者获取左右部分的差:

df.where($"a" =!= $"b").show(false)

+-----------------------------+----------------------------+
|a                            |b                           |
+-----------------------------+----------------------------+
|[Sofia, true, 15-05-2019, 54]|[John, true, 15-05-2019, 53]|
+-----------------------------+----------------------------+

【讨论】:

嗨,Mishy,这是您要寻找的差异还是您的意思?

以上是关于如何将数据框的几列与其其他列进行比较的主要内容,如果未能解决你的问题,请参考以下文章

Python:合并数据框的几列而没有重复的数据

将DataTable的几列序列化为xml并将其存储在数据库中的列中

html如何对表格的一行中的几列进行合并的代码

如何将几列熊猫数据框转换为另一条记录中的 JSON 记录?

根据其他列将数据框的一列转换为numpy数组或张量

将数据框的新列分配给与其他数据框匹配的值[重复]