【问题标题】:How to drop constant columns in pyspark, but not columns with nulls and one other value?如何在 pyspark 中删除常量列,但不删除具有空值和另一个值的列?
【发布时间】:2021-06-27 16:18:26
【问题描述】:

类似的问题被问了好几次。例如这里:How to automatically drop constant columns in pyspark?

但我发现,没有一个答案可以解决countDistinct() 不将空值视为不同值的问题。因此,只有两个结果为 null 和一个非 null 值的列也将被删除。

一个丑陋的解决方案是将 spark 数据框中的所有空值替换为您确定在数据框中其他地方不存在的东西。但就像我说的那样,那真的很难看。

【问题讨论】:

    标签: apache-spark pyspark apache-spark-sql


    【解决方案1】:

    您可以将整数 0 或 1 添加到 countDistinct,这取决于列中是否有空值:

    # example dataframe
    df.show()
    +---+---+----+----+
    |  a|  b|   c|   d|
    +---+---+----+----+
    |  1|  1|   1|null|
    |  1|  2|null|null|
    +---+---+----+----+
    
    import pyspark.sql.functions as F
    
    cnt = df.agg(*[
        (F.countDistinct(c) + F.max(F.col(c).isNull()).cast('int')).alias(c) 
        for c in df.columns
    ])
    
    cnt.show()
    +---+---+---+---+
    |  a|  b|  c|  d|
    +---+---+---+---+
    |  1|  2|  2|  1|
    +---+---+---+---+
    
    df.drop(*[c for c in cnt.first().asDict() if cnt.first()[c] == 1]).show()
    +---+----+
    |  b|   c|
    +---+----+
    |  1|   1|
    |  2|null|
    +---+----+
    

    【讨论】:

    • 谢谢。这听起来很合乎逻辑。在我接受你的回答之前,让我快速检查一下。
    • 说实话我不确定。我在我的数据的一个“小”子集上尝试了它,但在几个小时后它没有完成(350 万行和 100 列)。我将在今天晚些时候在一个更小的子集上尝试它。你知道 F.max(F.col(c).isNull()).cast('int') 是不是特别慢吗?
    • 我认为countDistinct 会慢得多,但没有什么可以加快速度...它确实需要遍历整个数据集。
    • 好的,我尝试了一些方法。我首先有一个问题:cast("int") 是否应该在 F.max 函数中?我改变了这个,你的代码在一个普通的集群上花了 18 分钟来处理 7000 行和 92 列。相比之下,df.agg(*(countDistinct(col(c)).alias(c) for c in df.columns)).show() 耗时不到 10 秒。这不是很奇怪吗?但我可以确认您的代码符合预期的用途:)
    • 似乎cast("int) 在F.max() 函数之外也可以正常工作。我会接受你的回答,因为它有效。仍然会对为什么需要这么长时间感兴趣。
    猜你喜欢
    • 1970-01-01
    • 2021-11-19
    • 2018-12-21
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多