Извлечение троек SVO из предварительно обработанного текста

Мне нужно извлечь тройки субъект-глагол-объект из голландского текста. Текст анализируется голландским инструментом НЛП под названием Frog, который токенизирует, анализирует, маркирует, лемматизирует. ..Это. Frog производит FoLiA XML или вывод в формате столбцов с разделителями табуляцией, по одной строке на токен. Из-за некоторых проблем с файлом XML я выбрал формат столбца. В этом примере представлено одно предложение. введите здесь описание изображения Теперь мне нужно извлечь для каждого предложения тройки SVO, поэтому мне нужен последний столбец, который представляет собой отношения зависимости. Итак, мне нужно получить элемент ROOT и элементы su и obj1, которые принадлежат ROOT. К сожалению, в предложении-примере нет obj1. Давайте притворимся, что это так. Моя идея заключалась в том, чтобы сначала создать вложенный список со списком на каждое предложение.

    import csv
    with open('romanfragment_frogged.tsv','r') as f:
         reader = csv.reader(f,delimiter='\t')
         tokens = []
         sentences = []
         list_of_sents = []
         for line in reader:
             tokens.append(line)
             #print(tokens)
             for token in tokens:
                 if token == '1':
                    previous_sentence = list_of_sents
                    sentences.append(previous_sentence)
         list_of_sents = []
         list_of_sents.append(tokens)
         print(list_of_sents)

Когда я печатаю «токены», я получаю один список со всеми токенами. Так что это правильно, но я все еще пытаюсь создать вложенный список с одним списком (токенов) на предложение. Может кто-нибудь помочь мне с этой проблемой?

(P.S. вторая проблема в том, что я не уверен, как продолжить, когда я получаю вложенный список)


person Bambi    schedule 31.05.2017    source источник
comment
Я думаю, что для начала есть некоторая путаница по поводу формата ввода. На веб-сайте инструмента, на который вы ссылаетесь, указано, что вывод - это XML. Однако изображение и ваша попытка разбить на "\t" предполагают, что это файл TSV (простой текст, разделенный табуляцией). И снова вы утверждаете, что это документ Word - по-видимому, старая двоичная версия .doc, что было бы наихудшим из всех вариантов. Разберитесь с этим и обновите вопрос.   -  person lenz    schedule 31.05.2017
comment
@lenz Как указано на веб-сайте, существует 2 варианта вывода: «Frog создает FoLiA XML или вывод в формате столбцов с разделителями табуляции, по одной строке на токен». Из-за некоторых проблем с файлом XML я выбрал формат столбца. Но я сохранил его как .doc, как вы сказали, лучше сохранить его как .txt файл?   -  person Bambi    schedule 31.05.2017
comment
Хорошо, я понимаю - я думаю, вы на самом деле не сохранили его как документ Word, вы просто сохранили его с именем файла, заканчивающимся на .doc. Условно использовать .tsv или иногда .csv.   -  person lenz    schedule 31.05.2017
comment
Основная проблема здесь в том, что for line in text перебирает символы в тексте. В отличие от открытого файла строковые объекты не разбивают текст на строки волшебным образом при повторении. Лучше всего использовать with open(...) as f:, а затем внутри этого блока for line in f: и т. Д. Также рассмотрите возможность использования библиотеки csv для анализа файла TSV.   -  person lenz    schedule 31.05.2017
comment
@lenz Я снова проанализировал текст и на этот раз сохранил его в Frog как файл .tsv. Я изменил свой код и вопрос выше. Мне удалось собрать все строки в один список. Но теперь я не знаю, как составить вложенный список по каждому предложению. Я новичок в программировании, поэтому у меня еще много проблем и вопросов   -  person Bambi    schedule 31.05.2017
comment
Я бы использовал verb-srl и извлекал A0-A1: deagol.cs.illinois.edu:8080   -  person Daniel    schedule 31.05.2017
comment
@ Дэниел Это работает на голландском языке? Потому что инструмент Frog NLP очень точен, особенно для голландцев. Кроме того, мой университет просит использовать инструмент Frog NLP.   -  person Bambi    schedule 31.05.2017


Ответы (1)


Может, что-то вроде этого могло бы сработать:

