Pandas 如何编写一个函数来迭代数据帧组并应用分层条件?

Pandas 如何编写一个函数来迭代数据帧组并应用分层条件?,pandas,group-by,iteration,filtering,hierarchical,Pandas,Group By,Iteration,Filtering,Hierarchical,我需要编写一个函数来根据一些层次条件过滤数据集。此函数的目的是为一组蛋白质中的每一种蛋白质获得一个注释 该函数需要执行以下操作: 按“id”列对蛋白质进行分组 检查蛋白质组中的每个分析 以优先顺序选择分析(这不是排序问题,因此分析应按条件顺序进行,以便以后可以重新排序)。首先,检查analysis_1(如果不存在),然后进行analysis_2或analysis_3等 将行放入新的数据框中 下面是一个将被过滤的数据示例 df=pd.DataFrame({ 'id': ['Protein

我需要编写一个函数来根据一些层次条件过滤数据集。此函数的目的是为一组蛋白质中的每一种蛋白质获得一个注释

该函数需要执行以下操作:

  • 按“id”列对蛋白质进行分组
  • 检查蛋白质组中的每个分析
  • 以优先顺序选择分析(这不是排序问题,因此分析应按条件顺序进行,以便以后可以重新排序)。首先,检查analysis_1(如果不存在),然后进行analysis_2或analysis_3等
  • 将行放入新的数据框中
  • 下面是一个将被过滤的数据示例

    df=pd.DataFrame({
    'id':      ['Protein_1', 'Protein_1', 'Protein_1', 
              'Protein_2','Protein_2','Protein_2'],
    'analysis': ['analysis_6', 'analysis_4', 'analysis_1', 
                     'analysis_3','analysis_2','analysis_5'],
    'annotation':['annotation_1', 'annotation_2', 'annotation_3',
                  'annotation_1','annotation_2','annotation_3'] })
    
    这是我想看到的输出

    df_filtered= pd.DataFrame({
    'id':      ['Protein_1','Protein_2'],
    'analysis': ['analysis_1', 'analysis_2'],
    'annotation':['annotation_3', 'annotation_2'] })
    
    下面的代码正在运行,但我希望使用pandas groupby、apply和iterrows函数来实现

    new_df =pd.DataFrame(columns=df.columns)
    protein_id=list(df.id.unique())
    
    for protein in protein_id:
    
    data=df[df["id"] == protein]
    
    if len(data[data["analysis"] =="analysis_1"]) == 0:
        
        if len(data[data["analysis"] =="analysis_2"]) == 0:
            
            if len(data[data["analysis"] =="analysis_3"]) == 0:
                pass
            else:
                data2=data[data["analysis"] =="analysis_3"]
                new_df = pd.concat([new_df,data2])
            
        else:
            data2=data[data["analysis"] =="analysis_2"]
            new_df = pd.concat([new_df,data2])
        
    else:
        data2=data[data["analysis"] =="analysis_1"]
        new_df = pd.concat([new_df,data2])
        
    new_df
    

    谢谢你的帮助

    您可以使用矢量化方法来执行此操作,如果
    分析
    列遵循相同的模式,您可以按
    \uu
    进行拆分,并获得最后一个整数层次结构:

    方法1:(如果每个组可以有重复的最小层次结构)


    方法2:

    helper_s = df['analysis'].str.split("_").str[-1].astype(int)
    out = df.loc[df.assign(helper_s=helper_s).groupby("id")['helper_s'].idxmin()]
    

    您可以暂时对数据帧进行排序,然后为每个id删除除一个之外的所有条目。如下所示:

    df.sort_values('analysis').drop_duplicates(['id'], keep='first')
    
              id    analysis    annotation
    2  Protein_1  analysis_1  annotation_3
    4  Protein_2  analysis_2  annotation_2
    
    请注意,这不会更改原始数据帧中的顺序。结果如下所示:

    df.sort_values('analysis').drop_duplicates(['id'], keep='first')
    
              id    analysis    annotation
    2  Protein_1  analysis_1  annotation_3
    4  Protein_2  analysis_2  annotation_2
    
    如果您有一个返回分析优先级的函数,您可以将其与上述方法结合使用:

    def prio_function(analysis):
        # return a low number for a better result
        # and a high number for a worse result
        return int(analysis.split('_')[1])  # replace this row by your code
    
    df_work= df.assign(_prio=df['analysis'].apply(prio_function))
    df_work.sort_values('_prio').drop_duplicates(['id'], keep='first').drop(columns='_prio')
    

    如果优先级更简单,您还可以将一个dictionary传递给
    apply
    ,而不是传递一个函数。

    您为什么说这不是排序问题?为什么你认为排序不是正确的方法(见下面我建议的答案)。排序只能通过对分析进行优先级排序来完成,而不能通过它们的名称或顺序来完成。我写analysis_1和analysis_2只是为了举个例子。好的,我明白了,但是我认为你应该提供一个从实际分析值到它的优先级的映射,以防它们不是按数字顺序排列的。您需要指定什么更好,以及如何确定它更好,否则就不可能提供选择最佳结果的解决方案。不幸的是,分析列中填充了几个数据库,如PANTHER、Pfam、Gene3D等。不可能根据它们的字符串对它们进行排序。是的,这完全有意义。我已经更改了分析名称df[“analysis”]=df[“analysis”].str.replace('PANTHER','PANTHER_1'),然后使用prio_函数作为排序方法。现在它工作得非常好。非常感谢你!谢谢你的反馈。我很高兴它成功了。如果你愿意,你可以把它标记为答案。现在,也许使用apply函数为一打不同的分析做字符串更改会很好,但我不知道如何做。你说的“为一打不同的分析做字符串更改”是什么意思?我认为您应该创建一个函数,它只返回一个分数,这是一个序号,可以帮助您确定最相关的分析。因此,如果您可以通过检查它们是否包含关键字来识别它们,您只需按特定顺序检查这些关键字是否存在并返回结果分数。我的意思是将字符串例如“PANTHER”替换为“PANTHER_1”,就像我用str.replace()所做的那样函数,但正如您所提到的,我需要对它们进行评分,我认为手动更改分析字符串对于这个问题来说要容易得多。
    def prio_function(analysis):
        # return a low number for a better result
        # and a high number for a worse result
        return int(analysis.split('_')[1])  # replace this row by your code
    
    df_work= df.assign(_prio=df['analysis'].apply(prio_function))
    df_work.sort_values('_prio').drop_duplicates(['id'], keep='first').drop(columns='_prio')