【问题标题】:How do I check if pandas df column value exists based on value in another column?如何根据另一列中的值检查 pandas df 列值是否存在?
【发布时间】:2021-09-19 13:53:26
【问题描述】:

我有一个如下的熊猫数据框

Year ID Value
2016 1 100
2017 1 102
2017 1 105
2018 1 98
2016 2 121
2016 2 101
2016 2 133
2018 3 102

我想检查该 ID 是否仅存在于 2018 年。我想要的输出如下:

Year ID Value ID_only_in_2018
2016 1 100 0
2017 1 102 0
2017 1 105 0
2018 1 98 0
2016 2 121 0
2016 2 101 0
2016 2 133 0
2018 3 102 1

请问,我如何在 python 中实现这一点?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    比较2018 的年份,然后测试是否所有值都只是2018

    mask = df['Year'].eq(2018).groupby(df['ID']).transform('all')
    

    另一个想法是测试 Year 是否不是 2018,过滤 ID 以获得不匹配的至少一个非 2018 行,最后通过 ~ 反转掩码以仅获取 2018 组:

    mask = ~df['ID'].isin(df.loc[df['Year'].ne(2018), 'ID'])
    

    最后将掩码转换为整数:

    df['ID_only_in_2018'] = mask.astype(int)
    

    或者:

    df['ID_only_in_2018'] = np.where(mask, 1, 0)
    

    或者:

    df['ID_only_in_2018'] = mask.view('i1')
    

    print (df)
       Year  ID  Value  ID_only_in_2018
    0  2016   1    100                0
    1  2017   1    102                0
    2  2017   1    105                0
    3  2018   1     98                0
    4  2016   2    121                0
    5  2016   2    101                0
    6  2016   2    133                0
    7  2018   3    102                1
    

    【讨论】:

      【解决方案2】:

      你必须在你的小组中测试ID如果年份是唯一的并且这个唯一的年份是 2018 年:

      df['ID_only_in_2018'] = df.groupby('ID')['Year'] \
                                .apply(lambda y: (y.nunique() == 1) &
                                      (y == 2018)).astype(int)
      
      >>> df
         Year  ID  Value  ID_only_in_2018
      0  2016   1    100                0
      1  2017   1    102                0
      2  2017   1    105                0
      3  2018   1     98                0
      4  2016   2    121                0
      5  2016   2    101                0
      6  2016   2    133                0
      7  2018   3    102                1
      

      【讨论】:

        【解决方案3】:

        对于每组IDs,我们可以检查它们唯一的Years是否等于[2018]isin。然后我们可以在框架中map所有IDs:

        only_2018 = df.groupby("ID").Year.unique().isin([[2018]])
        df["ID_only_in_2018"] = df.ID.map(only_2018).astype(int)
        

        2018 年左右的双括号是因为 unique 给出了一个列表,所以我们放了另一个,astype 是将 True/False 转换为 1/0。

        得到

        >>> df
        
           Year  ID  Value  ID_only_in_2018
        0  2016   1    100                0
        1  2017   1    102                0
        2  2017   1    105                0
        3  2018   1     98                0
        4  2016   2    121                0
        5  2016   2    101                0
        6  2016   2    133                0
        7  2018   3    102                1
        

        only_2018 是:

        ID
        1    False
        2    False
        3     True
        

        【讨论】:

        • 嗯,很有趣。但是,如果按列表与多个值(如df.groupby("ID").Year.unique().isin([[2016, 2017, 2018]]))进行比较,似乎有问题。对于一个运行良好的元素列表。
        • @Emmy 似乎需要一年,但 map(tuple) 并检查元组使其适用于多个值;当涉及到列表时,isin 会发生一些有趣的事情,也许我应该查看源代码...感谢多个值的反馈。
        • 是的,它似乎很少使用,所以它应该是错误的。顺便说一句,这里的比较集应该是避免将isin 与列表一起使用的可能方法。
        【解决方案4】:

        第一次重新创建示例:

        import pandas as pd
        data = [{"Year" : 2016, "ID" : 1, "Value" : 100},
               {"Year" : 2017, "ID" : 1, "Value" : 102},
               {"Year" : 2017, "ID" : 1, "Value" : 105},
               {"Year" : 2018, "ID" : 1, "Value" : 98},
               {"Year" : 2016, "ID" : 2, "Value" : 121},
               {"Year" : 2016, "ID" : 2, "Value" : 101},
               {"Year" : 2016, "ID" : 2, "Value" : 133},
               {"Year" : 2018, "ID" : 3, "Value" : 102}]
        
        df = pd.DataFrame(data)
        

        并仔细查看汇总数据,看看是什么。

        df.groupby("ID")['Year'].apply(list)
        

        返回以下内容:

        ID 1    [2016, 2017, 2017, 2018] 
           2          [2016, 2016, 2016] 
           3                      [2018] Name: Year, dtype: object
        

        所以 ID 1 出现在所有 4 年中,ID 2 出现了 3 次,但只出现在 2016 年,ID 3 只出现一次,在 2018 年这一年。

        将聚合函数从 list 更改为 set 会返回稍微不同的视图:

        df.groupby("ID")['Year'].apply(set)
        
        ID
        1    {2016, 2017, 2018}
        2                {2016}
        3                {2018}
        Name: Year, dtype: object
        

        这显示了 ID 1 如何分布在 3 年中,而 ID 2 和 3 分别仅分布在一年中。

        如果您想测试给定 ID 是否仅与一年相关联,您可以保存并引用其中一个字典,测试所选年份返回的值。

        unique_lookup_set = dict(df.groupby("ID")['Year'].apply(set))
        
        def contains_and_only_contains(value, collection):
            if value in collection and len(set(collection))==1:
                 return 1
            else:
                 return 0
        

        现在尝试用答案生成一个系列,进行测试:

        df.apply(lambda x : contains_and_only_contains(2018, unique_lookup_set.get(x['ID'])), axis=1)
        
        0    0
        1    0
        2    0
        3    0
        4    0
        5    0
        6    0
        7     1
        dtype: int
        

        好,最后,将该系列包含到原始数据框中以获得最终输出。

        df['ID_only_in_2018']=df.apply(lambda x : contains_and_only_contains(2018, unique_lookup_set.get(x['ID'])), axis=1)
        
        df
        
        Year ID Value ID_only_in_2018
        0 2016 1 100 0
        1 2017 1 102 0
        2 2017 1 105 0
        3 2018 1 98 0
        4 2016 2 121 0
        5 2016 2 101 0
        6 2016 2 133 0
        7 2018 3 102 1

        【讨论】:

          猜你喜欢
          • 2022-12-12
          • 2019-11-02
          • 2022-01-24
          • 1970-01-01
          • 2019-02-22
          • 2022-01-23
          • 1970-01-01
          • 2020-10-01
          • 1970-01-01
          相关资源
          最近更新 更多