def iter_sentences(fn):
    with open(fn, 'r') as f:
         reader = csv.reader(f,delimiter='\t')
         sentence = []
         for row in reader:
             if not row:
                # Ignore blank lines.
                continue
             if row[0] == '1' and sentence:
                 # A new sentence started.
                 yield sentence
                 sentence = []
             sentence.append(row)
         # Last sentence.
         if sentence:
             yield sentence

def iter_triples(fn):
    for sentence in iter_sentences(fn):
        # Get all subjects and objects.
        subjects = [tok for tok in sentence if tok[-1] == 'su']
        objects = [tok for tok in sentence if tok[-1] == 'obj1']
        # Now try to map them: find pairs with a head in the same position.
        for obj in objects:
            for subj in subjects:
                # row[-2] is the position of the head.
                if subj[-2] == obj[-2]:
                    # Matching subj-obj pair found.
                    # Now get the verb (the head of both subj and obj).
                    # Its position is given in the second-to-last column.
                    position = int(subj[-2])
                    # Subtract 1, as the positions start counting at 1.
                    verb = sentence[position-1]
                    yield subj, verb, obj

for subj, verb, obj in iter_triples('romanfragment_frogged.tsv'):
    # Only print the surface forms.
    print(subj[1], verb[1], obj[1])

Краткое объяснение: iter_sentences перебирает предложения. Каждое предложение представляет собой вложенный список: это список токенов, а каждый токен - это сам список (содержащий номер строки, форму поверхности, лемму, POS, зависимость и т. Д.). Функция iter_triples перебирает тройки ‹подлежащее, глагол, объект›. Каждый элемент этих троек представляет собой токен (то есть снова список).

Последние три строки кода - это просто пример того, как использовать функцию iter_triples. Я не знаю, сколько и какой информации нужно от каждой тройки ...

person lenz    schedule 31.05.2017
comment
благодарю вас! Но этот код for row in reader: if row[0] == '1' and sentence дает мне ошибку индекса: индекс списка вне допустимого диапазона - person Bambi; 01.06.2017
comment
Наверное, пустая строка. Вы можете добавить if not row: continue перед этой проверкой, тогда пустые строки будут пропущены. - person lenz; 01.06.2017
comment
действительно, проблема решена. Я отредактировал ваш код. Теперь у меня осталось 2 небольших вопроса. 1. Я не совсем понимаю, как работает эта строка verb = предложение [int (subj [-2]) - 1]. 2. Мне это нужно для работы с другим текстом. Тройки SVO служат функцией машинного обучения. Можно ли получить в качестве вывода из iter_triples вложенный список с тройками на предложение, но только с именем токена и отношением. Итак, элементы 2 и 10 из списка на токен? - person Bambi; 01.06.2017
comment
(1) Я попытался прояснить это. Предпоследний столбец - это указатель на токен / строку, которая является заголовком. Нам нужно преобразовать его в целое число, а затем вычесть 1, потому что списки Python начинаются с 0, а не с 1. (2) Чтобы получить троек в предложениях, вы можете удалить внешний цикл for (= удалить первый список) и вызвать функция с предложением вместо имени файла. - person lenz; 01.06.2017
comment
Спасибо за разъяснение. Это мой самый последний вопрос. Поправьте меня если я ошибаюсь. Я думал, что позиции, которые вы можете прочитать в предпоследнем столбце, начинаются с 0, потому что позиция глагола, ROOT всегда равна 0. Я также до сих пор не понимаю, почему мы делаем verb = предложение [... ] в этой строке. Я все еще немного запутался в этой строке кода. - person Bambi; 01.06.2017
comment
Цифры в предпоследнем столбце относятся к номерам, которые вы видите в первом столбце. У корня нет головы, поэтому нет строки, на которую он мог бы указывать, что выражается через 0. - Переменная sentence представляет собой список токенов (строк TSV). Например, sentence[0] - это строка для токена Мари. Голова этого токена находится в позиции 2, поэтому мы вычитаем 1 и ищем sentence[1], т.е. вторая строка, которая представляет токен vroeg. - person lenz; 01.06.2017
comment
О, теперь я полностью понимаю это Спасибо за вашу помощь! - person Bambi; 01.06.2017