Въведение

Извличането на адреси от необработени данни е ценен инструмент за фирми и организации, които трябва да обработват големи количества писмени данни, като фактури или комуникации с клиенти. Системата за автоматично извличане на адреси е инструмент, който автоматично извлича и идентифицира адреси от неструктуриран текст. Той идентифицира и извлича подходяща информация, като имена на улици, имена на градове и пощенски кодове. След това извлечените адреси могат да се използват за различни задачи, като геокодиране, проверка на адреси и анализ на данни. Системата може да бъде обучена да работи с различни адресни формати и езици и може да бъде интегрирана в широк набор от приложения. В тази статия планираме да разгледаме различни техники за извличане на адреси и пакети на Python

Постановка на проблема

Извличане и анализиране на адрес от обикновен текст. Разглеждат се следните категории адреси.

Номер на къща
Име на улица
Град
Щат
Пощенски код
Държава

Пример:
1. Адресът на офиса на DMC е 3146 Barter St BEAUMONT TAXAS 77707–3514 САЩ.

Извличане:
3146 — Номер на къщата
Barter St BEAUMONT — Име на улица
TAXAS — Щат
77707–3514 — Пощенски код
Нас — Щат

Съдържание

  • Постановка на проблема
  • Подходи
    1. pyap
    2. usaddress
    3. nltk chunker
    4. усет (контролирано обучение)
    5. Simple Transformer (контролирано обучение)
  • Акценти
  • Заключение

Подходи

Един прост подход за извличане на адреси е използването на система, базирана на правила, където набор от предварително дефинирани правила се използват за идентифициране и извличане на адреси. Един пример за система, базирана на правила, е използването на регулярни изрази за съпоставяне на модели на адреси в текста, като например наличието на конкретни ключови думи (напр. „улица“, „авеню“ и т.н.) или използването на числа и съкращения в адрес.

Този подход може да бъде ефективен, но изисква много ръчни усилия за разработване на правилата и поддържането им, тъй като езикът и форматирането на адресите се променят с времето.

Последните постижения в обработката на естествения език (NLP) включват използването на техники за задълбочено обучение, като трансформаторни модели, предварително обучение върху големи набори от данни и трансфер на обучение за подобряване на ефективността при различни NLP задачи. Тези техники са довели до значителни подобрения в разбирането на естествения език, машинния превод и генерирането на текст. Освен това има нарастващ интерес към използването на НЛП за задачи като системи за диалог, разговорен AI и разбиране на контекста на текста в мултимодален набор

Едно от основните предимства на използването на обработка на естествен език (NLP) за извличане на адреси е, че позволява по-точни и последователни резултати от ръчните методи. Това е така, защото алгоритмите за машинно обучение могат да учат и да се адаптират въз основа на предоставените им данни, като стават по-точни и ефективни с течение на времето.

За да използва машинно обучение за извличане на адреси, бизнес или организация първо трябва да събере голямо количество писмени данни, които съдържат адреси. Тези данни могат да бъдат под формата на фактури, имейли или други видове писмена комуникация. По време на този блог ще разгледам един от вече анотираните набори от данни за обучение и фина настройка.

В този блог ще говорим за популярни пакети и няколко персонализирани подхода за извличане на адреси и сплитер.

1. Пяп

Pyap¹ е библиотека за обработка на текст за парсери на адреси. В момента поддържа адреси в САЩ, Канада и Великобритания. Pyap се основава на регулярен израз и следователно изпълнението му е по-бързо.

!pip install pyap
import pyap
text = "44 West 22nd Street, New York NY 12345"
addresses = pyap.parse(text, country='US')
for address in addresses:
    # shows found address
    print(address)
    # shows address parts
    print(address.as_dict())
    # 44 West 22nd Street, New York NY 12345
    # {'full_address': '44 West 22nd Street, New York NY 12345', 'full_street': '44 West 22nd Street', 'street_number': '44', 'street_name': 'West 22nd', 'street_type': 'Street', 'route_id': None, 'post_direction': None, 'floor': None, 'building_id': None, 'occupancy': None, 'city': 'New York', 'region1': 'NY', 'postal_code': '12345', 'country_id': 'US', 'match_start': 0, 'match_end': 38}

