我有一个包含大量行(几百万)的数据框。其中一列包含一个字符串,其中包含一个用逗号分隔的列表(但不是Python列表,只是一个用逗号分隔的项目列表)。数据框可以表示为:
df = pd.DataFrame({'A':['a,b,c','b,c,d,e','a,b,e,f','a,c,d,f']})
A
0 a,b,c
1 b,c,d,e
2 a,b,e,f
3 a,c,d,f
我有一个单独的Python列表,其中包含各种元素,例如:
lst1 = ['w','x','y','z','b']
我想在数据库中创建一个附加列,以指示lst1
中的元素之一是否包含在数据库的A列中。
我的解决方案是将列表元素转换为正则表达式,并使用.str.contains()
结构将行标记为True
或False
:
regex = regex = '|'.join(['(?:{})'.format(i) for i in lst1])
这将产生以下正则表达式:
(?:w)|(?:x)|(?:y)|(?:z)|(?:b)
然后:
df['B'] = df['A'].str.contains(regex)
A B
0 a,b,c True
1 b,c,d,e True
2 a,b,e,f True
3 a,c,d,f False
这在所描述的迷你示例中运行良好,但是在一个包含数百万行数据框的真实示例中,我担心正则表达式的使用可能太慢而无法实用。有没有更快的方法来达到相同的结果?
编辑
在@jezrael回答之后,我进行了时间比较。我生成了一个具有4M行和一个项目列表的数据框,以标识如下:
import timeit
df = pd.DataFrame({'A':['the,cat,sat,on,mat','the,cow,jumped,over,moon','humpty,dumpty,sat,on,the,wall','tiger,burning,bright']*1000000})
terms = ['sat','mat','moon','small','large','home','sliced']
regex = '|'.join(['(?:{})'.format(i) for i in terms])
%timeit df['B'] = df['A'].str.contains(regex)
这产生了:
1 loop, best of 3: 8.09 s per loop
与之比较:
import timeit
df = pd.DataFrame({'A':['the,cat,sat,on,mat','the,cow,jumped,over,moon','humpty,dumpty,sat,on,the,wall','tiger,burning,bright']*1000000})
terms = ['sat','mat','moon','small','large','home','sliced']
s = set(terms)
%timeit df['B1'] = [bool(set(x.split(',')) & s) for x in df['A']]
哪个制作的:
1 loop, best of 3: 8.36 s per loop
在这种特定设置中,结果大致相似,尽管,正如@jezrael所说,正则表达式选项的性能将受到许多因素的影响,例如字符串的长度,匹配数等。
答案 0 :(得分:2)
一种非正则表达式解决方案是使用集合的交集并将其转换为bool
:
s = set(lst1)
df['B1'] = [bool(set(x.split(',')) & s) for x in df['A']]
print (df)
A B B1
0 a,b,c True True
1 b,c,d,e True True
2 a,b,e,f True True
3 a,c,d,f False False