#python-3.x #nlp #fuzzy-search #fuzzy #fuzzy-comparison
Вопрос:
предположим, у меня есть следующий фрейм данных:
ID CompanyName JobDescription
1 Green Grass LLC "In the centre of Green Grass area..."
2 Johnny Inc. "Johnny is currently looking for data analist that..."
3 Liamloy "LiamLoy Corp. is established in New York..."
4 KaasKan "In the forest we are walking..."
Моя главная цель-исключить CompanyName
то, что есть в каждом JobDescription
. Желаемый результат был бы:
ID CompanyName JobDescription
1 Green Grass LLC "In the centre of area..."
2 Johnny Inc. "is currently looking for data analist that..."
3 Liamloy "is established in New York..."
4 KaasKan "In the forest we are walking"
Я попытался word tokenize
JobDescription
(преобразовать предложение в слова) и применить fuzzymatching
для обнаружения и удаления совпадений. Однако это оказалось не очень успешным. Например, при токенизации третьего JobDescription
. « Liamloy
» сравнивается с « LiamLoy
» и « Corp
.». Возможно, этот подход не идеален. На данный момент я понятия не имею. Интересно, не хотел бы кто-нибудь из вас поделиться своим мнением и просветить меня, как я могу успешно удалить CompanyName
в каждом JobDescription
из них .
Ответ №1:
Если вы не ожидаете, что слова в названиях компаний будут заменены, я предлагаю использовать встроенную библиотеку python difflib, чтобы найти общую часть двух строк и заменить ее маской.
def find_matching_spans(a, b, min_match=3, max_mismatch=1):
""" Find the spans in the string b that are similar to the string a"""
prev_match = 0
match = 0
mismatch = 0
i = 0
span_start = 0
prev_start = 0
span_end = 0
spans = []
common = []
def add_span():
if prev_match > min_match:
if spans and spans[-1][-1] >= prev_start - 2:
spans[-1][-1] = span_end
else:
spans.append([prev_start, span_end])
for item in difflib.ndiff(a.lower(), b.lower()):
if item[0] == ' ' and item[2] != ' ':
match = 1
mismatch = 0
if match == 1:
span_start = i
common = []
common.append(item[2])
elif item[0] == ' ' or item[2] == ' ':
if match > min_match:
add_span()
prev_start = span_start
prev_match = match
span_end = i
match = 0
mismatch = 1
if mismatch > max_mismatch:
add_span()
prev_match = 0
elif item[0] == '-':
pass
if item[0] in {' ', ' '}:
i = 1
return spans
def replace_spans(text, spans, replacement):
spans = [[0, 0]] spans [[len(text), len(text)]]
parts = []
for i in range(1, len(spans)):
parts.append(text[spans[i-1][1]:spans[i][0]])
if i < len(spans) - 1:
parts.append('XXX')
return ''.join(parts)
def replace_name(a, b, replacement='XXX'):
b_prev = None
while b_prev != b:
spans = find_matching_spans(a, b)
b_prev = b
b = replace_spans(b, spans, replacement)
return b
Это будет работать так:
print(replace_name("Green Grass LLC", "In the centre of Green Grass area..."))
print(replace_name("Johnny Inc.", "Johnny is currently looking for data analist that..."))
print(replace_name("Liamloy", "LiamLoy Corp. is established in New York..."))
print(replace_name("KaasKan", "In the forest we are walking..."))
И производить продукцию
In the centre of XXX area...
XXX is currently looking for data analist that...
XXX Corp. is established in New York...
In the forest we are walking...
Комментарии:
1. Это работает только для коротких предложений. Почему-то это не работает для длинных предложений. Однако я ценю ваши усилия.
Ответ №2:
Почему бы не использовать регулярное выражение?
import re
def replace_company_name(company_name, text):
sanitized_text = re.sub(company_name, '', text)
return sanitized_text
Похоже, вам также нужно рассмотреть исправления после названия компании, такие как corp, из-за примера с Лиамлоем.
Один из способов справиться с этим-обычный набор констант после исправления названия компании. Вы также должны отметить, что я использую флаг игнорировать регистр, потому что, глядя на строку для Liamloy, название компании-Liamloy, в то время как в описании должности это LiamLoy. Также, вероятно, существуют различия в том, как капитализируются исправления после исправления (INC, Inc, inc и т. Д. )
COMPANY_NAME_POSTFIXES = '|'.join(['INC', 'CORP', 'LLC', 'LTD'])
def replace_company_name(company_name, text):
# 1. replace any postfixes in the company name. E.G. Green Grass LLC. -> Green Grass
company_name_post_fixregex = rf'({COMPANY_NAME_POSTFIXES})?\.?'
sanitized_company_name = re.sub(company_name_postfix_regex, '', company_name, flags=re.IGNORECASE)
# 2. replace any instances of the sanitized company name followed optionally by both a space and a company name postfix
search_string = rf'{sanitized_company_name}\s?{company_name_postfix_regex}'
sanitized_text = re.sub(search_string, '', text, flags=re.IGNORECASE)
return sanitized_text
Вышеуказанный подход приведет к побочному эффекту замены используемых слов, если они не являются названием компании. Например, для ООО «Зеленая трава» «В центре зоны зеленой травы много зеленой травы, за которой ухаживают» — > В центре области много того, за чем ухаживают
Если этот побочный эффект нежелателен, вам нужно будет очистить описание работы для капитализации названия компании или рассчитать и передать массив названий компаний.