pandas 选择字符串列表中所有元素的快速方法,其中至少包含另一个列表中的子字符串

vc9ivgsu  于 2023-03-11  发布在  其他
关注(0)|答案(2)|浏览(92)

我有一个字符串列表,如下所示:

samples = ['2345_234_1.0_1.35_001', '0345_123_2.09_1.3_003', ...]

这个列表可以很长(最坏的情况下可以达到10^6个元素),我有另一个包含一些子字符串的列表:

matches = ['7895_001', '3458_669', '0345_123', ...]

我想创建一个列表matched_samples,它只包含samples的元素,而samples的元素包含matches的一个或多个元素。例如,samples[1]最后出现在matched_samples中,因为matches[3]samples[1]的子字符串。我可以这样做:

matched_samples = [s for s in samples if any(xs in s for xs in matches)]

但是,这看起来像一个双for循环,所以速度不会很快。有没有其他选择?如果samples是一个pandas Dataframe ,我可以简单地做:

matches_regex = '|'.join(matches)
matched_samples = samples[samples['sample'].str.contains(matches_regex)]

有没有类似的快速列表替代方案?

6xfqseft

6xfqseft1#

你可以做和你的Pandas例子一样的事情。

import re

samples = ['2345_234_1.0_1.35_001', '0345_123_2.09_1.3_003']
matches = ['7895_001', '3458_669', '0345_123']

pattern = re.compile(f"""{"|".join(re.escape(m) for m in matches)}""")
>>> [ s for s in samples if pattern.search(s) ]
['0345_123_2.09_1.3_003']

如果你的例子中没有换行符-你也可以把它转换成一个字符串,并在模式周围使用.findall()
不知道这是否会使速度方面的差异。

>>> pattern = re.compile(f"""(?:{"|".join(re.escape(m) for m in matches)}).*""")
>>> pattern
re.compile(r'(?:7895_001|3458_669|0345_123).*', re.UNICODE)
>>> pattern.findall("\n".join(samples))
['0345_123_2.09_1.3_003']
0g0grzrc

0g0grzrc2#

这看起来像一个双循环,所以不会很快.
首先,请注意通常被认为是不可取的 * 过早优化 *。在这种情况下,您应该回答以下问题:对于您使用情形来说,它是否足够快?
第二,注意到

matched_samples = [s for s in samples if any(xs in s for xs in matches)]

很大程度上取决于您的数据。最坏的情况是如果没有一个匹配,因为它会导致len(samples)*len(matches)的is子串检查,最好的情况是如果matches的第一个元素是samples的每个元素的子串,因为您将得到len(samples)的is子串检查,因为any在找到第一个真值y之后停止进一步的处理。观察到该平均处理时间确实取决于匹配排序。

相关问题