从pyspark数据框中删除空列

时间:2020-04-16 05:11:34

标签: python apache-spark pyspark data-cleaning

我有一个非常脏的csv,其中有几列只有空值。

我想删除它们。我试图选择所有列中的空值计数不等于行数的所有列。

clean_df = bucketed_df.select([c for c in bucketed_df.columns if count(when(isnull(c), c)) not bucketed_df.count()])

但是,出现此错误:

SyntaxError: invalid syntax
  File "<command-2213215314329625>", line 1
    clean_df = bucketed_df.select([c for c in bucketed_df.columns if count(when(isnull(c), c)) not bucketed_df.count()])
                                                                                                             ^
SyntaxError: invalid syntax

如果有人可以帮助我摆脱这些肮脏的专栏,那就太好了。

3 个答案:

答案 0 :(得分:0)

有两种方法可以解决此问题,

1)编写UDF函数以添加一个列,如果所需列(您正在检查NULL的列)的值为NULL,则该列的值为1,然后对列求和,如果总和等于到行数,然后删除列

2)使用amazon spark dq库(spark的开源数据质量库),该库具有用于配置数据的功能,dq返回的列之一是每一列的完整性因子,如果完整性因子为1,则整个列的值为NULL,您可以删除这些列 我个人认为此选项很棒,因为它旨在使用spark进行数据质量检查

下面的链接中有很多示例

https://aws.amazon.com/blogs/big-data/test-data-quality-at-scale-with-deequ/ https://github.com/awslabs/deequ

答案 1 :(得分:0)

可以使用函数“ min”,并且可以删除具有空值的列。在Scala上,可以轻松将其翻译成Python:

// data sample
val df = Seq(("Bug", null.asInstanceOf[Integer], null.asInstanceOf[String]),
  ("Termit", null.asInstanceOf[Integer], null.asInstanceOf[String]))
  .toDF("name", "size", "type")
val fieldNames = df.schema.fieldNames

// get null values 
val fieldExpressions = fieldNames.map(c => min(c).alias(c))
val firstRow = df.select(fieldExpressions: _*).collect().head

val fieldsToDrop = fieldNames.filter(f => firstRow.isNullAt(fieldNames.indexOf(f)))

答案 2 :(得分:0)

我对pyspark的经验很少,但是用counts创建一个数据帧并将其转换为pandas可能不是一个坏主意,因为counts数据帧只有一行:

从如下所示的数据帧开始,并另存为null_df

+---+---+---+----+
|  A|  B|  C|   D|
+---+---+---+----+
|  1|  a|  b|null|
|  2|  c|  d|null|
|  3|  e|  f|null|
+---+---+---+----+

import pyspark.sql.functions as F

counts = null_df.select([F.count(i).alias(i) for i in null_df.columns]).toPandas()
output = null_df.select(*counts.columns[counts.ne(0).iloc[0]])

或者甚至将整个第一行都转换成字典,然后遍历字典

counts1 = null_df.select([F.count(i).alias(i) for i in null_df.columns])
output2 = null_df.select([k for k,v in counts1.first().asDict().items() if v >0])

显示以下内容:

+---+---+---+
|  A|  B|  C|
+---+---+---+
|  1|  a|  b|
|  2|  c|  d|
|  3|  e|  f|
+---+---+---+

在我的系统中测试过的基准:

%%timeit
counts = null_df.select([F.count(i).alias(i) for i in null_df.columns]).toPandas()
output = null_df.select(*counts.columns[counts.ne(0).iloc[0]])
#8.73 s ± 412 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
counts1 = null_df.select([F.count(i).alias(i) for i in null_df.columns])
output2 = null_df.select([k for k,v in counts1.first().asDict().items() if v >0])
#9.43 s ± 253 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
counts1 = null_df.select([F.count(i).alias(i) for i in null_df.columns])
output1 = null_df.select([c for c in counts1.columns if counts1[[c]].first()[c] > 0])
#35.3 s ± 1 s per loop (mean ± std. dev. of 7 runs, 1 loop each)