Pyspark 迭代数据帧&;递归滤波器

Pyspark 迭代数据帧&;递归滤波器,pyspark,databricks,Pyspark,Databricks,我有两个数据帧。“MinNRule”和“SampleData” MinNRule提供了一些规则信息,SampleData需要基于这些信息: 在MinNRule.MinimumNPopulation和MinNRule.OrderOfOperation中定义的列上聚合“样本数据” 检查Aggregate.Entity>=MinNRule.MinimumNValue a。对于不符合MinNRule.MinimumNValue的所有实体,请从总体中删除 b。对于满足MinNRule.MinimumNV

我有两个数据帧。“MinNRule”和“SampleData” MinNRule提供了一些规则信息,SampleData需要基于这些信息:

  • 在MinNRule.MinimumNPopulation和MinNRule.OrderOfOperation中定义的列上聚合“样本数据”

  • 检查Aggregate.Entity>=MinNRule.MinimumNValue

    a。对于不符合MinNRule.MinimumNValue的所有实体,请从总体中删除

    b。对于满足MinNRule.MinimumNValue的所有实体,保留在人口中

  • 使用2.b数据集对下一个MinNRule.OrderOfOperation执行1到2

  • 拟议的步骤:

  • 读取规则,读取操作顺序为1的规则

    a。分组设施,依靠人

    b。按1.a聚合样本数据,并与最小值=6进行比较

  • 选择MinNPass='Y'行并将初始数据帧向下过滤到这些实体(F2被删除)
  • 读取规则,读取操作顺序为2的规则

    a。GroupBy项目,依靠人

    b。按3.a聚合样本数据,并与最小值=4进行比较

  • 选择MinNPass='Y'行,并将数据帧过滤到3个实体中(P2被删除)
  • 打印最终结果
  • 想法:

  • 我一直在考虑将MinNRule移动到一个LocalIterator,循环遍历它并“过滤”样本数据
  • 我不知道如何将一个循环结束时的结果传递给另一个循环
  • 仍在学习Pyspark,不确定这是否是正确的方法。 我正在使用Azure Databricks

  • IIUC,因为规则df定义了规则,因此它必须很小,并且可以收集到驱动程序,以便对主数据执行操作

    获得所需结果的一种方法是收集规则df并将其传递给reduce函数,如下所示:

    data = MinNRule.orderBy('OrderOfOperation').collect()
    
    from pyspark.sql.functions import *
    from functools import reduce
    
    dfnew = reduce(lambda df, rules: df.groupBy(col(rules.MinimumNPopulation.split('by')[1].strip())).\
           agg(count(col({'People':'PeopleID'}.get(rules.MinimumNPopulation.split('by')[0].strip()))).alias('count')).\
           filter(col('count')>=rules.MinimumNValue).drop('count').join(df,rules.MinimumNPopulation.split('by')[1].strip(),'inner'), data, sampleData)
    
    dfnew.show()
    
    +-------+--------+--------+
    |Project|Facility|PeopleID|
    +-------+--------+--------+
    |     P1|      F1|  166152|
    |     P1|      F1|  425906|
    |     P1|      F1|  332127|
    |     P1|      F1|  241630|
    +-------+--------+--------+
    
    
    或者,您也可以通过df进行循环,并获得在这两种情况下性能保持不变的结果

    import pyspark.sql.functions as f
    mapped_cols = {'People':'PeopleID'}
    data = MinNRule.orderBy('OrderOfOperation').collect()
    for i in data:
        cnt, grp = i.MinimumNPopulation.split('by')
        cnt = mapped_cols.get(cnt.strip())
        grp = grp.strip()
        sampleData = sampleData.groupBy(f.col(grp)).agg(f.count(f.col(cnt)).alias('count')).\
        filter(f.col('count')>=i.MinimumNValue).drop('count').join(sampleData,grp,'inner')
    
    sampleData.show()
    +-------+--------+--------+
    |Project|Facility|PeopleID|
    +-------+--------+--------+
    |     P1|      F1|  166152|
    |     P1|      F1|  425906|
    |     P1|      F1|  332127|
    |     P1|      F1|  241630|
    +-------+--------+--------+
    
    

    注意:您必须手动解析您的规则语法,因为它可能会发生更改

    谢谢。我会试试这个。关于规则语法,我计划使用dict来查找需要“分组”的内容和需要“计数”的内容,然后将它们传递到reduce中。或者,您也可以传递第三个参数来reduce,其中部分包含您的规则dict,如果有帮助,请接受答案:)
                | Facility  | Project   | PeopleID  |
                |:--------: |:-------:  |:--------: |
                |    F1     |    P1     |  166152   |
                |    F1     |    P1     |  425906   |
                |    F1     |    P1     |  332127   |
                |    F1     |    P1     |  241630   |
                |    F1     |    P2     |  373865   |
                |    F1     |    P2     |  120672   |
                |    F1     |    P2     |  369407   |
    
            | Project   | Count     | MinNPass  |
            |:--------: |:-------:  |:--------: |
            |    P1     |    4      |  Y        |
            |    P2     |    3      |  N        | 
    
                | Facility  | Project   | PeopleID  |
                |:--------: |:-------:  |:--------: |
                |    F1     |    P1     |  166152   |
                |    F1     |    P1     |  425906   |
                |    F1     |    P1     |  332127   |
                |    F1     |    P1     |  241630   |
    
    data = MinNRule.orderBy('OrderOfOperation').collect()
    
    from pyspark.sql.functions import *
    from functools import reduce
    
    dfnew = reduce(lambda df, rules: df.groupBy(col(rules.MinimumNPopulation.split('by')[1].strip())).\
           agg(count(col({'People':'PeopleID'}.get(rules.MinimumNPopulation.split('by')[0].strip()))).alias('count')).\
           filter(col('count')>=rules.MinimumNValue).drop('count').join(df,rules.MinimumNPopulation.split('by')[1].strip(),'inner'), data, sampleData)
    
    dfnew.show()
    
    +-------+--------+--------+
    |Project|Facility|PeopleID|
    +-------+--------+--------+
    |     P1|      F1|  166152|
    |     P1|      F1|  425906|
    |     P1|      F1|  332127|
    |     P1|      F1|  241630|
    +-------+--------+--------+
    
    
    import pyspark.sql.functions as f
    mapped_cols = {'People':'PeopleID'}
    data = MinNRule.orderBy('OrderOfOperation').collect()
    for i in data:
        cnt, grp = i.MinimumNPopulation.split('by')
        cnt = mapped_cols.get(cnt.strip())
        grp = grp.strip()
        sampleData = sampleData.groupBy(f.col(grp)).agg(f.count(f.col(cnt)).alias('count')).\
        filter(f.col('count')>=i.MinimumNValue).drop('count').join(sampleData,grp,'inner')
    
    sampleData.show()
    +-------+--------+--------+
    |Project|Facility|PeopleID|
    +-------+--------+--------+
    |     P1|      F1|  166152|
    |     P1|      F1|  425906|
    |     P1|      F1|  332127|
    |     P1|      F1|  241630|
    +-------+--------+--------+