【问题标题】:How to determine whether a Pandas Column contains a particular value如何确定 Pandas 列是否包含特定值
【发布时间】:2014-02-14 16:40:46
【问题描述】:

我正在尝试确定 Pandas 列中是否存在具有特定值的条目。我试图用if x in df['id'] 来做到这一点。我认为这是可行的,除非我给它提供了一个我知道不在列 43 in df['id'] 中的值,它仍然返回 True。当我对仅包含与缺少的 id df[df['id'] == 43] 匹配的条目的数据框进行子集时,显然其中没有条目。如何确定 Pandas 数据框中的列是否包含特定值,为什么我当前的方法不起作用? (仅供参考,当我将这个answer 中的实现用于类似问题时,我遇到了同样的问题)。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    in 的 Series 检查值是否在索引中:

    In [11]: s = pd.Series(list('abc'))
    
    In [12]: s
    Out[12]: 
    0    a
    1    b
    2    c
    dtype: object
    
    In [13]: 1 in s
    Out[13]: True
    
    In [14]: 'a' in s
    Out[14]: False
    

    一种选择是查看它是否在unique 值中:

    In [21]: s.unique()
    Out[21]: array(['a', 'b', 'c'], dtype=object)
    
    In [22]: 'a' in s.unique()
    Out[22]: True
    

    或python集:

    In [23]: set(s)
    Out[23]: {'a', 'b', 'c'}
    
    In [24]: 'a' in set(s)
    Out[24]: True
    

    正如@DSM 所指出的,直接在值上使用 in 可能更有效(特别是如果您只是为一个值执行此操作):

    In [31]: s.values
    Out[31]: array(['a', 'b', 'c'], dtype=object)
    
    In [32]: 'a' in s.values
    Out[32]: True
    

    【讨论】:

    • 我不想知道它是否一定是唯一的,主要是想知道它是否存在。
    • 我认为 'a' in s.values 对于长系列应该更快。
    • @AndyHayden 你知道为什么对于'a' in s,pandas 选择检查索引而不是序列的值吗?在字典中他们检查键,但熊猫系列应该更像一个列表或数组,不是吗?
    • 从 pandas 0.24.0 开始,使用 s.values 和 df.values 是非常不受欢迎的。见this。此外,s.values 在某些情况下实际上要慢得多。
    • @QusaiAlothman 既不是.to_numpy 也不是.array 在系列中可用,所以我不完全确定他们提倡什么替代方案(我没有读到“非常气馁”)。事实上,他们说 .values 可能不会返回一个 numpy 数组,例如在分类的情况下......但这很好,因为in 仍然可以按预期工作(实际上比它的 numpy 数组对应物更有效)
    【解决方案2】:

    你也可以使用pandas.Series.isin,虽然它比'a' in s.values长一点:

    In [2]: s = pd.Series(list('abc'))
    
    In [3]: s
    Out[3]: 
    0    a
    1    b
    2    c
    dtype: object
    
    In [3]: s.isin(['a'])
    Out[3]: 
    0    True
    1    False
    2    False
    dtype: bool
    
    In [4]: s[s.isin(['a'])].empty
    Out[4]: False
    
    In [5]: s[s.isin(['z'])].empty
    Out[5]: True
    

    但如果您需要一次为 DataFrame 匹配多个值,这种方法会更加灵活(请参阅DataFrame.isin)

    >>> df = DataFrame({'A': [1, 2, 3], 'B': [1, 4, 7]})
    >>> df.isin({'A': [1, 3], 'B': [4, 7, 12]})
           A      B
    0   True  False  # Note that B didn't match 1 here.
    1  False   True
    2   True   True
    

    【讨论】:

    【解决方案3】:
    found = df[df['Column'].str.contains('Text_to_search')]
    print(found.count())
    

    found.count() 将包含匹配数

    如果为 0,则表示在列中未找到字符串。

    【讨论】:

    • 为我工作,但我使用 len(found) 来获取计数
    • 是的 len(found) 是一个更好的选择。
    • 这种方法对我有用,但我必须为我的用例包含参数 na=False 和 regex=False,如下所述:pandas.pydata.org/pandas-docs/stable/reference/api/…
    • 但是 string.contains 会进行子字符串搜索。例如:如果存在名为“head_hunter”的值。在 str.contains 中传递“head”匹配并给出错误的 True。
    • @karthikeyan 它没有错。取决于您的搜索上下文。如果您正在搜索地址或产品怎么办。您需要符合描述的所有产品。
    【解决方案4】:

    我做了一些简单的测试:

    In [10]: x = pd.Series(range(1000000))
    
    In [13]: timeit 999999 in x.values
    567 µs ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    In [24]: timeit 9 in x.values
    666 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    In [16]: timeit (x == 999999).any()
    6.86 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [21]: timeit x.eq(999999).any()
    7.03 ms ± 33.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [22]: timeit x.eq(9).any()
    7.04 ms ± 60 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [15]: timeit x.isin([999999]).any()
    9.54 ms ± 291 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [17]: timeit 999999 in set(x)
    79.8 ms ± 1.98 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    有趣的是,查找 9 或 999999 并不重要,使用 in 语法似乎需要相同的时间(必须使用一些矢量化计算)

    In [24]: timeit 9 in x.values
    666 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    In [25]: timeit 9999 in x.values
    647 µs ± 5.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    In [26]: timeit 999999 in x.values
    642 µs ± 2.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    In [27]: timeit 99199 in x.values
    644 µs ± 5.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    In [28]: timeit 1 in x.values
    667 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    似乎使用 x.values 是最快的,但也许在 pandas 中有更优雅的方式?

    【讨论】:

    • 如果您将结果的顺序从最小到最大更改,那就太好了。干得好!
    【解决方案5】:

    或者使用Series.tolist或Series.any:

    >>> s = pd.Series(list('abc'))
    >>> s
    0    a
    1    b
    2    c
    dtype: object
    >>> 'a' in s.tolist()
    True
    >>> (s=='a').any()
    True
    

    Series.tolist 列出了一个Series 的列表,而另一个我只是从普通的Series 得到一个布尔值Series,然后检查布尔值@ 中是否有Trues 987654329@.

    【讨论】:

      【解决方案6】:

      您可以尝试检查名为“id”的特定列中的特定值“x”

      if x in df['id'].values
      

      【讨论】:

        【解决方案7】:

        简单条件:

        if any(str(elem) in ['a','b'] for elem in df['column'].tolist()):
        

        【讨论】:

          【解决方案8】:

          使用

          df[df['id']==x].index.tolist()
          

          如果x 存在于id 中,那么它将返回它存在的索引列表,否则它会给出一个空列表。

          【讨论】:

            【解决方案9】:

            假设你的数据框看起来像:

            现在您要检查文件名“80900026941984”是否存在于数据框中。

            你可以简单地写:

            if sum(df["filename"].astype("str").str.contains("80900026941984")) > 0:
                print("found")
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-11-10
              • 2012-09-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多