【问题标题】:spark dataset filter column with conditions like pandas具有熊猫等条件的火花数据集过滤器列
【发布时间】:2017-12-23 22:36:37
【问题描述】:

我是 Spark/Scala 的新手。我不知道如何使用 spark 数据集来过滤 pandas.loc 之类的列。

熊猫代码:

data_fact = pd.read_excel(path, sheetname=sheetname_factor)
//drop some columns which have too many null value
data_fact_v1=data_fact.loc[:,((data_fact>0).sum()>len(data_fact) *0.7)]

非常感谢您的帮助!

【问题讨论】:

    标签: scala pandas apache-spark dataset apache-spark-ml


    【解决方案1】:

    我会为此使用 RDD,因为 API 更灵活。在下面的代码中,我将每一行映射到一个 tuple2 列表,如果字段的值为空,则列名关联为 0,否则为 1。然后我将所有内容展平并使用reduceByKey 计算每列非空值的数量。我终于在原始数据框中删除了与您的要求不匹配的列。

    var data = ...
    val cols = data.columns
    val total = data.count
    
    val nullMap = data.rdd
        .flatMap{row => cols.filter(col => row.getAs(col) == null).map(col => (col, 1) ) }
        .reduceByKey(_+_)
        .collectAsMap
    
    for(col <- cols) 
        if(nullMap.getOrElse(col, 0).toDouble / total < 0.7)
            data = data.drop(col)
    

    编辑其他方法:为避免数据扁平化,可以使用聚合函数

    def combine(map1 : Map[String, Int], map2 : Map[String, Int]) = 
        map1.keySet
            .union(map2.keySet)
            .map(k => (k, map1.getOrElse(k, 0)+map2.getOrElse(k, 0)))
            .toMap
    
    val nullMap = data.rdd.aggregate(Map[String, Int]())(
         (map, row)=> combine(map, cols.filter(col => row.getAs(col) == null).map(col => (col, 1)).toMap),
         combine)
    

    然后是一样的

    for(col <- cols) 
        if(nullMap.getOrElse(col, 0).toDouble / total >= 0.3)
            data = data.drop(col)
    

    或者

    val valid_columns = cols
        .filter(col => nullMap.getOrElse(col, 0).toDouble / total >= 0.3)
    data = data.drop(valid_columns : _*)
    

    【讨论】:

    • 有效,但效率低,耗时15分钟。我的测试数据有 3000 行和 1000 列。因为pandas处理这个速度很快,spark有没有更有效的方法?
    • 我编辑了代码以加快速度。我只展平空值。然而,对于这么小的数据集来说,15 分钟似乎确实很大。你用的是什么配置?
    • 我添加了另一种完全避免扁平化的方法(第一次编辑只是减少了它)。如果您仍有性能问题,请告诉我们。
    • 我调试代码,发现: data = data.drop(col) 占用了大部分时间。因为我从 1000 列中删除了 950 列。
    • 我添加了一个只调用 drop 一次的版本。知道现在是否会好转会很有趣……
    【解决方案2】:

    您可以遍历数据框的列并删除具有多个空值的列。

    val cols = data.columns
    val limit = data.count * 0.7
    
    for(mycol <- cols){
       if (data.filter(col(mycol).isNotNull).count < limit){
           data = data.drop(mycol)
       }
    }
    

    【讨论】:

    • 您的方法可行,但每列会生成一个任务,这可能会很昂贵。
    猜你喜欢
    • 1970-01-01
    • 2016-06-23
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多