Най-добрата част е, че анализира пълния адрес и предоставя необходимите детайлни подробности. Помислете за това за извършване на основно извличане.

Бележник: pyap

Ограничение:

  • Pyap се основава на регулярен израз, може да даде фалшиво положителни резултати.

2. потребителски адрес

usaddress² е друга библиотека на Python за извличане на адреси от неструктурирани данни. Поддържа само адреси в САЩ.

Той използва ""парсератор"" вероятностния модел за прогнозиране. Следните етикети са достъпни от анализатора.

  • AddressNumber — номер на адрес
  • AddressNumberPrefix — модификатор преди номер на адрес, напр. „Майл“, „#“
  • AddressNumberSuffix — модификатор след номер на адрес, напр. „B“, „1/2“
  • BuildingName — името на сграда, напр. „Финансов център в Атланта“
  • CornerOf — думи, указващи, че даден адрес е ъгъл, напр. „Кръстовище“, „ъгъл на“
  • IntersectionSeparator — връзка, свързваща части от пресечка, напр. 'и', '&'
  • Име на забележителност — името на забележителност, напр. „Ригли Фийлд“, „Юниън Стейшън“
  • NotAddress — компонент без адрес, който не препраща към получател
  • OccupancyType — тип заетост в сграда, напр. „Апартамент“, „Апартамент“, „Етаж“
  • OccupancyIdentifier — идентификаторът на заетостта, често цифра или буква
  • PlaceName — град
  • Получател — получател без адрес, напр. име на лице/организация
  • StateName — състояние
  • StreetName — име на улица, без тип и посока
  • StreetNamePreDirectional — посока преди име на улица, напр. „Север“, „S“
  • StreetNamePreModifier — модификатор преди име на улица, което не е посока, напр. 'Стар'
  • StreetNamePreType — тип улица, който стои преди име на улица, напр. „Маршрут“, „Аве“
  • StreetNamePostDirectional — посока след име на улица, напр. „Север“, „S“
  • StreetNamePostModifier — модификатор, добавящ име на улица, напр. „Външно“
  • StreetNamePostType — тип улица, който идва след име на улица, напр. „Avenue“, „Rd“
  • SubaddressIdentifier — името/идентификаторът на компонент на подадрес
  • SubaddressType — ниво на детайлност в адрес, който не е зает в сграда, напр. „Сграда“, „Кула“
  • USPSBoxGroupID — идентификаторът на USPS група кутии, обикновено число
  • USPSBoxGroupType — име за група USPS кутии, напр. „RR“
  • USPSBoxID — идентификаторът на USPS кутия, обикновено число
  • USPSBoxType — USPS кутия, напр. „P.O. Кутия'
  • ZipCode — пощенски код

Методът "Parser" ще раздели вашия адресен низ на токени и ще маркира всички токени.

import usaddress
text = "DMC office address is 3146 Barter St BEAUMONT TAXAS 77707-3514 US."
usaddress.parse(text)
# [('DMC', 'Recipient'),
#  ('office', 'Recipient'),
#  ('address', 'Recipient'),
#  ('is', 'Recipient'),
#  ('3146', 'AddressNumber'),
#  ('Barter', 'StreetName'),
#  ('St', 'StreetNamePostType'),
#  ('BEAUMONT', 'PlaceName'),
#  ('TAXAS', 'StateName'),
#  ('77707-3514', 'ZipCode'),
#  ('US.', 'CountryName')]

„tag“ ще обедини последователни компоненти и ще премахне запетаите, както и ще върне тип адрес (адрес, кръстовище, пощенска кутия или двусмислен). Може да изведе грешка „RepeatedLabelError“, когато няколко области на адрес имат един и същ етикет и следователно не могат да бъдат свързани.

try:
    usaddress.tag(text)
except usaddress.RepeatedLabelError as e :
    print(e.parsed_string, e.original_string)
#(OrderedDict([('Recipient', 'DMC office address is'),
#              ('AddressNumber', '3146'),
#              ('StreetName', 'Barter'),
#             ('StreetNamePostType', 'St'),
#              ('PlaceName', 'BEAUMONT'),
#              ('StateName', 'TAXAS'),
#              ('ZipCode', '77707-3514'),
#              ('CountryName', 'US.')]),
# 'Street Address')

