2017-06-06 182 views
0

我们有一个具体的需求,其中我必须从dataframedrop列开始,该列在该列中只有一个唯一值。以下是我们在做什么Spark - Scala - 根据条件从数据框中删除列

val rawdata = spark.read.format("csv").option("header","true").option("inferSchema","true").load(filename) 

随后找到火花支持我们使用的是HyperLog++算法中的所有列唯一值

val cd_cols = rawdata.select(rawdata.columns.map(column => approxCountDistinct(col(column)).alias(column)): _*) 

输出是

scala> cd_cols.show 
+----+----------+---------+---+---------+--------------+---------+----------+----------------+---------+--------------+-------------+ 
| ID|First Name|Last Name|Age|Attrition|BusinessTravel|DailyRate|Department|DistanceFromHome|Education|EducationField|EmployeeCount| 
+----+----------+---------+---+---------+--------------+---------+----------+----------------+---------+--------------+-------------+ 
|1491|  172|  154| 43|  2|    3|  913|   3|    30|  1|    6|   1| 
+----+----------+---------+---+---------+--------------+---------+----------+----------------+---------+--------------+-------------+ 

注意我有两列有1作为唯一值。我想创建另一个dataframe具备除了这两列的所有列(EducationEmployeeCount

我试图用一个for循环,但不是很高兴,也试过

cd_cols.columns.filter(colName => cd_cols.filter(colName) <= 1) 

,它也无法正常工作。

请问有没有更智能的方法来做到这一点。

感谢

巴拉

+0

如果你不想要这些列,那么只需选择其余的列。 –

+0

@RameshMaharjan,我不会知道它。这一切都取决于前面的语句返回的唯一值。我不能'硬编码'这些列。 –

+0

所以这意味着你想删除那些有1值的列? –

回答

1

你试试下面的命令:

df.selectExpr(df.first().getValuesMap[Int](df.columns).filter(_._2 != 1).keys.toSeq: _*).show 

在这里,我们首先考虑的dataframe的第一行,并将其转换成使用getValueMap与列名的地图并且只是过滤其值不为1的列。

+1

就像魅力一样工作。我不得不作出的一个小修正是将[Int]改为[Long]。 val select_cols = df.selectExpr(df.first()。getValuesMap [Long](df.columns).filter(_._ 2!= 1).keys.toSeq:_ *) 非常感谢帮帮我 –

0

如果您想继续从您的更新最初尝试,以下也应该工作。另外,请注意,使用Spark 2.0以后,您可以将列表传递给drop,然后删除列。关于你在做什么,这可能会更清楚。

或者最坏的情况是另一种方式。

这应该适用于大多数火花版本。

val keptCols: Seq[Column] = df.columns 
     .map(c => (c, df.select(c).first.getLong(0))) 
     .filter{case (c, v) => v!=1} 
     .map{case (c, v) => df(c)} 
     .toSeq 

    df.select(keptCols: _*).show 

对于>火花2.0

val droppedCols: Seq[String] = df.columns 
     .map(c => (c, df.select(c).first.getLong(0))) 
     .filter{case (c, v) => v==1} 
     .map{case (c, v) => c} 
     .toSeq 

    df.drop(droppedCols: _*).show 

两者应该使用相同的结果。