布尔值屏蔽每一行中不同长度的列表

Boolean masking a list of different lengths within each individual row

我有以下数据框:

df = pd.DataFrame({
    'tags': [
        [{'id': 1401}, {'id': 1801}],
        [{'id': 502}, {'id': 703}, {'id': 1801}],
        [{'id': 1801}]
    ]
})

我只对 'tags' 列中的 'id': 1801 值感兴趣,如果 'id': 1801 存在或 False如果不是。

如有任何帮助,我们将不胜感激

如果性能对 get 很重要,则使用带有 any 的 lambda 函数进行测试,如果缺少 id

df = pd.DataFrame({
    'tags': [
        [{'id': 1401}, {'id': 1801}],
        [{'id': 502}, {'id': 703}, {'id': 1801}],
        [{'id': 1}]
    ]
})

df['new'] = df['tags'].apply(lambda x: any(y.get('id') == 1801 for y in x))
print (df)
                                       tags    new
0              [{'id': 1401}, {'id': 1801}]   True
1  [{'id': 502}, {'id': 703}, {'id': 1801}]   True
2                               [{'id': 1}]  False

df = pd.concat([df] * 1000, ignore_index=True)

In [275]: %timeit df['tags'].explode().str['id'].eq(1801).any(level=0)
8.09 ms ± 265 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [276]: %timeit df['tags'].apply(lambda x: any(y.get('id') == 1801 for y in x))
2.64 ms ± 6.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

如果总是 id 每个 tags 存在:

In [283]: %timeit [any(d['id'] == 1801 for d in l) for l in df['tags']]
2.44 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

我们可以 explode tags 列然后使用 str 访问器获取 id 的值并将其与 1801 进行比较以创建布尔掩码接着 anylevel=0 上减少:

df['flag'] = df['tags'].explode().str['id'].eq(1801).any(level=0)

如果数据帧很大并且需要考虑性能,那么我们可以使用 list comprehension,它将胜过所有可用的基于 pandas 的解决方案

df['flags'] = [any(d['id'] == 1801 for d in l) for l in df['tags']]

                                       tags  flag
0              [{'id': 1401}, {'id': 1801}]  True
1  [{'id': 502}, {'id': 703}, {'id': 1801}]  True
2                            [{'id': 1801}]  True