检查字符串是否存在于 Pandas 中另一列的值中的最有效方法

Most efficient way of checking whether a string is present in another column's values in Pandas

我有一个 pandas 数据框如下,

id all_items items_check1 items_check2
1239 'foobar,foo,foofoo,bar' 'foo,bar' 'foobar'
3298 'foobar,foo' 'foobar' 'bar'
9384 'foo,bar' 'bar,foo' 'bar'

我想检查 items_check1 中的项目是否存在于 all_items 中,稍后将此结果保存到单独的列中作为 check1_output;然后想用 items_check2all_items 再次重复相同的过程;并将其保存到 check2_output.

所以[期望的输出]应该是这样的,

id all_items items_check1 items_check2 check1_output check2_output
1239 'foobar,foo,foofoo,bar' 'foo,bar' 'foobar' 正确 正确
3298 'foobar,foo' 'foobar' 'bar' 正确
9384 'foo,bar' 'bar,foo' 'bar' 正确 正确

我有数十亿行,有时 all_items 的单个单元格中的项目数最多可达 100 项。我正在寻找完成此比较的最有效方法。

到目前为止的尝试
以下是我的尝试,这比遍历行更有效,但我很快发现输出并不总是如预期的那样.这种行为的可能原因是什么?

df['check1_output'] = np.where([x[0] in x[1] for x in zip(df['items_check1'], df['all_items'])], True, False)
df['check2_output'] = np.where([x[0] in x[1] for x in zip(df['items_check2'], df['all_items'])], True, False)

[实际输出]

id all_items items_check1 items_check2 check1_output check2_output
1239 'foobar,foo,foofoo,bar' 'foo,bar' 'foobar' 正确 正确
3298 'foobar,foo' 'foobar' 'bar' 正确 正确
9384 'foo,bar' 'bar,foo' 'bar' 正确

这是重新生成上述数据帧的片段

df = pd.DataFrame({'id': [1239,3298,9384], 
                   'all_items': ['foobar,foo,foofoo,bar','foobar,foo','foo,bar'],
                   'items_check1': ['foo,bar','foobar','barfoo'],
                   'items_check2': ['foobar','bar','bar']
                  })

编辑: 增加计算时间

我提到的方法需要 610µs 3 行数据帧的时间。但是当我 运行 它跨越具有数十亿条记录的实际数据时,需要花费很多时间。因此寻找更有效的方法。

尝试将 issubset()str.split() 结合使用:

df["check1_output"] = df.apply(lambda x: set(x["items_check1"].split(",")).issubset(x["all_items"].split(",")), axis=1)
df["check2_output"] = df.apply(lambda x: set(x["items_check2"].split(",")).issubset(x["all_items"].split(",")), axis=1)
>>> df
     id              all_items  ... check1_output check2_output
0  1239  foobar,foo,foofoo,bar  ...          True          True
1  3298             foobar,foo  ...          True         False
2  9384                foo,bar  ...         False          True

Numpy哪里会快

import numpy as np 

…

df['check1_output'] = np.where(df['items_check1'].isin(df['all_items']), True, False)

# do same for the other check

您可以使用 split() 将字符串转换为列表,然后应用 np.in1d 检查特定项目是否在 all_items.

df['check1_output'] = df.apply(lambda row: np.in1d(row['items_check1'].split(','), row['all_items'].split(',')).all(), axis=1)
df['check2_output'] = df.apply(lambda row: np.in1d(row['items_check2'].split(','), row['all_items'].split(',')).all(), axis=1)