Я хотел бы выполнить поиск по ключевым словам в столбце фрейма данных, который называется «строка».
Ключевые слова содержатся в словаре.
Для каждого ключа значение представляет собой массив из нескольких ключевых слов.
Меня беспокоит то, что скорость очень низкая и на это уходит много времени.
Возможно, задействовано много петель, и df.str.contains нельзя использовать.
Как ускорить процесс?
def match(string, keyword):
m = len(string)
n = len(keyword)
idx = string.find(keyword)
if idx == -1:
return 0
if len(re.findall('[a-zA-Z]', string[idx])) > 0:
if idx > 0:
if len(re.findall('[a-zA-Z]', string[idx - 1])) > 0:
return 0
if len(re.findall('[a-zA-Z]', string[idx+n-1])) > 0:
if idx + n < m:
if len(re.findall('[a-zA-Z]', string[idx + n])) > 0:
return 0
return 1
def match_keyword(df, keyword_dict, name):
df_new = pd.DataFrame()
for owner_id, keyword in keyword_dict.items():
try:
for index, data in df.iterrows():
a = [match(data['string'], word) for word in keyword]
t = int(np.sum(a))
if t > 0:
df_new.loc[index, name+'_'+str(owner_id)] = 1
else:
df_new.loc[index, name+'_'+str(owner_id)] = 0
except:
df_new[name+'_'+str(owner_id)] = 0
return df_new.astype(int)
Вход:
String
0 New Beauty Company is now offering 超級discounts
1 Swimming is good for children and adults
2 Children love food though it may not be good
keywords:{'a':['New', 'is', '超級'], 'b':['Swim', 'discounts', 'good']}
Полученные результаты:
'New' 'is' '超級' result(or relation)
0 1 1 1 1
1 0 1 0 1
2 0 0 0 0
'Swim' 'discounts' 'good' result(or relation)
0 0 1 0 1
1 0 0 1 1
2 0 0 1 1
Окончательные результаты:
'a' 'b'
0 1 1
1 1 1
2 0 1
Алгоритм Pandas является базовым. Вы можете использовать регулярное выражение, но для большого ускорения вам, вероятно, понадобится специальная библиотека, например см. этот ответ.
Спасибо, jpp. Это интересно.


Я считаю, что нужен str.contains в цикле по dict с word bondaries по \b с соединением по | для регулярного выражения OR:
for k, v in keywords.items():
pat = '|'.join(r"\b{}\b".format(x) for x in v)
#print (pat)
df[k] = df['String'].str.contains(pat).astype(int)
print (df)
String a b
0 New Beauty Company is now offering discounts 1 1
1 Swimming is good for children and adults 1 1
2 Children love food though it may not be good 0 1
При необходимости также столбцы по каждому значению и создать MultiIndex в столбцах:
df = df.set_index('String')
for k, v in keywords.items():
for x in v:
df[(k, x)] = df.index.str.contains(x).astype(int)
df.columns = pd.MultiIndex.from_tuples(df.columns)
print (df)
a b
New is Swim discounts good
String
New Beauty Company is now offering discounts 1 1 0 1 0
Swimming is good for children and adults 0 1 1 0 1
Children love food though it may not be good 0 0 0 0 1
И тогда можно получить max по MultiIndex:
df = df.max(axis=1, level=0)
print (df)
a b
String
New Beauty Company is now offering discounts 1 1
Swimming is good for children and adults 1 1
Children love food though it may not be good 0 1
Спасибо, Джезраэль. А если есть китайские иероглифы?
@Chan - Сложный вопрос, правда, понятия не имею. Но тогда второе решение должно быть лучше.
Я не знаком с регулярным выражением. Я поискал в Интернете и обнаружил, что есть (?(?=regex)then|else). Как написать регулярное выражение: если первый символ [a-zA-Z], то поставить первый \b, иначе ничего не поставить. Более того, если последний символ [a-zA-Z], то ставить последний \b, иначе ничего не ставить?
@Chan - К сожалению, у меня такая же проблема со сложным регулярным выражением, возможно, лучше всего создать для этого новый вопрос :( Извините.
Можете ли вы привести пример ваших входов и ожидаемых результатов?