我正在寻找一种方法来确定
pandas
系列字符串是否包含在另一个系列的字符串列表的值中。
最好是单行 - 我知道我可以通过循环行并建立一个新系列来解决这个问题。
示例:
import pandas as pd
df = pd.DataFrame([
{'value': 'foo', 'accepted_values': ['foo', 'bar']},
{'value': 'bar', 'accepted_values': ['foo']},
])
期望的输出是
pd.Series([True, False])
因为
'foo'
在 ['foo', 'bar']
中,但 'bar'
不在 ['foo']
中
我尝试过的:
df['value'].isin(df['accepted_values'])
,但这给了我[False, False]
谢谢!
您可以将
apply
与 in
一起使用:
df.apply(lambda r: r.value in r.accepted_values, axis=1)
0 True
1 False
有更有效的方法来执行此操作。
创建用于性能测试的样本数据
list_strings = ['apple', 'banana', 'orange', 'pineapple', 'strawberry', 'elephant', 'butterfly', 'rainbow', 'computer']
rows_shape = 2_000_000
df = pd.DataFrame({'value':[random.sample(list_strings, 1)[0] for y in range(rows_shape)],
'accepted_values':[random.sample(list_strings, 3) for y in range(rows_shape)]})
索引 | 价值 | 接受的值 |
---|---|---|
0 | 电脑 |
|
1 | 蝴蝶 |
|
2 | 菠萝 |
|
3 | 菠萝 |
|
4 | 蝴蝶 |
|
... | ... | ... |
999995 | 彩虹 |
|
999996 | 菠萝 |
|
999997 | 橙色 |
|
999998 | 彩虹 |
|
999999 | 草莓 |
|
# 4.6 seconds - Using .apply
df.assign(check=lambda x:x.apply(lambda row:row['value'] in row['accepted_values'],axis=1))
# 0.431 seconds - Using Vectorized Operations
df.assign(formacao=lambda z:
z.pipe(lambda x:(
x[['name','options']]
.explode('options')
.pipe(lambda x:x['name'].eq(x['options']))
.groupby(level=0)
.any()))
)
索引 | 价值 | 接受的值 | 检查 |
---|---|---|---|
0 | 电脑 |
|
正确 |
1 | 蝴蝶 |
|
错误 |
2 | 菠萝 |
|
错误 |
3 | 菠萝 |
|
错误 |
4 | 蝴蝶 |
|
正确 |
... | ... | ... | ... |
999995 | 彩虹 |
|
正确 |
999996 | 菠萝 |
|
错误 |
999997 | 橙色 |
|
错误 |
999998 | 彩虹 |
|
错误 |
999999 | 草莓 |
|
正确 |
比使用 apply 几乎快 x11!
所采用的策略侧重于利用矢量化操作来提高效率。相反,apply 方法在内部迭代循环,导致处理速度变慢,应尽可能避免。为了便于理解,值得一提的是,爆炸后,复制了第一个系列的值。这意味着对于原始 DataFrame 中的每一行,该行的索引值对于“accepted_values”列表爆炸创建的每个对应行都是重复的。此复制可确保比较结果可以正确地与其源自的原始行相关联。
例如,如果原始 DataFrame 中的一行的索引为 5,其“值”为 10,并且其“accepted_values”列表包含 [10, 20, 30],则爆炸将创建具有相同索引的三个新行值为 5,每个对应于“accepted_values”列表中的值之一。这允许对每个新行进行正确的后续比较,确保最终结果准确反映“值”是否等于原始行的任何“accepted_values”。
索引值的复制对于维护数据的完整性并确保比较结果与原始数据结构正确对齐至关重要。它允许转换准确确定“value”列是否等于 DataFrame 中每一行的“accepted_values”列表中的任何值,从而生成一个新列“check”,对于“value”相等的行,该列为 True任何“accepted_values”,否则为 False。