什么是最惯用(也是最有效的)方法,只选择那些包含至少一个 NOT NULL 值的数据帧/数据集列。
即具有以下数据集:
+----+----+------+----+---------------------+----+
|int1|int2|str1 |str2|dt1 |dt2 |
+----+----+------+----+---------------------+----+
|1 |null|strin1|null|null |null|
|null|null|null |null|2000-01-03 12:12:12.0|null|
+----+----+------+----+---------------------+----+
我将如何获得以下一个:
+----+------+---------------------+
|int1|str1 |dt1 |
+----+------+---------------------+
|1 |strin1|null |
|null|null |2000-01-03 12:12:12.0|
+----+------+---------------------+
有一个适用于Apache Spark版本1.6.0 +的解决方案会很好
数据设置:
case class C(int1: Integer, int2: Integer, str1: String, str2: String, dt1: String, dt2: String)
val cc = Seq(
C(1, null, "strin1", null, null, null),
C(null, null, null, null, "2000-01-03 12:12:12", null)
)
val t = sc.parallelize(cc, 2).toDF()
val df = t.withColumn("dt1", $"dt1".cast("timestamp")).withColumn("dt2", $"dt2".cast("timestamp"))
更新:
PS感谢@user8371915指出非常相似的问题。我想让这个问题悬而未决,希望找到一个更优雅的解决方案 - 我试图找到一种方法来使用类似的东西:
df.columns.filter(c => when(count(col(c))>0,c))
但是我不知道如何正确地做到这一点...
使用与这个伟大答案中描述的方法非常相似的方法:
val cols = df.select(df.columns.map(c => count(col(c)).alias(c)): _*)
.collect()(0)
.toSeq.zipWithIndex
.filter(_._1 != 0).map(_._2)
.map(i => df.columns.apply(i))
这为我们提供了一个我们正在寻找的列数组:
scala> cols
res125: Seq[String] = ArrayBuffer(int1, str1, dt1)
现在我们可以选择这些列:
scala> df.select(cols.head, cols.tail: _*).show
+----+------+--------------------+
|int1| str1| dt1|
+----+------+--------------------+
| 1|strin1| null|
|null| null|2000-01-03 12:12:...|
+----+------+--------------------+
或
scala> df.select(cols.map(col): _*).show
+----+------+--------------------+
|int1| str1| dt1|
+----+------+--------------------+
| 1|strin1| null|
|null| null|2000-01-03 12:12:...|
+----+------+--------------------+