如何删除具有太多NULL值的行?

时间:2016-03-17 14:05:10

标签: scala apache-spark dataframe apache-spark-sql

我想对我的数据进行一些预处理,并且我想删除稀疏的行(对于某个阈值)。

例如,我有一个包含10个功能的数据帧表,并且我有一个8位空值的行,然后我想删除它。

我找到了一些相关主题,但我找不到任何有用的信息。

stackoverflow.com/questions/3473778/count-number-of-nulls-in-a-row

上面链接中的示例对我来说不起作用,因为我想自动执行此预处理。我不能写列名并做相应的事情。

那么无论如何在没有使用带有scala的Apache Spark中的列名来执行此删除操作?

4 个答案:

答案 0 :(得分:3)

考试日期:

case class Document( a: String, b: String, c: String)
val df = sc.parallelize(Seq(new Document(null, null, null), new Document("a", null, null), new Document("a", "b", null), new Document("a", "b", "c"), new Document(null, null, "c"))).df

使用UDF

通过以下David和我的RDD版本重新混合答案,您可以使用占用一行的UDF来完成:

def nullFilter = udf((x:Row) => {Range(0, x.length).count(x.isNullAt(_)) < 2})
df.filter(nullFilter(struct(df.columns.map(df(_)) : _*))).show

使用RDD

您可以将其转换为Row中列的rdd循环,并计算有多少为null。

sqlContext.createDataFrame(df.rdd.filter( x=> Range(0, x.length).count(x.isNullAt(_)) < 2 ), df.schema).show

答案 1 :(得分:2)

使用UDF更清洁:

import org.apache.spark.sql.functions.udf
def countNulls = udf((v: Any) => if (v == null) 1; else 0;))
df.registerTempTable("foo")

sqlContext.sql(
  "select " + df.columns.mkString(", ") + ", " + df.columns.map(c => {
    "countNulls(" + c + ")"
  }).mkString(" + ") + "as nullCount from foo"
).filter($"nullCount" > 8).show

如果使查询字符串让您感到紧张,那么您可以试试这个:

var countCol: org.apache.spark.sql.Column = null
df.columns.foreach(c => {
  if (countCol == null) countCol = countNulls(col(c))
  else countCol = countCol + countNulls(col(c)) 
});

df.select(Seq(countCol as "nullCount") ++ df.columns.map(c => col(c)):_*)
  .filter($"nullCount" > 8)

答案 2 :(得分:2)

我很惊讶没有答案指出Spark SQL只有很少的标准功能符合要求:

  

例如,我有一个包含10个功能的数据帧表,并且我有一个8位空值的行,然后我想删除它。

你可以使用DataFrameNaFunctions.drop方法的一种变体,minNonNulls设置得恰当,比如2。

  

drop(minNonNulls:Int,cols:Seq [String]):DataFrame 返回一个新的DataFrame,它删除指定列中包含少于minNonNulls非空和非NaN值的行。 / p>

并且要满足要求中列名的可变性:

  

我不能写列名并做相应的事情。

您只需使用Dataset.columns

即可
  

columns:Array [String] 以数组形式返回所有列名。

假设您拥有以下数据集,其中包含5个要素(列)和几乎所有null的几行。

val ns: String = null
val features = Seq(("0","1","2",ns,ns), (ns, ns, ns, ns, ns), (ns, "1", ns, "2", ns)).toDF
scala> features.show
+----+----+----+----+----+
|  _1|  _2|  _3|  _4|  _5|
+----+----+----+----+----+
|   0|   1|   2|null|null|
|null|null|null|null|null|
|null|   1|null|   2|null|
+----+----+----+----+----+

// drop rows with more than (5 columns - 2) = 3 nulls
scala> features.na.drop(2, features.columns).show
+----+---+----+----+----+
|  _1| _2|  _3|  _4|  _5|
+----+---+----+----+----+
|   0|  1|   2|null|null|
|null|  1|null|   2|null|
+----+---+----+----+----+

答案 3 :(得分:1)

以下是Spark 2.0的替代方案:

val df = Seq((null,"A"),(null,"B"),("1","C"))
         .toDF("foo","bar")
         .withColumn("foo", 'foo.cast("Int"))

df.show()

+----+---+
| foo|bar|
+----+---+
|null|  A|
|null|  B|
|   1|  C|
+----+---+

df.where('foo.isNull).groupBy('foo).count().show()

+----+-----+
| foo|count|
+----+-----+
|null|    2|
+----+-----+