За картографиране на последователни етикети може да се използва следният аргумент.

usaddress.tag(text, tag_mapping={
   'Recipient': 'recipient',
   'AddressNumber': 'home1',
   'AddressNumberPrefix': 'home1',
   'AddressNumberSuffix': 'home1',
   'StreetName': 'home1',
   'StreetNamePreDirectional': 'st1',
   'StreetNamePreModifier': 'st1',
   'StreetNamePreType': 'st1',
   'StreetNamePostDirectional': 'st1',
   'StreetNamePostModifier': 'st1',
   'StreetNamePostType': 'st1',
   'CornerOf': 'st1',
   'IntersectionSeparator': 'st1',
   'LandmarkName': 'st1',
   'USPSBoxGroupID': 'st1',
   'USPSBoxGroupType': 'st1',
   'USPSBoxID': 'st1',
   'USPSBoxType': 'st1',
   'BuildingName': 'st1',
   'OccupancyType': 'home1',
   'OccupancyIdentifier': 'home1',
   'SubaddressIdentifier': 'home1',
   'SubaddressType': 'home1',
   'PlaceName': 'city',
   'StateName': 'state',
   'ZipCode': 'zip_code',
})

usaddress предоставя готова за използване функционалност за извличане и работи перфектно през повечето време.

Бележник: usaddress

Ограничение:

  • Поддържа само адрес в САЩ
  • Вероятността за прогнозиране не е налична за обработка на грешна прогноза
  • Няма скорошни актуализации в хранилище

3. NLTK

Този пакет използва метода за разбиване на NLTK³, за да анализира адреса. Той използва вече маркирани над 9000 IOB-маркирани изречения. Той използва ClassifierBasedTagger, който се основава на Naive Bayes класификатора.

Този списък е създаден с помощта на множество методи: Получаване на съществуващ набор от данни на уеб страници с информация за контакт на хотел/пица; Генериране на фалшив текст с фалшиви адреси; Вмъкване на произволни адреси в корпуса на nltk.corpus.treebank.

Какво е Chunking?
„Chunking е процесът на извличане на фрази от вече анализиран текст, т.е. получаване на съществителна фраза или глаголна фраза от POS маркирани данни.“

Какво представляват IOB таговете?
Това е нотация за парчета за улавяне на пълния токен. Тези етикети могат да обозначават вътрешната, външната страна и началото на част. Тук са разрешени не само съществителни фрази, но множество различни типове частични фрази.
B-NP:началото на съществителна фраза
I-NP: описва, че думата е вътре в текущата съществителна фраза (част от предишна дума).
O:край на изречението.

Пример:
„Mr. Бийн беше президент на САЩ.
POS тагове:
г-н NNP B-NP
Bean NNP I-NP
имаше VBD B-VP< br /> беше VBN I-VP
президент NN I-NP
на IN B-PP
USA NNP B-NP

В горното изречение г-н Бийн обозначава единствената съществителна фраза, нотациите на IOB помагат за попълване

предварително компилиран набор от маркирани данни

# Extract address from unstructured text

import pickle
import nltk
import string

from nltk import pos_tag
from nltk import word_tokenize
from nltk.chunk import ChunkParserI
from nltk.chunk import conlltags2tree, tree2conlltags
from nltk.tag import ClassifierBasedTagger
from nltk.tag.util import untag
from nltk.stem.snowball import SnowballStemmer

# IOB tag name for specifying address 
GPE_TAG = "GPE"

