猿问

熊猫对串联多个子串的过滤

我需要在pandas数据格式,以便特定的字符串列至少包含一个提供的子字符串列表中的一个。子字符串可能具有不寻常的/正则字符。比较不应涉及regex,而且不区分大小写。

例如:

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,我们就不必测试该行的任何后续字符串。

熊猫对串联多个子串的过滤

侃侃无极
浏览 451回答 3
3回答

FFIVE

如果你坚持使用纯熊猫,无论是性能还是实用性,我认为你应对此任务使用regex。但是,您需要首先正确地转义子字符串中的任何特殊字符,以确保它们确实匹配(而不是用作regex元字符)。这很容易使用re.escape:>>> import re>>> esc_lst = [re.escape(s) for s in lst]然后,可以使用regex管道连接这些转义子字符串。|..每个子字符串都可以根据字符串进行检查,直到其中一个匹配为止(或者它们都已经过测试)。>>> pattern = '|'.join(esc_lst)然后,掩蔽阶段通过行变成一个单一的低级别循环:df[col].str.contains(pattern, case=False)下面是一个获得性能感觉的简单设置:from random import randint, seed seed(321)# 100 substrings of 5 characterslst = [''.join([chr(randint(0, 256)) for _ in range(5)]) for _ in range(100)]# 50000 strings of 20 charactersstrings = [''.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秒。值得注意的是,这些时候是“最糟糕的情况”,因为没有匹配(所以全检查子串)。如果有比赛时间更好的比赛。

智慧大石

使用更简单的例子&忽略案例(大写或小写)过滤和获取二进制向量:我想找到pd.Series, v,包含“at”或“Og”。如果元素包含模式,则获取1;如果不包含模式,则获取0。我会用re:import re我的载体:v=pd.Series(['cAt','dog','the rat','mouse','froG'])[Out]:0        cAt1        dog2    the rat3      mouse4       froG我想找到包含“at”或“Og”的所有v元素。这是,我可以定义我的pattern作为:pattern='at|Og'因为我想要一个带有1s的向量,如果项目包含模式,则为0。我创建了一个长度与v相同的酉向量:v_binary=[1]*len(v)我得到了一个s那是True如果一个元素v包含pattern或False如果它不包含它。s=v.str.contains(pattern, flags=re.IGNORECASE, regex=True)若要获得二进制向量,请将v_binary*s:v_binary*s[Out]0    11    12    13    04    1
随时随地看视频慕课网APP

相关分类

Python
我要回答