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

Немного саморекламы

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

Что такое когезия

Когезия, как явление, очень основательно описана в работе Халидая и Хасана 1976 года под названием "Cohesion in English". По определению авторов, когезия - это явление непрерывности между разными частями того, что мы называем текстом. Эта непрерывность образуется благодаря грамматическим и лексическим связям между отдельными смысловыми сущностями, которыми могут выступать предложения или простые части сложных предложений. Отношения смысловых сущностей в тексте выражаются как “предполагающий” и “предполагаемый”, например

Вымойте и приготовьте шесть вареных яблок. Поместите их в огнеупорную посуду.

Слово "их" предполагает слово "яблок", создавая связь между двумя предложениями, т.е. образуя когезию. Без когезии текст бы просто разваливался на части.

Видов когезии существует достаточно много: выделяют пять разных видов когезии с их подвидами. Диаграмма этих видов показана на рисунке ниже. Чтобы не нагружать пост, дам ссылку, где вы можете найти их описание в [3] или в статье на Вики. Я же остановлю подробнее только на лексической когезии.

Полное дерево видов когезии
Полное дерево видов когезии

Лексическая когезия

Лексическая когезия отличается от других видов тем, что она образуется при выборе определенного набора слов, а не с помощью грамматических конструкций. Давайте посмотрим детально на виды лексической когезии. Их существует два:

  • повторительный - повторение лексического элемента, ссылки на него или использование какого-либо его синонима,

  • словосочетательная - связь, которая возникает при частом совместном появлении слов вместе.

Дерево видов лексической когезии
Дерево видов лексической когезии

Рассмотрим примеры каждого подтипа:

  1. Повторение с указанием ссылки. Он сел в машину. В машине было холодно. Холодно именно в той машине, в которую сел некий "он".

  2. Повторение без идентификации. Петр купил машину. Ему нравятся красные машины. Петру нравятся красные машины в принципе, а не только ту машину которую он купил.

  3. Повторение с родительскими по абстракции словами. Петр купил седан. Он давно хотел купить машину. Здесь слово "седан" - это подмножество машин.

  4. Систематические семантические отношения (систематически классифицируемые): Леше нравятся красные машины. Он не любит синие. Слова "красные" и "синие" обозначают цвета - то, что можно собрать в одну четкую группу.

  5. Не систематические семантические отношения (систематически не классифицируемые): Миша провел в гараже весь день. Он ремонтировал машину УАЗ. Гараж и машина семантически близкие слова, которые часто встречаются рядом.

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

Когерентность и ее отличие от когезии

Теперь поговорим о когерентности и ее взаимосвязи с когезией. Если когезия определяет способ, благодаря которому текст связан, то когерентность отражает смысловое содержание текста в целом. Другими словами, когерентность отражает то, о чем нам хотел сказать автор текста. Именно это свойство когерентности тесно связывает ее с понятием дискурса - более общее понятие, которое описывает такие речевые явления, как текст, диалог или монолог. Когерентность является носителем смысла дискурса. К дискурсу мы еще вернемся.

Понятие когерентности играет важную роль в задачах генерации саммари, сегментации текста и оценки сложности текста.

Если отношения когезии довольно хорошо определены, то вот с когерентностью все гораздо сложнее: на сегодняшний день существуют несколько теорий, которые описывают отношения когерентности. На их базе лингвисты старались придумать вычислительные методы их определения в тексте. Но, оказывается, что иногда даже людям трудно определить эти отношения. Далее, я постараюсь это проиллюстрировать.

Рассмотрим два вида отношений из одной теории: элаборация и объяснение. Элаборация, простыми словами, это когда второе предложение добавляет какую-то важную информацию о ранее упомянутой сущности. Объяснение, это когда второе предложение объясняет то, что написано в первом. Взглянем на такой пример.

1. Вася может открыть сейф Пети.
2. Он знает комбинацию.

Автор относит этот пример к элаборации. Добавим теперь одно предложение

1. Кто может открыть эти сейфы?
2. Вася может открыть сейф Пети.
3. Он знает комбинацию.

Теперь то же самое отношение можно характеризовать как объяснение, но это не отменяет того, что это похоже на элаборацию. Когерентность очень сильно зависит от представленной информации и точки зрения читающего.

