У меня есть функция, которая принимает на вход строку и пытается извлечь имя и фамилию. Это комбинация NER и регулярного выражения, позволяющая извлечь присутствующие имена. Есть ли лучший или более эффективный способ сделать это? В основном он борется со сложными именами, то есть имя + отчество + фамилия. Пользователь может ввести Джона Майкла Смита, и код не сможет определить, какая часть к какой принадлежит.
def extract_name(self, text: str):
all_names = []
# Method 1: Named Entity Recognition (NER)
try:
tokens = nltk.word_tokenize(text)
pos_tags = nltk.pos_tag(tokens)
named_entities = nltk.ne_chunk(pos_tags)
for chunk in named_entities:
if hasattr(chunk, 'label') and chunk.label() == 'PERSON':
name = ' '.join([token for token, pos in chunk.leaves()])
all_names.append(name)
except Exception as e:
logger.debug(f"NER extraction failed: {e}")
# Method 2: POS Tagging + Pattern Recognition
# Define action verbs to skip (must match before combining into names)
action_verbs_lower = {
'change', 'remove', 'update', 'delete', 'add', 'create',
'show', 'find', 'get', 'view', 'display', 'list',
'fetch', 'retrieve', 'pull', 'access', 'lookup', 'search', 'locate', 'bring',
'mark', 'set', 'record', 'edit', 'modify', 'alter', 'revise',
'erase', 'drop', 'register', 'enroll'
}
try:
tokens = nltk.word_tokenize(text)
pos_tags = nltk.pos_tag(tokens)
i = 0
while i < len(pos_tags):
if pos_tags[1] == 'NNP':
# Skip if this word is an action verb
if pos_tags[0].lower() in action_verbs_lower:
i += 1
continue
name_parts = [pos_tags[0]]
j = i + 1
while j < len(pos_tags) and pos_tags[j][1] == 'NNP':
# Skip action verbs even in the middle of proper noun sequences
if pos_tags[j][0].lower() not in action_verbs_lower:
name_parts.append(pos_tags[j][0])
j += 1
# Only add if we have actual name parts (not just action verbs)
if len(name_parts) >= 1:
all_names.append(' '.join(name_parts))
i = j
else:
i += 1
except Exception as e:
logger.debug(f"POS extraction failed: {e}")
# Method 3: Regex Pattern Matching
patterns = [
r'\b[A-Z][a-z]+\s+[A-Z][a-z]+\b', # Standard Firstname Lastname
r'\b[A-Z][a-z]+\b', # Single capitalized name
]
for pattern in patterns:
matches = re.findall(pattern, text)
# Filter out action verbs from regex matches
for match in matches:
words = match.split()
# Only add if no word in the match is an action verb
if not any(word.lower() in action_verbs_lower for word in words):
all_names.append(match)
# Filter out common false positives (action verbs and system words)
false_positives = {
# Action verbs
'Change', 'Remove', 'Update', 'Delete', 'Add', 'Create',
'Show', 'Find', 'Get', 'View', 'Display', 'List',
'Fetch', 'Retrieve', 'Pull', 'Access', 'Lookup', 'Search', 'Locate', 'Bring',
'Mark', 'Set', 'Record', 'Edit', 'Modify', 'Alter', 'Revise',
'Erase', 'Drop', 'Register', 'Enroll',
}
filtered_names = []
for name in all_names:
if name not in filtered_names and not any(fp in name for fp in false_positives):
filtered_names.append(name)
# Use voting/frequency to determine most likely name
if filtered_names:
name_counts = Counter(filtered_names)
most_common = name_counts.most_common(1)[0][0]
confidence = name_counts[most_common] / len(all_names) if all_names else 0
return most_common, confidence, filtered_names
return None, 0.0, []
Подробнее здесь: https://stackoverflow.com/questions/798 ... m-a-string
Лучший способ извлечь имена из строки ⇐ Python
Программы на Python
1764288920
Anonymous
У меня есть функция, которая принимает на вход строку и пытается извлечь имя и фамилию. Это комбинация NER и регулярного выражения, позволяющая извлечь присутствующие имена. Есть ли лучший или более эффективный способ сделать это? В основном он борется со сложными именами, то есть имя + отчество + фамилия. Пользователь может ввести Джона Майкла Смита, и код не сможет определить, какая часть к какой принадлежит.
def extract_name(self, text: str):
all_names = []
# Method 1: Named Entity Recognition (NER)
try:
tokens = nltk.word_tokenize(text)
pos_tags = nltk.pos_tag(tokens)
named_entities = nltk.ne_chunk(pos_tags)
for chunk in named_entities:
if hasattr(chunk, 'label') and chunk.label() == 'PERSON':
name = ' '.join([token for token, pos in chunk.leaves()])
all_names.append(name)
except Exception as e:
logger.debug(f"NER extraction failed: {e}")
# Method 2: POS Tagging + Pattern Recognition
# Define action verbs to skip (must match before combining into names)
action_verbs_lower = {
'change', 'remove', 'update', 'delete', 'add', 'create',
'show', 'find', 'get', 'view', 'display', 'list',
'fetch', 'retrieve', 'pull', 'access', 'lookup', 'search', 'locate', 'bring',
'mark', 'set', 'record', 'edit', 'modify', 'alter', 'revise',
'erase', 'drop', 'register', 'enroll'
}
try:
tokens = nltk.word_tokenize(text)
pos_tags = nltk.pos_tag(tokens)
i = 0
while i < len(pos_tags):
if pos_tags[i][1] == 'NNP':
# Skip if this word is an action verb
if pos_tags[i][0].lower() in action_verbs_lower:
i += 1
continue
name_parts = [pos_tags[i][0]]
j = i + 1
while j < len(pos_tags) and pos_tags[j][1] == 'NNP':
# Skip action verbs even in the middle of proper noun sequences
if pos_tags[j][0].lower() not in action_verbs_lower:
name_parts.append(pos_tags[j][0])
j += 1
# Only add if we have actual name parts (not just action verbs)
if len(name_parts) >= 1:
all_names.append(' '.join(name_parts))
i = j
else:
i += 1
except Exception as e:
logger.debug(f"POS extraction failed: {e}")
# Method 3: Regex Pattern Matching
patterns = [
r'\b[A-Z][a-z]+\s+[A-Z][a-z]+\b', # Standard Firstname Lastname
r'\b[A-Z][a-z]+\b', # Single capitalized name
]
for pattern in patterns:
matches = re.findall(pattern, text)
# Filter out action verbs from regex matches
for match in matches:
words = match.split()
# Only add if no word in the match is an action verb
if not any(word.lower() in action_verbs_lower for word in words):
all_names.append(match)
# Filter out common false positives (action verbs and system words)
false_positives = {
# Action verbs
'Change', 'Remove', 'Update', 'Delete', 'Add', 'Create',
'Show', 'Find', 'Get', 'View', 'Display', 'List',
'Fetch', 'Retrieve', 'Pull', 'Access', 'Lookup', 'Search', 'Locate', 'Bring',
'Mark', 'Set', 'Record', 'Edit', 'Modify', 'Alter', 'Revise',
'Erase', 'Drop', 'Register', 'Enroll',
}
filtered_names = []
for name in all_names:
if name not in filtered_names and not any(fp in name for fp in false_positives):
filtered_names.append(name)
# Use voting/frequency to determine most likely name
if filtered_names:
name_counts = Counter(filtered_names)
most_common = name_counts.most_common(1)[0][0]
confidence = name_counts[most_common] / len(all_names) if all_names else 0
return most_common, confidence, filtered_names
return None, 0.0, []
Подробнее здесь: [url]https://stackoverflow.com/questions/79832143/best-way-to-extract-a-names-from-a-string[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия