【问题标题】:Filter pandas dataframe rows if any value on a list inside the dataframe is in another list如果数据框内列表中的任何值在另一个列表中,则过滤熊猫数据框行
【发布时间】:2019-06-10 08:51:35
【问题描述】:

我有一个pandas dataframe,它在 split_categories 列中包含一个列表:

df.head()

      album_id categories split_categories
    0    66562    480.494       [480, 494]
    1   114582        128            [128]
    2     4846          5              [5]
    3     1709          9              [9]
    4    59239    105.104       [105, 104]

我想选择特定列表 [480, 9, 104] 中至少一个类别所在的所有行。

预期输出:

  album_id categories split_categories
0    66562    480.494       [480, 494]
3     1709          9              [9]
4    59239    105.104       [105, 104]

我设法使用apply

def match_categories(row):
    selected_categories =  [480, 9, 104]
    result = [int(i) for i in row['split_categories'] if i in selected_categories]
    return result

df['matched_categories'] = df.apply(match_categories, axis=1)

但是这段代码在生产环境中运行,这种方式耗时太长(我为包含列表的多个列运行它)

有没有办法运行类似的东西:

df[~(df['split_categories'].anyvalue.isin([480, 9, 104]))]

谢谢

【问题讨论】:

  • df['split_categories'] 中列表的最大大小是多少,例如总是 1 或 2 项?

标签: python pandas python-2.7


【解决方案1】:

另一种方法:

my_list = [480, 9, 104]
pat = r'({})'.format('|'.join(str(i) for i in my_list))
#'(480|9|104)' <-- This is how the pat looks like
df.loc[df.split_categories.astype(str).str.extract(pat, expand=False).dropna().index]

或者:

pat = '|'.join(r"\b{}\b".format(x) for x in my_list)
df[df.split_categories.astype(str).str.contains(pat,na=False)]

    album_id    categories  split_categories
0   66562       480.494     [480, 494]
3   1709        9.000       [9]
4   59239       105.104     [105, 104]

这将适用于 split_categoriescategories 列。

【讨论】:

  • str.contains 这里更好
  • @jezrael 我试过了,收到警告UserWarning: This pattern has match groups. To actually get the groups, use str.extract. :(
  • 试试pat = '|'.join(r"\b{}\b".format(x) for x in L)
  • @jezrael 有效,谢谢。 :) 将添加编辑。 :) 仍在学习字符串格式。 :D
【解决方案2】:

您可以将每个列表转换为集合,获取交集并转换为布尔:

L = [480, 9, 104]
mask = np.array([bool(set(map(int, x)) & set(L))  for x in df['split_categories']])

或者将list column转换为DataFrame,转换为float并与isin比较:

df1 = pd.DataFrame(df['split_categories'].values.tolist(), index=df.index)
mask = df1.astype(float).isin(L).any(axis=1)

df = df[mask]
print (df)
  album_id categories split_categories
0    66562    480.494       [480, 494]
3     1709          9              [9]
4    59239    105.104       [105, 104]

【讨论】:

    【解决方案3】:

    避免一系列列表

    您可以拆分为多个数字系列,然后使用矢量化布尔运算。使用逐行操作的 Python 级循环通常效率较低

    df = pd.DataFrame({'album_id': [66562, 114582, 4846, 1709, 59239],
                       'categories': ['480.494', '128', '5', '9', '105.104']})
    
    split = df['categories'].str.split('.', expand=True).add_prefix('split_').astype(float)
    df = df.join(split)
    
    print(df)
    #    album_id categories  split_0  split_1
    # 0     66562    480.494    480.0    494.0
    # 1    114582        128    128.0      NaN
    # 2      4846          5      5.0      NaN
    # 3      1709          9      9.0      NaN
    # 4     59239    105.104    105.0    104.0
    
    L = [480, 9, 104]
    res = df[df.filter(regex='^split_').isin(L).any(1)]
    
    print(res)
    #    album_id categories  split_0  split_1
    # 0     66562    480.494    480.0    494.0
    # 3      1709          9      9.0      NaN
    # 4     59239    105.104    105.0    104.0
    

    【讨论】:

      【解决方案4】:

      可以展开内层列表,检查内层列表中的any项是否包含在[480, 9, 104]中:

      l = [480, 9, 104]
      df[df.categories.str.split('.', expand=True).isin(map(str,l)).any(axis=1)]
      
         album_id  categories split_categories
      0     66562     480.494        [480,494]
      3      1709       9.000              [9]
      4     59239     105.104        [105,104]
      

      【讨论】:

      • df.split_categories.str.strip('[]') 返回一个 NaN 数组(split_categories 中的值已经是一个列表(不是 trsing)我使用了 df[df.categories.str。 split('.', expand=True).isin(map(str,l)).any(axis=1)] 代替,它起作用了。谢谢
      • 哦,我明白了,我知道你必须改用split_categories,更新了答案
      【解决方案5】:

      用途:

      print(df[~(df['split_categories'].isin([480, 9, 104])).any()])
      

      输出:

        album_id categories split_categories
      0    66562    480.494       [480, 494]
      3     1709          9              [9]
      4    59239    105.104       [105, 104]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-08
        • 2019-05-21
        • 1970-01-01
        • 2014-12-27
        • 2021-12-01
        • 2017-12-15
        • 1970-01-01
        • 2018-11-24
        相关资源
        最近更新 更多