【问题标题】:Pandas dataframe select rows where a list-column contains any of a list of strings熊猫数据框选择列表列包含任何字符串列表的行
【发布时间】:2018-11-16 17:29:34
【问题描述】:

我有一个看起来像这样的 pandas DataFrame:

  molecule            species
0        a              [dog]
1        b       [horse, pig]
2        c         [cat, dog]
3        d  [cat, horse, pig]
4        e     [chicken, pig]

我喜欢提取一个只包含那些行的 DataFrame,这些行包含selection = ['cat', 'dog'] 中的任何一个。所以结果应该是这样的:

  molecule            species
0        a              [dog]
1        c         [cat, dog]
2        d  [cat, horse, pig]

最简单的方法是什么?

用于测试:

selection = ['cat', 'dog']
df = pd.DataFrame({'molecule': ['a','b','c','d','e'], 'species' : [['dog'], ['horse','pig'],['cat', 'dog'], ['cat','horse','pig'], ['chicken','pig']]})

【问题讨论】:

  • 使用df = df.loc[df.species.str.contains('cat|dog'),:]

标签: python pandas dataframe


【解决方案1】:

IIUC 重新创建您的 df 然后使用 isinany 应该比 apply 更快

df[pd.DataFrame(df.species.tolist()).isin(selection).any(1).values]
Out[64]: 
  molecule            species
0        a              [dog]
2        c         [cat, dog]
3        d  [cat, horse, pig]

【讨论】:

  • 这很好 - 唯一需要注意的是,如果您的索引不是顺序整数(我的具体问题,而不是 OP),您必须在数据帧构造函数中添加一个 index=df.index 参数.例如df[pd.DataFrame(df.species.tolist(), index=df.index).isin(selection).any(1)]
  • @James_SO 最后添加值~
【解决方案2】:

您可以在此处使用maskapply

selection = ['cat', 'dog']

mask = df.species.apply(lambda x: any(item for item in selection if item in x))
df1 = df[mask]

对于您在上面作为示例提供的 DataFrame,df1 将是:

molecule    species
0   a   [dog]
2   c   [cat, dog]
3   d   [cat, horse, pig]

【讨论】:

  • 鉴于@NicoH 正在寻找“猫”或“狗”的存在,我建议将掩码更改为mask = df.species.apply(lambda x: any(item for item in selection if item in x))
  • @rs311 同意 - 使用选择示例更新了 lambda
【解决方案3】:

在这种情况下,使用 Numpy 会比使用 Pandas 快得多,

选项 1:使用 numpy 交集,

mask =  df.species.apply(lambda x: np.intersect1d(x, selection).size > 0)
df[mask]
450 µs ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

    molecule    species
0   a   [dog]
2   c   [cat, dog]
3   d   [cat, horse, pig]

选项2:使用numpy in1d的类似解决方案,

df[df.species.apply(lambda x: np.any(np.in1d(x, selection)))]
420 µs ± 17.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

选项 3:有趣的是,在这里使用纯 python 集相当快

df[df.species.apply(lambda x: bool(set(x) & set(selection)))]
305 µs ± 5.22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

    【解决方案4】:

    使用熊猫str.contains (uses regular expression):

    df[~df["species"].str.contains('(cat|dog)', regex=True)]
    

    输出:

        molecule    species
    1   b   [horse, pig]
    4   e   [chicken, pig]
    

    【讨论】:

      【解决方案5】:

      这是一种简单而基本的方法。 您可以创建一个函数来检查 Selection list 中的元素是否存在于 pandas 列 list 中。

      def check(speciesList):
          flag = False
          for animal in selection:
              if animal in speciesList:
                  flag = True
          return flag
      

      然后,您可以使用此list 根据记录是否包含选择列表中的至少一个元素来创建包含TrueFalse 的列,并根据它创建一个新的数据框。

      df['containsCatDog'] = df.species.apply(lambda animals: check(animals))
      newDf = df[df.containsCatDog == True]
      

      希望对你有帮助。

      【讨论】:

        【解决方案6】:
        import  pandas as pd
        import numpy as np
        selection = ['cat', 'dog']
        df = pd.DataFrame({'molecule': ['a','b','c','d','e'], 'species' : [['dog'], ['horse','pig'],['cat', 'dog'], ['cat','horse','pig'], ['chicken','pig']]})
        
        df1 = df[df['species'].apply((lambda x: 'dog' in x) )]
        df2=df[df['species'].apply((lambda x: 'cat' in x) )]
        frames = [df1, df2]
        result = pd.concat(frames,join='inner',ignore_index=False)
        print("result",result)
        result = result[~result.index.duplicated(keep='first')]
        print(result)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-09-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-27
          • 1970-01-01
          • 2015-07-31
          相关资源
          最近更新 更多