Что может быть лучшим подходом для сопоставления с образцом и замены в Python? - PullRequest
2 голосов
/ 17 октября 2019

У меня есть плоский файл с терминами и предложениями. Если в предложении есть какой-либо термин, мне нужно добавить | присутствует (термин | присутствует). По сути, сопоставление с образцом (без учета регистра) и добавление | присутствует. Также нам нужно сохранить тот же случай, что и в предложении. Какой подход будет осуществим и быстрее в Python. Я пробовал это с помощью Oracle regex, это занимает дни, чтобы обработать записи по 70 тыс. Есть ли лучший подход. А также с текущим подходом, он прекрасно работает для 50 записей, но df ['words'] пуст при запуске для всех 70k записей. Не уверен, в чем причина.

from pandas import DataFrame

df = {'term': ['Ford', 'EXpensive', 'TOYOTA', 'Mercedes Benz', 'electric', 'cars'],
        'sentence': ['Ford is less expensive than Mercedes Benz.' ,'toyota, hyundai mileage is good compared to ford','tesla is an electric-car','toyota too has electric cars','CARS','CArs are expensive.']
        }
from pandas import DataFrame
import re
df = DataFrame(df,columns= ['term','sentence'])

pattern = "|".join(f"\w*(?<![A-Za-z-;:,/|]){i}\\b" for i in df["term"])

df["words"]= df['sentence'].str.findall(pattern, flags=re.IGNORECASE)

def replace_values(row):
    if len(row.words)>0:
        pat = r"(\b"+"|".join(row.words) +r")(\b)"
        row.sentence = re.sub(pat, "\\1|present\\2", row.sentence)
    return row

df = df.apply(replace_values, axis=1)


1 Ответ

2 голосов
/ 17 октября 2019

Ваш паттерн очень неэффективен, так как у него есть много незанятых альтернатив, начинающихся с идентичного паттерна, который может сильно откатиться назад. Кроме того, границы слов, которые вы хотите использовать, также должны отсортировать термины по длине в порядке убывания, чтобы найти самые длинные термины в случае их совпадения (например, Merceded и Mercedes Benz).

Итак, используйте

pattern = r'(?i)\b(?:{})\b'.format('|'.join(sorted(df["term"],key=len,reverse=True)))

Или, если у вас есть особые символы в терминах,

pattern = r'(?i)(?<!\w)(?:{})(?!\w)'.format('|'.join(map(re.escape, sorted(df["term"],key=len,reverse=True))))

, а затем

df["words"]= df["sentence"].str.findall(pattern)
df["sentence"].replace(pattern, r"\g<0>|present", inplace=True, regex=True)

Шаблон будет выглядеть как (?i)\b(?:Mercedes Benz|EXpensive|electric|TOYOTA|Ford|cars)\b, он будет совпадать - в случае нечувствительности к регистру из-за (?i) - целых слов Mercedes Benz, EXpensive, electric, TOYOTA, Ford, cars и в df["sentence"].str.findall(pattern) этонайдет все непересекающиеся вхождения совпадения с образцом, и в df["sentence"].replace(pattern, r"\g<0>|present", inplace=True, regex=True) все совпадения будут заменены на себя (\g<0> - это обратная ссылка на все совпадение) + |present, добавленные к ним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...