class AddressChunker(ChunkParserI):
    def __init__(self, train_sents, **kwargs):
        self.tagger = ClassifierBasedTagger(
            train=train_sents,
            feature_detector=self.features,
            **kwargs)

    def parse(self, tagged_sent):
        chunks = self.tagger.tag(tagged_sent)

        # Transform the result from [((w1, t1), iob1), ...]
        # to the preferred list of triplets format [(w1, t1, iob1), ...]
        iob_triplets = [(w, t, c) for ((w, t), c) in chunks]

        # Transform the list of triplets to nltk.Tree format
        return conlltags2tree(iob_triplets)
    
    def features(self, tokens, index, history):
        # for more details see: http://nlpforhackers.io/named-entity-extraction/ 
        
        """
        `tokens`  = a POS-tagged sentence [(w1, t1), ...]
        `index`   = the index of the token we want to extract features for
        `history` = the previous predicted IOB tags
        """

        # init the stemmer
        stemmer = SnowballStemmer('english')

        # Pad the sequence with placeholders
        tokens = [('[START2]', '[START2]'), ('[START1]', '[START1]')] + list(tokens) + [('[END1]', '[END1]'), ('[END2]', '[END2]')]
        history = ['[START2]', '[START1]'] + list(history)

        # shift the index with 2, to accommodate the padding
        index += 2

        word, pos = tokens[index]
        prevword, prevpos = tokens[index - 1]
        prevprevword, prevprevpos = tokens[index - 2]
        nextword, nextpos = tokens[index + 1]
        nextnextword, nextnextpos = tokens[index + 2]
        previob = history[index - 1]
        contains_dash = '-' in word
        contains_dot = '.' in word
        allascii = all([True for c in word if c in string.ascii_lowercase])

        allcaps = word == word.capitalize()
        capitalized = word[0] in string.ascii_uppercase

        prevallcaps = prevword == prevword.capitalize()
        prevcapitalized = prevword[0] in string.ascii_uppercase

        nextallcaps = prevword == prevword.capitalize()
        nextcapitalized = prevword[0] in string.ascii_uppercase

        f = {
            'word': word,
            'lemma': stemmer.stem(word),
            'pos': pos,
            'all-ascii': allascii,

            'next-word': nextword,
            'next-lemma': stemmer.stem(nextword),
            'next-pos': nextpos,

            'next-next-word': nextnextword,
            'nextnextpos': nextnextpos,

            'prev-word': prevword,
            'prev-lemma': stemmer.stem(prevword),
            'prev-pos': prevpos,

            'prev-prev-word': prevprevword,
            'prev-prev-pos': prevprevpos,

            'prev-iob': previob,

            'contains-dash': contains_dash,
            'contains-dot': contains_dot,

            'all-caps': allcaps,
            'capitalized': capitalized,

            'prev-all-caps': prevallcaps,
            'prev-capitalized': prevcapitalized,

            'next-all-caps': nextallcaps,
            'next-capitalized': nextcapitalized,
        }

        return f

def get_address_chunker(dataset_file_name):
    """
    returns AddressChunker instance with dataset_file_name as training samples
    `dataset_file_name` = file name of pickled list of CoNLL IOB format sentences
    """

    with open(dataset_file_name, 'rb') as fp:
        dataset = pickle.load(fp)
        print(len(dataset))
        chunker = AddressChunker(dataset)

    return chunker

def get_chuncker_accuracy(chunker, test_samples):
    """
    returns score of the chunker against the gold standard
    """
    score = chunker.evaluate([
        conlltags2tree([(w, t, iob) for (w, t), iob in iobs])
        for iobs in test_samples
        ])
    return score.accuracy()

def get_tagged_sentence(chunker, sentence):
    """
    returns IOB tagged tree of sentence
    """
    return chunker.parse(pos_tag(word_tokenize(sentence)))

def extract_address(chunker, sentence):
    """
    returns all addresses in sentence
    """
    def tree_filter(tree):
        return GPE_TAG == tree.label()

    tagged_tree = get_tagged_sentence(chunker, sentence)
    addresses = list()
    for subtree in tagged_tree.subtrees(filter=tree_filter):
        addresses.append(untag(subtree.leaves()))
    return addresses

print("Loading dataset...")
chunker = get_address_chunker('dataset/IOB_tagged_addresses.pkl')
# Copy your address here.
addresses = extract_address(chunker, "Hey man! Joe lives here: 44 West 22nd Street, New York, NY 12345. Can you contact him now? If you need any help, call me on 12345678")
print([" ".join(address) for address in addresses])

