加入后火花下降多个重复的列

时间:2018-11-15 10:08:55

标签: apache-spark apache-spark-sql

加入两个数据框后,我得到许多重复的列, 现在我要删除最后一列,下面是我的printSchema

root
 |-- id: string (nullable = true)
 |-- value: string (nullable = true)
 |-- test: string (nullable = true)
 |-- details: string (nullable = true)
 |-- test: string (nullable = true)
 |-- value: string (nullable = true)

现在我要删除最后两列

 |-- test: string (nullable = true)
 |-- value: string (nullable = true)

我尝试使用df..dropDuplicates(),但它删除了所有

如何删除最后出现的重复列?

4 个答案:

答案 0 :(得分:2)

您必须使用vararg语法从数组中获取列名并将其删除。 检查以下内容:

scala> dfx.show
+---+---+---+---+------------+------+
|  A|  B|  C|  D|         arr|mincol|
+---+---+---+---+------------+------+
|  1|  2|  3|  4|[1, 2, 3, 4]|     A|
|  5|  4|  3|  1|[5, 4, 3, 1]|     D|
+---+---+---+---+------------+------+

scala> dfx.columns
res120: Array[String] = Array(A, B, C, D, arr, mincol)

scala> val dropcols = Array("arr","mincol")
dropcols: Array[String] = Array(arr, mincol)

scala> dfx.drop(dropcols:_*).show
+---+---+---+---+
|  A|  B|  C|  D|
+---+---+---+---+
|  1|  2|  3|  4|
|  5|  4|  3|  1|
+---+---+---+---+


scala>

Update1:​​

scala>  val df = Seq((1,2,3,4),(5,4,3,1)).toDF("A","B","C","D")
df: org.apache.spark.sql.DataFrame = [A: int, B: int ... 2 more fields]

scala> val df2 = df.select("A","B","C")
df2: org.apache.spark.sql.DataFrame = [A: int, B: int ... 1 more field]

scala> df.alias("t1").join(df2.alias("t2"),Seq("A"),"inner").show
+---+---+---+---+---+---+
|  A|  B|  C|  D|  B|  C|
+---+---+---+---+---+---+
|  1|  2|  3|  4|  2|  3|
|  5|  4|  3|  1|  4|  3|
+---+---+---+---+---+---+


scala> df.alias("t1").join(df2.alias("t2"),Seq("A"),"inner").drop($"t2.B").drop($"t2.C").show
+---+---+---+---+
|  A|  B|  C|  D|
+---+---+---+---+
|  1|  2|  3|  4|
|  5|  4|  3|  1|
+---+---+---+---+


scala>

Update2:

要动态删除列,请检查以下解决方案。

scala> val df = Seq((1,2,3,4),(5,4,3,1)).toDF("A","B","C","D")
df: org.apache.spark.sql.DataFrame = [A: int, B: int ... 2 more fields]

scala> val df2 = Seq((1,9,9),(5,8,8)).toDF("A","B","C")
df2: org.apache.spark.sql.DataFrame = [A: int, B: int ... 1 more field]

scala> val df3 = df.alias("t1").join(df2.alias("t2"),Seq("A"),"inner")
df3: org.apache.spark.sql.DataFrame = [A: int, B: int ... 4 more fields]

scala> df3.show
+---+---+---+---+---+---+
|  A|  B|  C|  D|  B|  C|
+---+---+---+---+---+---+
|  1|  2|  3|  4|  9|  9|
|  5|  4|  3|  1|  8|  8|
+---+---+---+---+---+---+

scala> val rem1 = Array("B","C")
rem1: Array[String] = Array(B, C)

scala> val rem2 = rem1.map(x=>"t2."+x)
rem2: Array[String] = Array(t2.B, t2.C)

scala> val df4 = rem2.foldLeft(df3) { (acc: DataFrame, colName: String) => acc.drop(col(colName)) }
df4: org.apache.spark.sql.DataFrame = [A: int, B: int ... 2 more fields]

scala>  df4.show
+---+---+---+---+
|  A|  B|  C|  D|
+---+---+---+---+
|  1|  2|  3|  4|
|  5|  4|  3|  1|
+---+---+---+---+


scala>

Update3

一次重命名/别名。

scala> val dfa = Seq((1,2,3,4),(5,4,3,1)).toDF("A","B","C","D")
dfa: org.apache.spark.sql.DataFrame = [A: int, B: int ... 2 more fields]

scala> val dfa2 = dfa.columns.foldLeft(dfa) { (acc: DataFrame, colName: String) => acc.withColumnRenamed(colName,colName+"_2")}
dfa2: org.apache.spark.sql.DataFrame = [A_2: int, B_2: int ... 2 more fields]

scala> dfa2.show
+---+---+---+---+
|A_2|B_2|C_2|D_2|
+---+---+---+---+
|  1|  2|  3|  4|
|  5|  4|  3|  1|
+---+---+---+---+


scala>

答案 1 :(得分:0)

假设您有两个数据帧DF1和DF2, 您可以使用任何一种方式来加入特定的列

 1. DF1.join(DF2,Seq("column1","column2"))
 2. DF1.join(DF2,DF1("column1") === DF2("column1") && DF1("column2") === DF2("column2")))

因此要删除重复的列,可以使用

 1. DF1.join(DF2,Seq("column1","column2")).drop(DF1("column1")).drop(DF1("column1"),DF1("column2"))
 2. DF1.join(DF2,DF1("column1") === DF2("column1") && DF1("column2") === DF2("column2"))).drop(DF1("column1"),DF1("column2"))

无论哪种情况,您都可以使用drop(“ columnname”)删除所需的任何列,而与它来自哪个df无关,因为在这种情况下它是相等的。

答案 2 :(得分:0)

  1. df.dropDuplicates()仅适用于行。
  2. 您可以df1.drop(df2.column(“ value”))
  3. 您可以使用df.select(列的列数)指定要选择的列

答案 3 :(得分:0)

我对这个答案并不完全满意。在大多数情况下,尤其是@ stack0114106的答案,它们暗示了正确的方法以及以干净的方式进行操作的复杂性。但是它们似乎是不完整的答案。对我来说,一种干净的自动化方法是使用df.columns功能将列作为字符串列表获取,然后使用集来查找要删除的公共列或查找要保留的唯一列,具体取决于您的用例。但是,如果使用选择,则必须为数据框添加别名,以便它知道要保留哪些非唯一列。无论如何,使用 pseudocode ,因为我不必费心编写适当的Scala代码。

common_cols = df_b.columns.toSet().intersection(df_a.columns.toSet())

df_a.join(df_b.drop(*common_cols))

它的选择版本看起来很相似,但是您必须添加别名。

unique_b_cols = df_b.columns.toSet().difference(df_a.columns.toSet()).toList
a_cols_aliased = df_a.columns.foreach(cols => "a." + cols)
keep_columns = a_cols_aliased.toList + unique_b_cols.toList 

df_a.alias("a")
    .join(df_b.alias("b"))
    .select(*keep_columns)

我更喜欢放置方式,但是写了很多火花代码。选择语句通常可以导致代码更简洁。