Это девятая статья в моей серии статей по Python для НЛП. В предыдущей статье мы видели , как библиотека шаблонов Python может использоваться для выполнения различных задач НЛП, начиная от токенизации и заканчивая POS-тегированием, а также классификацией текста и анализом настроений. До этого мы исследовали библиотеку TextBlob для выполнения аналогичных задач обработки естественного языка.
В этой статье мы рассмотрим библиотеку Stanford CoreNLP , которая является еще одной чрезвычайно удобной библиотекой для обработки естественного языка. Мы увидим различные особенности StanfordCoreNLP с помощью примеров. Поэтому, прежде чем тратить время впустую, давайте начнем.
Настройка среды
Процесс установки Stanford CoreNLP не так прост, как другие библиотеки Python. На самом деле Stanford CoreNLP-это библиотека, которая на самом деле написана на Java. Поэтому убедитесь, что в вашей системе установлена Java. Вы можете свободно скачать последнюю версию Java .
После установки Java вам необходимо загрузить JAR-файлы для библиотек Stanford CoreNLP. Файл JAR содержит модели, которые используются для выполнения различных задач НЛП. Чтобы загрузить JAR-файлы для английских моделей, загрузите и распакуйте папку, расположенную на официальном сайте Stanford CoreNLP .
Следующее, что вам нужно сделать, это запустить сервер, который будет обслуживать запросы, отправленные оболочкой Python в библиотеку Stanford CoreNLP. Перейдите к пути, по которому вы распаковали папку JAR files. Перейдите в папку и выполните следующую команду в командной строке:
$ java -mx6g -cp "*" edu.stanford.nlp.pipeline.StanfordCoreNLPServer -timeout 10000
Приведенная выше команда инициирует сервер Stanford CoreNLP. Параметр -mx6g
указывает, что объем используемой сервером памяти не должен превышать 6 гигабайт. Важно отметить, что вы должны работать под управлением 64-битной системы, чтобы иметь кучу размером до 6 ГБ. Если вы используете 32-разрядную систему, вам, возможно, придется уменьшить объем памяти, выделенной для сервера.
После выполнения приведенной выше команды вы должны увидеть следующие выходные данные:
[main] INFO CoreNLP - --- StanfordCoreNLPServer#main() called --- [main] INFO CoreNLP - setting default constituency parser [main] INFO CoreNLP - warning: cannot find edu/stanford/nlp/models/srparser/englishSR.ser.gz [main] INFO CoreNLP - using: edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz instead [main] INFO CoreNLP - to use shift reduce parser download English models jar from: [main] INFO CoreNLP - http://stanfordnlp.github.io/CoreNLP/download.html [main] INFO CoreNLP - Threads: 8 [main] INFO CoreNLP - Starting server... [main] INFO CoreNLP - StanfordCoreNLPServer listening at /0:0:0:0:0:0:0:0:9000
Сервер работает на порту 9000.
Теперь последний шаг – установить оболочку Python для библиотеки Stanford CoreNLP. Оболочка, которую мы будем использовать, – это pycorenlp
. Следующий сценарий загружает библиотеку-оболочку:
$ pip install pycorenlp
Теперь мы все готовы подключиться к серверу Stanford CoreNLP и выполнить необходимые задачи НЛП.
Чтобы подключиться к серверу, мы должны передать адрес сервера Stanford CoreNLP, который мы инициализировали ранее, классу StanfordCoreNLP
модуля pycorenlp
. Возвращенный объект затем можно использовать для выполнения задач НЛП. Посмотрите на следующий сценарий:
from pycorenlp import StanfordCoreNLP nlp_wrapper = StanfordCoreNLP('http://localhost:9000')
Выполнение задач НЛП
В этом разделе мы кратко рассмотрим использование библиотеки Stanford CoreNLP для выполнения общих задач НЛП.
Лемматизация, POS-маркировка и распознавание именованных сущностей
Лемматизация, маркировка частей речи и распознавание именованных сущностей-самые основные задачи НЛП. Библиотека Stanford CoreNLP поддерживает функциональность конвейера, которая может быть использована для выполнения этих задач структурированным образом.
В следующем сценарии мы создадим аннотатор, который сначала разбивает документ на предложения, а затем далее разбивает предложения на слова или токены. Затем слова аннотируются тегами распознавания POS и именованных сущностей.
doc = "Ronaldo has moved from Real Madrid to Juventus. While messi still plays for Barcelona" annot_doc = nlp_wrapper.annotate(doc, properties={ 'annotators': 'ner, pos', 'outputFormat': 'json', 'timeout': 1000, })
В приведенном выше сценарии у нас есть документ с двумя предложениями. Мы используем метод annotate
объекта-оболочки Stanford CoreNLP, который мы инициализировали ранее. Метод принимает три параметра. Параметр annotator
принимает тип аннотации, которую мы хотим выполнить над текстом. Мы передаем 'near, post'
в качестве значения параметра annotator
, который указывает, что мы хотим аннотировать ваш документ для POS-тегов и именованных сущностей.
Переменная output Format
определяет формат, в котором вы хотите получить аннотированный текст. Возможные значения: json
для объектов JSON, xml
для формата XML, text
для обычного текста и serialize
для сериализованных данных.
Последний параметр-это тайм-аут в миллисекундах, который определяет время, в течение которого оболочка должна ждать ответа от сервера перед тайм-аутом.
В выходных данных вы должны увидеть объект JSON следующим образом:
{'sentences': [{'index': 0, 'entitymentions': [{'docTokenBegin': 0, 'docTokenEnd': 1, 'tokenBegin': 0, 'tokenEnd': 1, 'text': 'Ronaldo', 'characterOffsetBegin': 0, 'characterOffsetEnd': 7, 'ner': 'PERSON'}, {'docTokenBegin': 4, 'docTokenEnd': 6, 'tokenBegin': 4, 'tokenEnd': 6, 'text': 'Real Madrid', 'characterOffsetBegin': 23, 'characterOffsetEnd': 34, 'ner': 'ORGANIZATION'}, {'docTokenBegin': 7, 'docTokenEnd': 8, 'tokenBegin': 7, 'tokenEnd': 8, 'text': 'Juventus', 'characterOffsetBegin': 38, 'characterOffsetEnd': 46, 'ner': 'ORGANIZATION'}], 'tokens': [{'index': 1, 'word': 'Ronaldo', 'originalText': 'Ronaldo', 'lemma': 'Ronaldo', 'characterOffsetBegin': 0, 'characterOffsetEnd': 7, 'pos': 'NNP', 'ner': 'PERSON', 'before': '', 'after': ' '}, {'index': 2, 'word': 'has', 'originalText': 'has', 'lemma': 'have', 'characterOffsetBegin': 8, 'characterOffsetEnd': 11, 'pos': 'VBZ', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 3, 'word': 'moved', 'originalText': 'moved', 'lemma': 'move', 'characterOffsetBegin': 12, 'characterOffsetEnd': 17, 'pos': 'VBN', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 4, 'word': 'from', 'originalText': 'from', 'lemma': 'from', 'characterOffsetBegin': 18, 'characterOffsetEnd': 22, 'pos': 'IN', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 5, 'word': 'Real', 'originalText': 'Real', 'lemma': 'real', 'characterOffsetBegin': 23, 'characterOffsetEnd': 27, 'pos': 'JJ', 'ner': 'ORGANIZATION', 'before': ' ', 'after': ' '}, {'index': 6, 'word': 'Madrid', 'originalText': 'Madrid', 'lemma': 'Madrid', 'characterOffsetBegin': 28, 'characterOffsetEnd': 34, 'pos': 'NNP', 'ner': 'ORGANIZATION', 'before': ' ', 'after': ' '}, {'index': 7, 'word': 'to', 'originalText': 'to', 'lemma': 'to', 'characterOffsetBegin': 35, 'characterOffsetEnd': 37, 'pos': 'TO', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 8, 'word': 'Juventus', 'originalText': 'Juventus', 'lemma': 'Juventus', 'characterOffsetBegin': 38, 'characterOffsetEnd': 46, 'pos': 'NNP', 'ner': 'ORGANIZATION', 'before': ' ', 'after': ''}, {'index': 9, 'word': '.', 'originalText': '.', 'lemma': '.', 'characterOffsetBegin': 46, 'characterOffsetEnd': 47, 'pos': '.', 'ner': 'O', 'before': '', 'after': ' '}]}, {'index': 1, 'entitymentions': [{'docTokenBegin': 14, 'docTokenEnd': 15, 'tokenBegin': 5, 'tokenEnd': 6, 'text': 'Barcelona', 'characterOffsetBegin': 76, 'characterOffsetEnd': 85, 'ner': 'ORGANIZATION'}], 'tokens': [{'index': 1, 'word': 'While', 'originalText': 'While', 'lemma': 'while', 'characterOffsetBegin': 48, 'characterOffsetEnd': 53, 'pos': 'IN', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 2, 'word': 'messi', 'originalText': 'messi', 'lemma': 'messus', 'characterOffsetBegin': 54, 'characterOffsetEnd': 59, 'pos': 'NNS', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 3, 'word': 'still', 'originalText': 'still', 'lemma': 'still', 'characterOffsetBegin': 60, 'characterOffsetEnd': 65, 'pos': 'RB', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 4, 'word': 'plays', 'originalText': 'plays', 'lemma': 'play', 'characterOffsetBegin': 66, 'characterOffsetEnd': 71, 'pos': 'VBZ', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 5, 'word': 'for', 'originalText': 'for', 'lemma': 'for', 'characterOffsetBegin': 72, 'characterOffsetEnd': 75, 'pos': 'IN', 'ner': 'O', 'before': ' ', 'after': ' '}, {'index': 6, 'word': 'Barcelona', 'originalText': 'Barcelona', 'lemma': 'Barcelona', 'characterOffsetBegin': 76, 'characterOffsetEnd': 85, 'pos': 'NNP', 'ner': 'ORGANIZATION', 'before': ' ', 'after': ''}]}]}
Если вы внимательно посмотрите на приведенный выше скрипт, то сможете найти теги СООБЩЕНИЙ, именованные сущности и лемматизированную версию каждого слова.
Лемматизация
Давайте теперь рассмотрим аннотированные результаты. Сначала мы напечатаем лемматизацию для слов в двух предложениях нашего набора данных:
for sentence in annot_doc["sentences"]: for word in sentence["tokens"]: print(word["word"] + " => " + word["lemma"])
В приведенном выше сценарии внешний цикл повторяет каждое предложение в документе, а внутренний цикл повторяет каждое слово в предложении. Внутри внутреннего цикла слово и соответствующая ему лемматизированная форма печатаются на консоли. Вывод выглядит следующим образом:
Ronaldo=>Ronaldo has=>have moved=>move from=>from Real=>real Madrid=>Madrid to=>to Juventus=>Juventus .=>. While=>while messi=>messus still=>still plays=>play for=>for Barcelona=>Barcelona
Например, вы можете видеть , что слово moved
было лемматизировано в move
, точно так же слово plays
было лемматизировано в play
.
POS-маркировка
Точно так же мы можем найти POS-теги для каждого слова. Посмотрите на следующий сценарий:
for sentence in annot_doc["sentences"]: for word in sentence["tokens"]: print (word["word"] + "=>" + word["pos"])
В выходных данных вы должны увидеть следующие результаты:
Ronaldo=>NNP has=>VBZ moved=>VBN from=>IN Real=>JJ Madrid=>NNP to=>TO Juventus=>NNP .=>. While=>IN messi=>NNS still=>RB plays=>VBZ for=>IN Barcelona=>NNP
Набор тегов, используемый для POS-тегов, является набором тегов Penn Treebank и может быть найден здесь .
Распознавание Именованных Сущностей
Чтобы найти именованные сущности в нашем документе, мы можем использовать следующий скрипт:
for sentence in annot_doc["sentences"]: for word in sentence["tokens"]: print (word["word"] + "=>" + word["ner"])
Вывод выглядит следующим образом:
Ronaldo=>PERSON has=>O moved=>O from=>O Real=>ORGANIZATION Madrid=>ORGANIZATION to=>O Juventus=>ORGANIZATION .=>O While=>O messi=>O still=>O plays=>O for=>O Barcelona=>ORGANIZATION
Мы видим , что Роналду
был идентифицирован как ЧЕЛОВЕК
в то время как Барселона
была идентифицирована как Организация
, что в данном случае правильно.
Анализ настроений
Чтобы найти смысл предложения, все, что вам нужно, – это передать sentiment
в качестве значения для свойства annotators
. Посмотрите на следующий сценарий:
doc = "I like this chocolate. This chocolate is not good. The chocolate is delicious. Its a very tasty chocolate. This is so bad" annot_doc = nlp_wrapper.annotate(doc, properties={ 'annotators': 'sentiment', 'outputFormat': 'json', 'timeout': 1000, })
Чтобы найти сентимент, мы можем перебирать каждое предложение, а затем использовать свойство sentiment Value
для поиска сентимента. Значение sentiment
возвращает значение от 1 до 4, где 1 соответствует очень негативному настроению, а 4-очень позитивному. Свойство sentiment
может быть использовано для получения sentiment в вербальной форме, то есть positive
, negative
или neutral
.
Следующий сценарий находит тональность для каждого предложения в документе, который мы определили выше.
for sentence in annot_doc["sentences"]: print ( " ".join([word["word"] for word in sentence["tokens"]]) + " => " \ + str(sentence["sentimentValue"]) + " = "+ sentence["sentiment"])
Выход:
I like this chocolate . => 2 = Neutral This chocolate is not good . => 1 = Negative The chocolate is delicious . => 3 = Positive Its a very tasty chocolate . => 3 = Positive This is so bad => 1 = Negative
Вывод
Stanford CoreNLP
– еще одна чрезвычайно удобная библиотека для обработки естественного языка. В этой статье мы изучили, как настроить среду для запуска StanfordCoreNLP. Затем мы изучили использование библиотеки StanfordCoreNLP для общих задач НЛП, таких как лемматизация, POS-тегирование и распознавание именованных сущностей, и, наконец, мы завершили статью сентиментальным анализом с использованием StanfordCoreNLP.