Модулът NLTK извлича всички възможни набори от пълни адреси в текста. В момента не анализира адресите. Въпреки това, той може да се използва като предшественик за модели на парсер на адреси като usaddressза по-добро цялостно прогнозиране.

Бележник: nltk_chunker

Ограничение:

  • Работи само за адрес в САЩ
  • Не анализира текста на адреса

4. Усет

Flair⁵ е една от мощните библиотеки, разработена от Хумболтовия университет в Берлин. Flair може да се използва за всички популярни NLP задачи като класификация, разпознаване на именувани обекти, класификация с нулев удар и много други.

За извличането на адреси взехме предвид вече анотирания набор от данни [4]. Наборът от данни съдържа 200 анотирани проби от адреси в САЩ в следните категории.

  • Име на сграда
  • Номер_на_сграда
  • Име на улица
  • Град, щат
  • Пощенски код
  • Държава
  • Получател

Планираме да обучим модела с предварително обучен модел от библиотека за усещане.

  1. Инсталирайте библиотеката flair
!pip install flair

2. Наборът от данни трябва да бъде преобразуван във формат за въвеждане на Flair, т.е. BIO нотация.

import pandas as pd
import numpy as np
import pandas as pd
from flair.data import Corpus
from flair.datasets import ColumnCorpus
import re, math
columns = ['Building_Name', 'Building_Number', 'City', 'Recipient',
       'Street_Name', 'Zip_Code', 'State', 'Country']
count=0
labels = set()
def generate_data(file_name):
    data = pd.read_csv(file_name)
    def get_value(x):
        global count
        results = []
        address = x["Address"]
        previous = ""
        _temp = x.to_dict()
        for each in address.split():
            match = False
            for col in columns:
                if each.strip(" ,.-") in str(_temp[col]):
                    if previous == col:
                        results.append((count, each, "I-"+col))
                        labels.add("I-"+col)
                    else:
                        results.append((count, each, "B-"+col)) 
                        labels.add("B-"+col)
                    previous = col
                    match = True
                    break
            if not match:
                results.append((count, each, "O")) 
                labels.add("O")
                match = False
        results.append(("", "",""))
        count += 1
        return results
    values = data[:].apply(lambda x:get_value(x), axis=1)
    flat_list = [item for sublist in values for item in sublist]
    train_df = pd.DataFrame(flat_list, columns=["sentence_id", "words", "labels"])
    return train_df

3. Заредете влака и тествайте csv файла.

train_df = generate_data("us-train-dataset.csv")
test_df = generate_data("us-test-dataset.csv")
train_df[["words", "labels"]].tail(20)

4. Създайте текстов файл, съвместим с flair input

train_df[["words", "labels"]].to_csv(r'train/train.txt', header=None, index=None, sep=' ')
test_df[["words", "labels"]].to_csv(r'train/test.txt', header=None, index=None, sep=' ')

5. Заредете набора от данни и инициализирайте вгражданията

# define columns
columns = {0 : 'text', 1 : 'ner'}
# directory where the data resides
data_folder = 'train/'
# initializing the corpus
corpus: Corpus = ColumnCorpus(data_folder, columns,
                              train_file = 'train.txt',
                              test_file = 'test.txt',
                              dev_file = 'test.txt')
print(len(corpus.train))
# tag to predict
columns = {0: 'text', 1: 'ner'}
tag_type = columns[1]
# make tag dictionary from the corpus
tag_dictionary = corpus.make_label_dictionary("ner")
from flair.embeddings import FlairEmbeddings, TransformerWordEmbeddings
# init Flair embeddings
flair_forward_embedding = FlairEmbeddings('multi-forward')
flair_backward_embedding = FlairEmbeddings('multi-backward')
# init multilingual BERT
bert_embedding = TransformerWordEmbeddings('bert-base-multilingual-cased')
from flair.embeddings import StackedEmbeddings
# now create the StackedEmbedding object that combines all embeddings
embeddings = StackedEmbeddings(
    embeddings=[flair_forward_embedding, flair_backward_embedding, bert_embedding])

6. Обучете модела

from flair.datasets import CONLL_03
from flair.embeddings import WordEmbeddings, FlairEmbeddings, StackedEmbeddings
from flair.models import SequenceTagger
from flair.trainers import ModelTrainer
print(corpus)

