Лучший способ извлечь имена из строкиPython

Программы на Python
Ответить
Anonymous
 Лучший способ извлечь имена из строки

Сообщение 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[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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»