Поговорим о взаимосвязи между когерентностью и когезией. Вообще говоря, когерентность может существовать даже если нет каких-то явно определенных локальных отношений, при условии, что в тексте говорится об одном и том же. Поэтому можно было бы сказать, что именно когерентность определяет когезию. Текст примера выше, очевидно, когерентен, а пара слов "сейф" и "комбинация" связаны по смыслу, образуя при этом словосочетательную когезию. Из этого следует, что когезия может служить индикатором наличия когерентности между предложениями. Однако, наличие когерентности не является обязательным условием для существования когезии. Вот оригинальный пример текста из статьи с когезией, но без когерентности

Wash and core six apples. Use them to cut out the material for your new suit. 
They tend to add a lot to the color and texture of clothing. 
Actually, maybe you should use five of them instead of six, since they are quite large.

А вот когерентный текст без когезии

I came home from work at 6:00 p.m. 
Dinner consisted of two chicken breasts and a bowl of rice.

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

Лексические цепи

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

Для того чтобы лично познакомиться с лексическими цепями, рассмотрим оригинальный пример из статьи:

In front of me lay a virgin crescent cut out of pine bush. 
A dozen houses were going up, in various stages of construction, 
surrounded by hummocks of dry earth and stands of precariously 
tall trees nude halfway up their trunks. 
They were the kind of trees you might see in the mountains.

В данном случае, лексическая цепь представляет собой набор слов {virgin, pine, bush, trees, trunks, trees}.

Для чего важны лексические цепи?

Во-первых, т.к. значение слова определяются по его контексту, лексические цепи можно использовать для снятия лексической многозначности, ведь они задают тот самый контекст. Если мы рассмотрим цепь {море, ветер, коса, песок}, очевидно, что слово "коса" обозначает берег, а не ручной инструмент или прическу. Во-вторых, по скольку единица дискурса имеет тенденцию к использованию связанных по смыслу слов, они помогают определять структуру дискурса и, как следствие, как уже отмечалось, когеренцию текста, а через нее и смысл.

В статье авторы, опираясь на одну из теорий дискруса, показывают, как лексические цепи могут помочь в поиске струкутур в рамках этой теории. Сама теория была описана в работе [5]. Ее основное положение гласит, что любой дискурс представляет собой пирамиду из трех структур:

  • Лингвистическая структура - фундамент пирамиды, который представляет собой разделение дискурса по группам предложений, каждая из которых играет определенную роль в дискурсе. Переход от одной группы к другой говорит об изменении темы или идеи разговора. Допускается, что границы могут быть нечеткими, однако для более точного их определения существуют ключевые слова.

  • Структура намерений - показывает, как отдельные сегменты вносят вклад в общую цель дискурса. Цель дискурса отражает то, зачем автор пишет или говорит что-то: убедить в чем-то, рассказать, озадачить. Соответственно, каждый сегменты вносит свой вклад в достижение этой цели. Причем, между сегментами возникает два типа взаимосвязи.

    • Первый тип показывает, что завершение одного сегмента ведет к завершению другого.

    • Второй тип показывает, что для завершения какого-то сегмента должно произойти завершение другого.

  • Структура внимания - эта стековая структура наборов сущностей. На вершине стека находится сущность, которой уделено внимание в данные момент времени. По мере продвижение по тексту или речи, разные сегменты могут говорить о разных темах, для которых существуют отдельные наборы сущностей. Иногда фокус может сместиться к ранее упомянутым темам, как это было в этом посте выше

    Когеренотность является носителем смысла дискурса. К дискурсу мы еще вернемся.

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

Так вот, в работе [1] говорится о том, что лексические цепи могут служить индикаторами лингвистических сегментов, а следовательно и соответствующей структуры: заканчивается цепь, заканчивается и лингвистический сегмент, а с началом новой цепи - новый сегмент. Далее в статье она показывает, как использовать лексические цепи для определения структуры намерений, что странно, ведь речь шла лингвистическую структуру, но авторы написали "based on the theory", т.е. возможно есть несказанная импликация. Пример здесь я приводить не буду, см. 4.3 в статье.

Алгоритм нахождения лексических цепей