# 2. what label do we want to predict?
label_type = 'ner'

# 3. make the label dictionary from the corpus
label_dict = corpus.make_label_dictionary(label_type=label_type)
print(label_dict)

# 4. initialize embedding stack with Flair and GloVe
embedding_types = [
    # WordEmbeddings('glove'),
    FlairEmbeddings('news-forward'),
    FlairEmbeddings('news-backward'),
]

embeddings = StackedEmbeddings(embeddings=embedding_types)

# 5. initialize sequence tagger
tagger = SequenceTagger(hidden_size=256,
                        embeddings=embeddings,
                        tag_dictionary=label_dict,
                        tag_type=label_type,
                        use_crf=True)

# 6. initialize trainer
trainer = ModelTrainer(tagger, corpus)

# 7. start training
trainer.train('resources/taggers/sota-ner-flair',
              learning_rate=0.1,
              mini_batch_size=32,
              max_epochs=50)

7. Прогноза за невидяни данни.

from flair.data import Sentence
from flair.models import SequenceTagger
# load the trained model
model = SequenceTagger.load('/content/resources/taggers/sota-ner-flair/best-model.pt')
# create example sentence
sentence = Sentence('My address is 223 NW STATE STRE, DOVER, DE 19001, United States, Thank you for confirming.')
# predict the tags
model.predict(sentence)
# print(sentence.to_tagged_string())
print(sentence.labels)

Базираното на трансформатор вграждане може да се използва и за фина настройка. Помислете за експериментиране с хиперпараметри за по-добра прогноза.

Тетрадка: Flair

Ограничение:

  • За по-добри резултати е необходим по-голям набор от данни
  • Времето за извод е малко по-високо за процесора

5. Прост трансформатор

Simple transformer⁶ е NLP библиотека, която е оптимизирана за лесна употреба. Той предоставя всички възможности на трансформатора с много минимални редове код. Той осигурява поддръжка за всички стандартни NLP задачи като NER, класификация, отговор на въпрос и т.н.

За да обучим персонализирания модел за извличане на адреси, ние разглеждаме горния набор от данни.

  1. Инсталирайте пакета Transformer
!pip install simpletransformers

2. Преобразувайте входния набор от данни в нотация BOI. Simple Transformer изисква данни в IOB нотация с sentence_id, думи и колони с етикети.

import pandas as pd
import re, math
import numpy as np
import pandas as pd
from scipy.special import softmax
from simpletransformers.ner import NERModel
import logging
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)
columns = ['Building_Name', 'Building_Number', 'City', 'Recipient',
       'Street_Name', 'Zip_Code', 'State', 'Country']
count=0
labels = set()
def generate_data(file_name):
    data = pd.read_csv(file_name)
    def get_value(x):
        global count
        results = []
        address = x["Address"]
        previous = ""
        _temp = x.to_dict()
        for each in address.split():
            match = False
            for col in columns:
                if each.strip(" ,.-") in str(_temp[col]):
                    if previous == col:
                        results.append((count, each, "I-"+col))
                        labels.add("I-"+col)
                    else:
                        results.append((count, each, "B-"+col)) 
                        labels.add("B-"+col)
                    previous = col
                    match = True
                    break
            if not match:
                results.append((count, each, "O")) 
                labels.add("O")
                match = False
        # results.append(("", "",""))
        count += 1
        return results
    values = data[:].apply(lambda x:get_value(x), axis=1)
    flat_list = [item for sublist in values for item in sublist]
    train_df = pd.DataFrame(flat_list, columns=["sentence_id", "words", "labels"])
    return train_df
train_df = generate_data("us-train-dataset.csv")
test_df = generate_data("us-test-dataset.csv")
train_df.to_csv(r'pandas1.txt', header=None, index=None, sep=' ', mode='a')

3. Инициализирайте NER модела

arguments={"save_eval_checkpoints": False,
      "save_steps": -1,
      'overwrite_output_dir': True,
      "save_model_every_epoch": False,
      'reprocess_input_data': True, 
      "train_batch_size": 5,
      'num_train_epochs': 50,
      "max_seq_length": 256, 
      "gradient_accumulation_steps": 8,
      "learning_rate": 4e-5,
      "do_lower_case": False,
      "adam_epsilon" : 1e-8,
      "train_batch_size": 8,
      "eval_batch_size": 8,
      "fp16" : True
      }
