Как извлечь из датафрейма адреса с помощью библиотеки Natasha

У меня имеется датафрейм. С помощью библиотеки Natasha мне необходимо извлечь адреса и очистить от лишних данных, таких как Match(start=1, stop=7, fact=Addr и оставить только название города/улицы. В сети нашел это решение:

from natasha import AddrExtractor, MorphVocab
morph_vocab = MorphVocab()
extractor = AddrExtractor(morph_vocab)
text = "г Калининград, ул Гагарина,20"
matches = extractor(text)
for match in matches:
    address = text[match.start:match.stop]
print(address)

однако, оно работает только для строковых данных и выдает последнее совпадение (ул Гагарина).Подскажите, пожалуйста, как преобразовать данный код для dataframe.

введите сюда описание изображения

Код исходного датафрейма

import pandas as pd
df = pd.DataFrame([[1,'Bob', ' москва'],
                  [2,'Sally', 'отдых'],
                  [3,'Scott', ' хабаровск']], 
columns=['id','name', 'street'])
df

Ожидаемый результат введите сюда описание изображения


Ответы (1 шт):

Автор решения: CrazyElf

Примерно так это всё можно объединить:

# !pip install natasha

import pandas as pd
from natasha import AddrExtractor, MorphVocab

morph_vocab = MorphVocab()
extractor = AddrExtractor(morph_vocab)

def fix_addr(text):
    matches = extractor(text)
    return (', '.join(f'{match.fact.type or ""} {match.fact.value}' for match in matches)) or None

df = pd.DataFrame([[1,'Bob', ' москва'],
                  [2,'Sally', 'отдых'],
                  [3,'Scott', 'хабаровск'], 
                  [4,'Вася', 'село Верхний Низ, ул. Ленина, д. 17']],  
columns=['id','name', 'street'])
df['street1'] = df['street'].map(fix_addr)
df
index id name street street1
0 1 Bob москва москва
1 2 Sally отдых None
2 3 Scott хабаровск хабаровск
3 4 Вася село Верхний Низ, ул. Ленина, д. 17 село Верхний Низ, улица Ленина, дом 17

В вашем коде показывает только последний найденный элемент адреса из-за неправильной табуляции, нужно внести print в цикл, вот так:

for match in matches:
    address = text[match.start:match.stop]
    print(address) # <- правильная табуляция

Теперь напечатает все фрагменты. Ну и брать элемент можно проще, как у меня в коде выше, через match.fact.value, а не через срез. Ещё там есть match.fact.type с типом элемента (например, "город"), но он не всегда заполнен.

→ Ссылка