Мне попался один репозиторий с реализацией алгоритма построения лексических цепей, который довольно близок к оригинальному алгоритму. Там же показан алгоритм саммаризации, основанный на этих цепях. Хотя описание алгоритма есть в лежащем там pdf-файле, опишу его и здесь для целостности. Для работы нам понадобится питон и библиотека NLTK.

Итак, на входе у нас есть англоязычный текст. Первым делом нужно извлечь из него все существительные.

position = ['NN', 'NNS', 'NNP', 'NNPS']
    
sentence = nltk.sent_tokenize(input_txt)
tokenizer = RegexpTokenizer(r'\w+')
tokens = [tokenizer.tokenize(w) for w in sentence]
tagged =[pos_tag(tok) for tok in tokens]
nouns = [word.lower() for i in range(len(tagged)) for word, pos in tagged[i] if pos in position ]

Затем, при помощи WordNet нам нужно для каждого слова найти все синонимы, антонимы, гипонимы и гиперонимы.

def relation_list(nouns):

   relation_list = defaultdict(list)
   
   for noun in nouns:   
      relation = []
      for syn in wordnet.synsets(noun, pos = wordnet.NOUN):
         for l in syn.lemmas():
               relation.append(l.name())
               if l.antonyms():
                  relation.append(l.antonyms()[0].name())
         for l in syn.hyponyms():
               if l.hyponyms():
                  relation.append(l.hyponyms()[0].name().split('.')[0])
         for l in syn.hypernyms():
               if l.hypernyms():
                  relation.append(l.hypernyms()[0].name().split('.')[0])
      relation_list[noun].append(relation)
   return relation_list

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

  • текущее существительное уже есть в цепи

  • если Wu-Palmer похожесть между любым словом из цепи, которое входит в список связанных слов для рассматриваемого существительного, и самим существительным превышает 0.5

  • если Wu-Palmer похожесть между рассматриваемым существительным, которое входит в список связанных слов для слова из цепи, и самим словом из цепи превышает 0.5

Вот как это выглядит в коде

def create_lexical_chain(nouns, relation_list):
   lexical_chains = []
   threshold = 0.5
   for noun in nouns:
      flag = 0
      for chain in lexical_chains:
         if flag == 0:
               for key in list(chain):
                  if key == noun and flag == 0:
                     chain[noun] +=1
                     flag = 1
                  elif key in relation_list[noun][0] and flag == 0:
                     syns1 = wordnet.synsets(key, pos = wordnet.NOUN)
                     syns2 = wordnet.synsets(noun, pos = wordnet.NOUN)
                     if syns1[0].wup_similarity(syns2[0]) >= threshold:
                           chain[noun] = 1
                           flag = 1
                  elif noun in relation_list[key][0] and flag == 0:
                     syns1 = wordnet.synsets(key, pos = wordnet.NOUN)
                     syns2 = wordnet.synsets(noun, pos = wordnet.NOUN)
                     if syns1[0].wup_similarity(syns2[0]) >= threshold:
                           chain[noun] = 1
                           flag = 1
      if flag == 0: 
         dic_nuevo = {}
         dic_nuevo[noun] = 1
         lexical_chains.append(dic_nuevo)
         flag = 1
   return lexical_chains

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

def prune(lexical):
   final_chain = []
   while lexical:
      result = lexical.pop()
      if len(result.keys()) == 1:
         for value in result.values():
               if value != 1: 
                  final_chain.append(result)
      else:
         final_chain.append(result)
   return final_chain

Применение лексических цепей для задачи саммаризации

Как я сказал выше, репозиторий содержит код, демонстрирующий использование лексических цепей для задачи саммаризации. Сам алгоритм базируется на очень простой идее извлечения предложений, значимость который считается, как сумма частот отдельных слов. Однако, в вычислении частоты есть трюк - если слово входит в лексическую цепь, счетчик увеличивается на количество слов в этой цепи. У алгоритма есть гиперпараметры в виде верхней и нижней границ для частот. Все это организовано в небольшой класс(я удалил комментарии). Все, что нужно, это подать в метод summarize лист листов - предложений, разбитых на токены.

