python - Pandas 过滤串联的多个子字符串

标签 python string pandas dataframe series

我需要过滤 pandas 数据框中的行,以便特定字符串列至少包含所提供的子字符串列表之一。子字符串可能包含不寻常/正则表达式字符。比较不应涉及正则表达式且不区分大小写。

例如:

lst = ['kdSj;af-!?', 'aBC+dsfa?\-', 'sdKaJg|dksaf-*']

我目前使用面膜是这样的:

mask = np.logical_or.reduce([df[col].str.contains(i, regex=False, case=False) for i in lst])
df = df[mask]

我的数据框很大(~1mio 行),并且 lst 的长度为 100。是否有更有效的方法?例如,如果找到 lst 中的第一项,我们不必测试该行的任何后续字符串。

最佳答案

如果您坚持使用纯 Pandas ,出于性能和实用性的考虑,我认为您应该使用正则表达式来完成此任务。但是,您需要首先正确转义子字符串中的任何特殊字符,以确保它们按字面匹配(并且不用作正则表达式元字符)。

使用 re.escape 可以轻松做到这一点:

>>> import re
>>> esc_lst = [re.escape(s) for s in lst]

然后可以使用正则表达式管道 | 连接这些转义的子字符串。可以根据字符串检查每个子字符串,直到有一个匹配(或者它们都已被测试)。

>>> pattern = '|'.join(esc_lst)

然后,屏蔽阶段变成通过行的单个低级循环:

df[col].str.contains(pattern, case=False)
<小时/>

这里有一个简单的设置来了解性能:

from random import randint, seed

seed(321)

# 100 substrings of 5 characters
lst = [''.join([chr(randint(0, 256)) for _ in range(5)]) for _ in range(100)]

# 50000 strings of 20 characters
strings = [''.join([chr(randint(0, 256)) for _ in range(20)]) for _ in range(50000)]

col = pd.Series(strings)
esc_lst = [re.escape(s) for s in lst]
pattern = '|'.join(esc_lst)

建议的方法大约需要 1 秒(因此对于 100 万行可能最多需要 20 秒):

%timeit col.str.contains(pattern, case=False)
1 loop, best of 3: 981 ms per loop

问题中的方法使用相同的输入数据大约需要 5 秒。

值得注意的是,这些时间是“最坏情况”,因为没有匹配项(因此所有子字符串都被检查)。如果有匹配的话,时间将会改善。

关于python - Pandas 过滤串联的多个子字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59279772/

相关文章:

python - 从自动化器运行 python 脚本

带有简单网络包装器的 python tkinter

python - 从一列中获取值作为减法变量

python - 使用tensorflow tf.control_dependency 和 tf.layers.batch_normalization 出现错误

c - 如何对 char 字符串/数组使用 malloc() 函数?

c - C 中的字符串排序

Java:将一组字符转换为单个字符串

python - 如何从数据框中提取父节点和后续节点

python - Pandas 数据框将数组条目分成两列

python - Beautifulsoup 根据 nextSibling 标签名称获取文本