我有一系列单词序列,我试图确定字符串列是否包含列表中的任何序列。如果有任何匹配,则新列应包含1,否则应为0 下面的代码实现了这一点,但是对于大数据它不能很好地扩展。
import numpy as np
import pandas as pd
import re
data = {'TextVar' : ['this should never match',
'matches foo bar',
'this is the second random pattern',
np.nan,
'foo bars, should return 0',
'foo bar, with a comma, should return 1']}
df = pd.DataFrame(data)
patterns = ['foo bar', 'second random pattern', 'pink unicorns',]
def stringFound(string1, string2):
"""
string1 = pattern to look for
string2 = string to look in
"""
if pd.isnull(string1) or pd.isnull(string2):
return False
if re.search(r"\b" + re.escape(string1) + r"\b", string2):
return True
return False
def hasPattern(pattern_list, text):
for e in pattern_list:
if stringFound(e, text):
return 1
return 0
df['Output'] = df.apply(lambda x :hasPattern(patterns, x['TextVar']), axis=1)
我尝试在5000个序列(len(patterns) = 5000
)的列表上运行它,并在数据帧中运行15000行,30分钟后它仍在运行。我意识到我实际上已经迭代了7500万次 - 为了更有效率,我怎么写这个呢?
答案 0 :(得分:1)
In [16]: pat = '|'.join([r'\b{}\b'.format(x) for x in patterns])
In [17]: pat
Out[17]: '\\bfoo bar\\b|\\bsecond random pattern\\b|\\bpink unicorns\\b'
In [18]: df['TextVar'].fillna('').str.contains(pat).astype(np.int8)
Out[18]:
0 0
1 1
2 1
3 0
4 0
5 1
Name: TextVar, dtype: int8
如果使用更复杂的模式,请尝试使用@Wiktor Stribiżew中的模式:
pat = r'(?<!\w){}(?!\w)'.format('|'.join([re.escape(m) for m in patterns]))