class Summarizer:
    
    def __init__(self, threshold_min=0.1, threshold_max=0.9):
        self.threshold_min = threshold_min
        self.threshold_max = threshold_max 
        self._stopwords = set(stopwords.words('english') + list(punctuation))
        
    def return_frequencies(self, sentences, lexical_chain):
        frequencies = defaultdict(int)
        for sentence in sentences:
            for w in sentence:
                if w not in self._stopwords:
                    flag = 0
                    for chain in lexical_chain:
                        if w in chain.keys():
                            frequencies[w] = sum(chain.values())
                            flag = 1
                            break
                    if flag == 0: 
                        frequencies[w] += 1
        m = float(max(frequencies.values()))
        for w in list(frequencies.keys()):
            frequencies[w] = frequencies[w]/m
            if frequencies[w] >= self.threshold_max or frequencies[w] <= self.threshold_min:
                del frequencies[w]
        return frequencies

    def summarize(self, sentence, lexical_chain, n):
        assert n <= len(sentence)
        splited_sentence = [word_tokenize(s.lower()) for s in sentence]
        self.frequencies = self.return_frequencies(word_sentence, lexical_chain)
        ranking = defaultdict(int)
        for i,sent in enumerate(splited_sentence):
            for word in sent:
                if word in self.frequencies:
                    ranking[i] += self.frequencies[word]
        idx = self.rank(ranking, n) 
        return [sentence[j] for j in idx]

    def rank(self, ranking, n):
        return nlargest(n, ranking, key=ranking.get)

Запуск

Если запустить скрипт на тексте, который есть в репе, то получится следующие результаты

Некоторые цепи
Chain 29 : {'south': 2}
Chain 30 : {'cannot': 2}
Chain 31 : {'period': 1, 'days': 1}
Chain 32 : {'efforts': 1, 'endeavor': 1, 'effort': 1}
Chain 33 : {'people': 2}
Chain 34 : {'control': 3}
Chain 35 : {'ventures': 1, 'commerce': 1, 'work': 1}
Chain 36 : {'united': 2}
Chain 37 : {'loyalty': 2}
Chain 38 : {'success': 2, 'failure': 1, 'deeds': 1}
Chain 39 : {'friend': 1, 'foe': 1, 'friends': 1}
Chain 40 : {'support': 2, 'reward': 1}
Chain 41 : {'nation': 2, 'nations': 1, 'country': 1}
Chain 42 : {'peace': 4}
Chain 43 : {'war': 4}
Chain 44 : {'americans': 4}
Chain 45 : {'generation': 3, 'generations': 1}
Chain 46 : {'time': 2}
Chain 47 : {'word': 2}
Chain 48 : {'revolution': 2}
Chain 49 : {'hand': 2}
Chain 50 : {'state': 1, 'place': 1, 'home': 1, 'states': 1, 'area': 1, 'places': 1}

Саммари
Let the word go forth from this time and place, to friend and foe alike, that the torch has been passed to a new generation of Americans--born in this century, tempered by war, disciplined by a hard and bitter peace, proud of our ancient heritage--and unwilling to witness or permit the slow undoing of those human rights to which this nation has always been committed, and to which we are committed today at home and around the world.
Let every nation know, whether it wishes us well or ill, that we shall pay any price, bear any burden, meet any hardship, support any friend, oppose any foe to assure the survival and the success of liberty.
And if a beachhead of cooperation may push back the jungle of suspicion, let both sides join in creating a new endeavor, not a new balance of power, but a new world of law, where the strong are just and the weak secure and the peace preserved.
Now the trumpet summons us again--not as a call to bear arms, though arms we need--not as a call to battle, though embattled we are-- but a call to bear the burden of a long twilight struggle, year in and year out, "rejoicing in hope, patient in tribulation"--a struggle against the common enemies of man: tyranny, poverty, disease and war itself.
With a good conscience our only sure reward, with history the final judge of our deeds, let us go forth to lead the land we love, asking His blessing and His help, but knowing that here on earth God's work must truly be our own.

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

Ссылки

  1. Lexical Cohesion Computed by Thesaural Relations as an Indicator of the Structure of Text

  2. Lexical cohesion

  3. Cohesion in Texts: A Discourse Analysis of a News Article in a Magazine

  4. Coherence relations in discourse and cognition. Comparing approaches, annotations, and interpretations

  5. Attention, Intentions, and the Structure of Discourse

Комментарии (0)