Обработка искаженных текстовых данных с помощью машинного обучения или НЛП - PullRequest
8 голосов
/ 26 января 2012

Я пытаюсь извлечь данные из нескольких больших текстовых файлов, содержащих записи о людях.Однако проблема в том, что я не могу контролировать способ получения данных.

Обычно он имеет такой формат:

LASTNAME, Firstname Middlename (может быть, псевдоним)Почему этот текст здесь? Январь, 25, 2012

Имя Фамилия 2001 Некоторые тексты, которые меня не волнуют

Фамилия, Имя бла-бла ... 25 января 2012 ...

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

Это кажется неоптимальным.

Существуют ли какие-либо библиотеки машинного обучения для Python, которые могут анализировать искаженные данные, которыенесколько структурирован?

Я пробовал NLTK, но он не мог справиться с моими грязными данными.Сейчас я работаю с Orange, и мне нравится его стиль ООП, но я не уверен, что теряю время зря.

В идеале, я бы хотел сделать что-то подобное для обучения парсера.(со многими парами ввода / вывода):

training_data = (
  'LASTNAME, Firstname Middlename (Maybe a Nickname)FooBarJanuary 25, 2012',
   ['LASTNAME', 'Firstname', 'Middlename', 'Maybe a Nickname', 'January 25, 2012']
)

Возможно ли что-то подобное или я переоцениваю машинное обучение?Будем благодарны за любые предложения, так как я хотел бы узнать больше об этой теме.

Ответы [ 5 ]

3 голосов
/ 09 марта 2012

В итоге я реализовал несколько сложную серию исчерпывающих регулярных выражений, которые охватывали все возможные варианты использования с использованием текстовых «фильтров», которые были заменены соответствующими регулярными выражениями при загрузке анализатора.

Если кто-то заинтересован в коде, я отредактирую его в этом ответе.


Вот в основном то, что я использовал. Чтобы создать регулярные выражения из моего «языка», я должен был сделать замену классов:

class Replacer(object):
    def __call__(self, match):
        group = match.group(0)

        if group[1:].lower().endswith('_nm'):
            return '(?:' + Matcher(group).regex[1:]
        else:
            return '(?P<' + group[1:] + '>' + Matcher(group).regex[1:]

Затем я создал общий класс Matcher, который сконструировал регулярное выражение для определенного шаблона с учетом имени шаблона:

class Matcher(object):
    name_component =    r"([A-Z][A-Za-z|'|\-]+|[A-Z][a-z]{2,})"
    name_component_upper = r"([A-Z][A-Z|'|\-]+|[A-Z]{2,})"

    year = r'(1[89][0-9]{2}|20[0-9]{2})'
    year_upper = year

    age = r'([1-9][0-9]|1[01][0-9])'
    age_upper = age

    ordinal = r'([1-9][0-9]|1[01][0-9])\s*(?:th|rd|nd|st|TH|RD|ND|ST)'
    ordinal_upper = ordinal

    date = r'((?:{0})\.? [0-9]{{1,2}}(?:th|rd|nd|st|TH|RD|ND|ST)?,? \d{{2,4}}|[0-9]{{1,2}} (?:{0}),? \d{{2,4}}|[0-9]{{1,2}}[\-/\.][0-9]{{1,2}}[\-/\.][0-9]{{2,4}})'.format('|'.join(months + months_short) + '|' + '|'.join(months + months_short).upper())
    date_upper = date

    matchers = [
        'name_component',
        'year',
        'age',
        'ordinal',
        'date',
    ]

    def __init__(self, match=''):
        capitalized = '_upper' if match.isupper() else ''
        match = match.lower()[1:]

        if match.endswith('_instant'):
            match = match[:-8]

        if match in self.matchers:
            self.regex = getattr(self, match + capitalized)
        elif len(match) == 1:
        elif 'year' in match:
            self.regex = getattr(self, 'year')
        else:
            self.regex = getattr(self, 'name_component' + capitalized)

Наконец, есть общий Pattern объект:

class Pattern(object):
    def __init__(self, text='', escape=None):
        self.text = text
        self.matchers = []

        escape = not self.text.startswith('!') if escape is None else False

        if escape:
            self.regex = re.sub(r'([\[\].?+\-()\^\\])', r'\\\1', self.text)
        else:
            self.regex = self.text[1:]

        self.size = len(re.findall(r'(\$[A-Za-z0-9\-_]+)', self.regex))

        self.regex = re.sub(r'(\$[A-Za-z0-9\-_]+)', Replacer(), self.regex)
        self.regex = re.sub(r'\s+', r'\\s+', self.regex)

    def search(self, text):
        return re.search(self.regex, text)

    def findall(self, text, max_depth=1.0):
        results = []
        length = float(len(text))

        for result in re.finditer(self.regex, text):
            if result.start() / length < max_depth:
                results.extend(result.groups())

        return results

    def match(self, text):
        result = map(lambda x: (x.groupdict(), x.start()), re.finditer(self.regex, text))

        if result:
            return result
        else:
            return []