model = NERModel(
    "bert",
    "distilbert-base-uncased",
    args=arguments,
    labels =  list(labels)
)

Имаме стриктно конфигурирани следните параметри за по-добра точност.

  • do_lower_case: Вярно: Главните букви помагат да се осигури по-добър контекст
  • rate_Learning: 4e-5 : Стандартна скорост на обучение
  • train_batch_size и evel_batch_size могат да бъдат увеличени, ако се добави още проба

4. Стартирайте тренировъчния цикъл

# Train the model
model.train_model(train_df)
# Evaluate the model
result, model_outputs, predictions = model.eval_model(train_df)
print(result)
# {'eval_loss': 0.11480890100614892,
#  'precision': 0.9591054313099041,
#  'recall': 0.9578813018506701,
#  'f1_score': 0.9584929757343551}
# prediction on test dataset (unseen sample)
result, model_outputs, predictions = model.eval_model(test_df)
print(result)
#{'eval_loss': 0.7861490646998087,
# 'precision': 0.7011494252873564,
# 'recall': 0.7176470588235294,
# 'f1_score': 0.7093023255813954}

5. Прогноза за набор от тестови данни

# Predictions on arbitrary text strings
sentences = ["I stay at HIGHWAY 11-E, RUSSELLVILLE, TN 00000, United States"]
predictions, raw_outputs = model.predict(sentences)
print(predictions)
[[{'I': 'O'},
{'stay': 'I-Street_Name'},
{'at': 'O'},
{'HIGHWAY': 'I-Street_Name'},
{'11-E,': 'I-Street_Name'},
{'RUSSELLVILLE,': 'B-City'},
{'TN': 'B-State'},
{'00000,': 'O'},
{'United': 'B-Country'},
{'States': 'I-Country'}]]

Постигнал е добра точност с ограничен размер на набора от данни и епоха. Въпреки това, той може да бъде подобрен с повече проби и фина настройка.

Бележник: ST

Ограничение:

  • За по-добри резултати е необходим по-голям набор от данни
  • Времето за извод е малко по-високо за процесора

Акценти

  1. pyap и usaddress предоставят готови възможности за анализ.
  2. Usaddress работи добре през повечето време, но му липсва оценката за увереност за прогнозите
  3. Моделът Flair или трансформатор на изречения предоставя добри възможности поради следните причини
    - Огромен контрол върху очакваното извличане
    - Може да се подобри с по-големи данни за обучение

Заключение

В заключение, извличането на адреси с машинно обучение е мощен инструмент, който може да помогне на бизнеса и организациите бързо и точно да обработват големи количества писмени данни. Чрез използването на алгоритми за машинно обучение е възможно автоматично да се извличат адреси от писмен текст, което улеснява организирането и управлението на големи количества данни.

Използването на НЛП техники може да бъде много ефективно при извличане на адресна информация от неструктурирани текстови данни. Тези изброени техники могат да се използват за идентифициране и извличане на адреси от различни източници като имейли и онлайн формуляри. Важно е обаче да се отбележи, че ефективността на техниките ще зависи от качеството и формата на входните данни. Поради това е изключително важно данните да бъдат предварително обработени, като например премахване на неподходяща информация, преди да се приложат NLP техники за подобряване на точността на извличането на адреса. Освен това е важно също така да се оценят и фино настроят моделите, за да се гарантира, че могат да се справят с различни адресни формати и вариации.

справка

  1. https://pypi.org/project/pyap
  2. https://pypi.org/project/usaddress/
  3. https://github.com/bagrii/address_extraction
  4. https://github.com/swapnil-saxena/address-parser/tree/main/corpus/dataset
  5. https://github.com/flairNLP/flair
  6. https://simpletransformers.ai/docs/ner-specifics/

Ако ви харесва тази статия, моля, насърчете ме с пляскания. свържете се с мен в LinkedIn. Моля, намерете github repo.