Это стало довольно сложно, но это сработало. Я не собираюсь публиковать весь исходный код, но это должно кого-то начать. В конце концов, он конвертировал файл так:

$LASTNAME, $FirstName $I. said on $date

В скомпилированное регулярное выражение с именованными группами захвата.

0 голосов
/ 07 февраля 2012

Несколько указателей, чтобы начать:

  • для разбора даты, вы можете начать с пары регулярных выражений, а затем вы можете использовать хронический или jChronic
  • для имен, эти модели OpenNlp должны работать

Что касается обучения модели машинного обучения самостоятельно, это не так просто, особенно вданные тренировки (трудозатраты) ...

0 голосов
/ 26 января 2012

Что касается составных слов, их можно разделить с помощью токенизатора:

OpenNLP Tokenizer сегментирует входную последовательность символов в токены. Токенами обычно являются слова, знаки препинания, цифры и т. Д.

Например:

Пьер Винкен, 61 год, присоединится к совету директоров в качестве неисполнительного директора 29 ноября.

маркируется на:

Пьер Винкен, 61 год, присоединится к совету директоров в качестве неисполнительного директора 29 ноября.

В OpenNLP есть «обучаемый токенизатор», который вы можете обучать. Если не работает, вы можете попробовать ответы на: Определить наиболее вероятные слова из текста без пробелов / объединенные слова .

Когда разделение выполнено, вы можете устранить пунктуацию и передать ее в систему NER, такую ​​как CoreNLP :

Джонсон Джон Доу Может быть, псевдоним Почему этот текст здесь 25 января 2012

который выводит:

    Tokens
Id  Word    Lemma   Char begin  Char end    POS NER Normalized NER
1   Johnson Johnson 0   7   NNP PERSON  
2   John    John    8   12  NNP PERSON  
3   Doe Doe 13  16  NNP PERSON  
4   Maybe   maybe   17  22  RB  O   
5   a   a   23  24  DT  O   
6   Nickname    nickname    25  33  NN  MISC    
7   Why why 34  37  WRB MISC    
8   is  be  38  40  VBZ O   
9   this    this    41  45  DT  O   
10  text    text    46  50  NN  O   
11  here    here    51  55  RB  O   
12  January January 56  63  NNP DATE    2012-01-25
13  25  25  64  66  CD  DATE    2012-01-25
14  2012    2012    67  71  CD  DATE    2012-01-25
0 голосов
/ 26 января 2012

Одна часть вашей проблемы: «все слова с названием месяца, прикрепленными к концу»,

Если, как представляется, у вас есть дата в формате Monthname 1-or-2-digit-day-number, yyyy в концеСтрока, вы должны использовать регулярное выражение, чтобы жевать это в первую очередь.Тогда у вас теперь намного более простая работа с оставшейся частью входной строки.

Примечание. В противном случае вы можете столкнуться с проблемами с указанными именами, которые также являются названиями месяцев, например, апрель, май, июнь, август.Также March - это фамилия, которую можно использовать как «второе имя», например, SMITH, John March.

Вы используете терминологию «последний / первый / средний» «интересно».Существуют потенциальные проблемы, если ваши данные содержат неанглоязычные имена, подобные этим:

Mao Zedong aka Mao Ze Dong aka Mao Tse Tung
Sima Qian aka Ssu-ma Ch'ien
Saddam Hussein Abd al-Majid al-Tikriti
Noda Yoshihiko
Kossuth Lajos
José Luis Rodríguez Zapatero
Pedro Manuel Mamede Passos Coelho
Sukarno

0 голосов
/ 26 января 2012

У меня похожая проблема, в основном из-за проблемы с экспортом данных из Microsoft Office 2010, и в результате получается соединение двух последовательных слов с некоторой регулярностью.Область домена - это морфологическая операция, подобная проверке орфографии.Вы можете перейти к решению для машинного обучения или создать решение для эвристики, как я.

Простое решение состоит в том, чтобы предположить, что вновь сформированное слово представляет собой комбинацию собственных имен (с заглавной буквой первого символа).

Второе дополнительное решение состоит в том, чтобы иметь словарь допустимых слов и попробовать набор местоположений разделов, которые генерируют два (или хотя бы одно) допустимых слова.Другая проблема может возникнуть, когда одним из них является собственное имя, которое по определению не входит в словарь предыдущего словаря.возможно, мы можем использовать статистику длины слова, чтобы определить, является ли слово ошибочно сформированным или действительно допустимым.

В моем случае это часть ручной коррекции больших корпусовтекст (проверка «человек в цикле»), но единственное, что можно автоматизировать, - это выбор, возможно, неправильно сформированных слов и их исправленная рекомендация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...