Press "Enter" to skip to content

Обработка естественно-языковых текстов в R: облако слов

Обработка естественно-языковых текстов (Natural language processing) – это одна из областей, в которых применяется R.

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

Материалом для работы у нас послужит выборка новостных сообщений о работе Псковского городского молодёжного центра, опубликованных в течение 2013 года в различных Интернет-СМИ. Поиск публикаций и сбор отобранных текстов произвела Екатерина Банщикова в рамках работы над своей дипломным проектом. Всего из более чем сотни новостных сообщений случайным образом было выбрано 20 текстов.

Текстовый корпус

Источники формирования корпуса

Первым шагом при обработке текстов является подготовка простого корпуса текстов. В библиотеке tm поддерживается несколько источников формирования корпуса. Например, на моём компьютере после установки этой библиотеки мне стали доступны функции по созданию корпуса из массива данных (DataFrameSource), из каталога файлов, каждый из которых содержит отдельный документ (DirSource), из вектора (VectorSource), из текстов, доступных по URI-ссылке (URISource) и из набора новостных сообщений агентства Reuters, входящих в состав расширения tm (ReutersSource). Помимо типов, которые входят в библиотеку tm, пользователь может оперативно установить расширения из CRAN, позволяющие импортировать тексты из веб-источников в форматах XML, JSON, HTML (tm.plugin.webmining), из почтовых файлов eml и mbox (tm.plugin.mail), из файлов французской программы текстового анализа Alceste (tm.plugin.alceste), из файлов, полученных от новостных агрегаторов Europresse (tm.plugin.europresse), LexisNexis (tm.plugin.lexisnexis), Dow Jones Factiva (tm.plugin.factiva).

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

Чтение источника

Документы могут храниться в источнике в разных форматах. Библиотека tm поддерживает чтение документов в форматах простого текста (readPlain), PDF (readPDF), Microsoft Word (readDOC), XML (readXML), табличной структуры (readTabular – для источников DataFrameSource и VectorSource) и несколько Reuters-форматов. Наш вариант – простой текст.

library(tm)
# Файлы хранятся в каталоге articles
dirpath <- "articles"
articles <- Corpus(DirSource(dirpath),
                   readerControl = list(reader = readPlain,
                                      language = "ru",
                                      load = T))

Предполётная обработка документов корпуса

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

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

Команда tm_map позволяет применить заданную функцию к каждому документу в корпусе.

# Текстовые файлы были сохранены в кодировке Windows. Конвертируем.
articles <- tm_map(articles, iconv, 'cp1251', 'UTF-8')
articles <- tm_map(articles, stripWhitespace)
articles <- tm_map(articles, tolower)
articles <- tm_map(articles, removeNumbers)
articles <- tm_map(articles, removeWords, stopwords("russian"))
articles <- tm_map(articles, removePunctuation)

Облако слов: первый заход

library(wordcloud)
wordcloud(articles, random.order=F, max.words=80, 
          colors=brewer.pal(6,"Oranges"))
Облако слов без стемматизации
Облако слов без стемматизации

Всё бы хорошо, но на графике встречаются одни и те же слова, но в разных формах. Например: молодёжном – молодёжного – молодёжный, году – года, участники – участников. Поскольку в случае с облаком слов нам не важно, в какой форме слово использовалось, а гораздо полезнее сам факт появления слова и его частота, то нам следует привести все слова к исходной форме.

Стемматизация текстов

Стемматизация по-русски, или плач о национальной свободе

Любую околонаучно-исследовательскую работу крайне желательно проводить с помощью таких компьютерных программ, чей исходный код открыт и доступен для проверки публикой. Иначе, если вы, например, производите расчёты в Excel или SPSS, выводы и воспроизводимость вашего исследования можно поставить под сомнение, т.к. алгоритмы, по которым эти расчёты производились, недоступны ни вам, ни сообществу, а только разработчику программы.

Подозреваю, что алгоритмы стемматизации, в частности, для русского языка – это вещь крайне наукоёмкая, требующая для её создания больших умственных трудозатрат. В России, где отношение к нарушению прав на интеллектуальную собственность достаточно лояльное, а уровень понимания того, что такое лицензионный договор, открытый исходный код и свободные лицензии, у нашего научного сообщества низкий. Поэтому неудивительно, что эффективной программы для стемминга русскоязычных текстов нет, а для создания, например, «Национального корпуса русского языка» с участием РАН использовалась программа с закрытым исходным кодом MyStem от Яндекса. Это при том, что на разработку корпуса выделялось несколько грантов из государственного бюджета. Выглядит это грустно-позорно. Благо, обнаружился Открытый корпус русского языка, все тексты и связанное с ним программное обеспечение распространяются под свободными лицензиями – сразу жить стало приятнее.

Что же есть доступного в R для стемминга русского языка? Библиотека SnowballC реализует стеммер Портера. Например, на наши экземпляры дублирующих слов выше мы получем следующее:

wordStem(c('молодёжный', "молодёжного", "молодёжном",
           "года", "году", "участники", "участников"), language='ru')

[1] "молодёжн" "молодёжн" "молодёжн" "год" "год" "участник" "участник"

Вроде бы ничего, но не каждый поймёт, что такое «молодёжн». Ещё один пример стеммера с открытым исходным кодом – это отечественная разработка Андрея Коваленко Stemka. Написан на C++, может быть использован в качестве библиотеки, так что энтузиасты могут сделать библиотеку для R. На аналогичную строку русских слов Stemka выдаст следующий результат:

молодёжн|ый
молодёжн|ог|о
молодёжн|ом|
год|а
год|у
участник|ам|
участник|и

Удалив в каждой строке вертикальную черту и символы справа от неё мы получим результат, аналогичный портеровскому. Кстати, слово «кровать» он превращает в «крова», как и Портер.

Существует открытый проект АОТ, согласно описаниям предлагающий «COM-объекты, которые можно скомпилировать под Visual Studio и использовать под Delphi». Судя по активности в их svn-репозитории, проект жив. Спасибо разработчикам, что помимо доступных COM-объектов, для компиляции которых нужно купить Visual Studio, Delphi и операционную систему Windows, они предоставили демо-версию своих продуктов онлайн. Мы можем воспользоваться примером морфологического анализа http://aot.ru/demo/morph.html. Данный анализатор успешно справляется и со словом «кровать», и «молодёжного» он превращает в «молодёжный». Для немассированной обработки текстов в R можно отправлять автоматические запросы через демо-версию и «вытаскивать» нужное слово из получаемых в ответ страниц с помощью XPath. Но здесь нужно подумать, насколько такие действия сочетаются с условиями использования демо-версии.

Исходя из вышесказанного, придётся грусто-позорно пользоваться программой с закрытым исходным кодом.

Стемматизация с помощью MyStem от Яндекса

Стеммер MyStem разработан в 1998 году сооснователем Яндекса Ильёй Сегаловичем. Программа доступна для различных операционных систем, исходный код закрыт. И хотя сам сайт Яндекса уверяет, что программа доступна только для некоммерческого использования, внимательно ознакомившись с лицензионным договором, в пункте 3.2 вы обнаружите, что «Программа может использоваться в коммерческих целях для разработки/создания каких-либо сервисов или программ, включаться и использоваться по прямому функциональному назначению в составе таких сервисов или программ, а также использоваться иным образом в процессе оказания услуг/выполнения работ». Исключения составляют те случаи, когда пользователь хочет с помощью MyStem заниматься спамом, раскруткой сайтов или создать свой поисковый движок. Спасибо Яндексу за это!

Правда, помимо закрытого кода у MyStem есть ещё одна ложка дёгтя: в пункте 3.11 соглашения читаем, что «при установке на персональный компьютер каждой копии Программы присваивается индивидуальный номер, который автоматически сообщается Правообладателю». Понятно, что Яндекс хочет знать, сколько копий его программы используется (ведь часть пользователей MyStem точно приносит экономический вред Яндексу, когда пользуются им для раскрутки сайтов), но всё равно неприятно.

Для использования mystem в R создадим одноименную функцию. Для работы требуется, чтобы операционная система знала, где лежит исполняемый файл mystem (в Windows, видимо, mystem.exe).

mystem <- function(doc) {
  library(stringr)
  sdoc <- system('mystem -nl -e utf-8 ', intern=T, input=doc)
  # При получении нескольких вариантов mystem разделяет их
  # вертикальной чертой. Удалим черту и варианты.
  sdoc <- str_replace(sdoc, '\\|.*$', '')
  # Если mystem сомневается в результате, он добавляет знак вопроса. Удаляем.
  sdoc <- str_replace(sdoc, '\\?', '')
  sdoc <- paste(sdoc, collapse=" ")
  attributes(sdoc) <- attributes(doc)
  sdoc
}

Теперь мы обладаем инструментом для стемминга и можем возвращаться в облака.

Финальный аккорд

Дообработка текстов корпуса

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

articles <- tm_map(articles, iconv, 'cp1251', 'UTF-8')
articles <- tm_map(articles, stripWhitespace)
articles <- tm_map(articles, tolower)
articles <- tm_map(articles, removeNumbers)
articles <- tm_map(articles, removePunctuation)
articles <- tm_map(articles, mystem)
articles <- tm_map(articles, removeWords, c(stopwords("russian"),
                                            "это", "также",
                                            "быть", "мочь",
                                            "май", "апрель", "март",
                                            "ноябрь", "который",
                                            "псковский", "молодежный",
                                            "псков", "центр", 
                                            "городской"))

Рисуем облако слов

wordcloud(articles, random.order=F, max.words=80, 
          colors=brewer.pal(6,"Oranges"))
Облако слов после стемматизации. Слова с низкой частотой еле видны
Облако слов после стемматизации. Слова с низкой частотой еле видны

Теперь все существительные представлены в именительном падеже, глаголы – в инфинитиве. Но слова с низкой частотой, которые рисуются самым маленьким размером шрифта и с наименьшей интенсивностью цвета, практически не читаются. Что случилось, ведь мы не меняли никаких характеристик графика, кроме самих слов и их частот?

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

Как правильно использовать цвета в статистике или немного грамматики графики

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

Облако слов без использования цвета. Все слова хорошо читаются
Облако слов без использования цвета. Все слова хорошо читаются

В таком случае все слова хорошо читаются. А если заказчик всё-таки хочет цветную картинку? Надо подумать…

А на сегодня давайте сделаем последнюю доработку: уберём из графика несодержательные в случае с молодёжным центром слова:

articles <- tm_map(articles, removeWords, c(stopwords("russian"),
                                            "это", "также",
                                            "быть", "мочь", "октябрь",
                                            "май", "апрель", "март",
                                            "ноябрь", "который",
                                            "псковский", "молодежный",
                                            "псков", "центр", 
                                            "городской"))
wordcloud(articles, random.order=F, max.words=80)
Облако слов из новостей о Псковском городском молодёжном центре
Облако слов из новостей о Псковском городском молодёжном центре

65 Comments

  1. Сергей
    Сергей 2014-07-31

    Добрый день, Александр!
    Не могу построить облако слов используя Ваш пример. Не могли бы Вы помочь разобраться в этом примере.
    Опишу подробнее и пошагово:
    1. Устанавливаю библиотеки
    library(tm)
    library(wordcloud)
    2. На диске есть папка oblako в ней один файл 1.txt в нем примерно 20 слов (какие-то повторяются часто, какие-то один раз)
    3. Делаю как в Вашем примере
    dirpath <- "oblako"
    oblako <- Corpus(DirSource(dirpath),
    readerControl = list(reader = readPlain,
    language = "ru",
    load = T))
    R выдает сообщение (не понимаю какую финальную строку он имеет ввиду)
    Warning message:
    In readLines(y, encoding = x$Encoding) :
    incomplete final line found on 'oblako/1.txt'
    4. Строю само облако
    wordcloud(oblako, random.order=F, max.words=80,
    colors=brewer.pal(6,"Oranges")

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

    Буду благодарен если Вы найдете время мне в этом разобраться. Спасибо!

    • Александр Матрунич
      Александр Матрунич 2014-08-03

      Сергей, добрый день!

      Это, думаю, с кодировкой исходного файла проблема. В Windows работаете?

      Здесь проблема не в wordcloud, а в readLines, которая вызывается для чтения содержимого файлов, когда вы вызываете функцию Corpus. readLines прочитывает ваш файл строчку за строчкой, а потом натыкается в определённом слове на какой-то символ, который функцией интерпретируется как “incomplete final line”. Поскольку строка, с точки зрения функции, последняя, то дальше файл не читается. И в текстовом корпусе oblako хранятся только те слова, которые находятся в исходном файле не ниже виновной строки.

      Попробуйте, например, в этом текстовом файле следующую строку соединить с “виновной” строкой, чтобы удалить этот проблемный символ (он, скорее всего, не печатается, а служебный), а потом разбить строку Enter’ом заново.

  2. Сергей
    Сергей 2014-08-04

    Здравствуйте, Александр! Спасибо за ответ!

    Работаю в windows 7. Поэкспериментирую с “виновной” строкой. Однако при работе с большим объемом эксперименты будут очень трудоемкими. Может мне поможет конвертация текста в другой формат или кодировку так, что бы остаться на windows. Или решение такой задачи в winwows часто будет глючить.

    • Александр Матрунич
      Александр Матрунич 2014-08-07

      Сергей, под виндой тоже должно работать. Скорее всего ещё что-нибудь со знаком переноса строки (в Windows одно, в других ОС – другое). Можно попробовать сохранить с помощью Notepad++, эта программа позволяет менять кодировки и знак переноса строк. Хотя удивительно, что именно из-за одной строки.

      Ещё вариант – это посмотреть опции Corpus() или DirSource(), возможно, там есть опции для задания кодировки.

      Ещё вариант – это вместо чтения из текстовых файлов использовать другой способ загрузки корпуса (напр., XMLSource). Тем более, если объёмы у вас большие и “скакать” по файлам в поисках запрещённых символов непродуктивно.

  3. Александр Матрунич
    Александр Матрунич 2014-08-07

    Вообще под Windows в R вечно выскакивают проблемы с кириллицей. То там, то тут нужны какие-то дополнительные опции, потому что в винде не UTF (это я про 7 и ниже, в 8 не пробовал). Всё-таки если R использовать на регулярной основе и для “production”, то я б рекомендовал GNU/Linux. Если не хочется целиком уходить с MS, то можно в виртуальной машине развернуть линукс, там поставить RStudio server и работать в RStudio через браузер из винды.

  4. Сергей
    Сергей 2014-08-19

    Спасибо, Александр!
    Попробую предложенные варианты.

  5. Сергей
    Сергей 2014-09-01

    Добрый день, Александр!
    Хотелось бы еще получить вашу консультацию.
    Поставил ubuntu 14.04 поставил R и R studio, загружаю пакеты необходимые для построения облака слов

    install.packages(“tm”, dependencies=T)
    он ругается

    > install.packages(“tm”)
    Installing package into ‘/home/serg/R/i686-pc-linux-gnu-library/3.0’
    (as ‘lib’ is unspecified)
    Warning in install.packages :
    package ‘tm’ is not available (for R version 3.0.2)
    я так понял не хочет ставить на версию 3.0.2 но это вроде бы последняя версия, по карайней мере при попытке установить заново R он говорит установлена последняя версия.
    И в винде установлена версия 3.0.2, пакет tm устанавливается (хотя и предупреждает, что пакет был собран под версию 3.0.3).

    Не могу понять как поставить 3.0.3 или поставить tm на версию 3.0.2
    Заранее спасибо!

  6. Александр Матрунич
    Александр Матрунич 2014-09-03

    Сергей, попробуйте установить пакет средствами убунты через apt-get:

    apt-get install r-cran-tm

    Думаю, что дело в том, что убунта вышла в апреле, и в её “наборе” R версии 3.0, а летом вышел R версии 3.1. Но в убунте она не обновится до тех пор, пока дистрибутив целиком не обновится (14.10). Когда вы средствами R обновляете пакеты (update.packages / install.packages), то R скачивает самые последние версии, расчитанные на самое свежее ядро R.

    А когда вы пользуетесь apt-get, то убунта сама скачивает из своих репозиториев версию пакета, актуальную именно для неё. Т.е. убунтовцы сами отдельно поддерживают кучу R-пакетов.

    Да, интересно, в федоре версия R последняя, т.е. у них другая политика по отношению к R.

    http://stackoverflow.com/questions/2170043/r-apt-get-install-r-cran-foo-vs-install-packagesfoo

  7. Сергей
    Сергей 2014-11-27

    Добрый день, Александр!
    С пакетами разобрался, простейшее облако строить получается.

    Если есть время помогите разобраться в стемматизации.
    Не получается выполнить стемматизацию функцией mystem.

    Есть два файла txt, загружаю их

    dirpath <- "oblako"
    oblako <- Corpus(DirSource(dirpath),
    readerControl = list(reader = readPlain,
    language = "ru",
    load = T))

    Далее

    mystem <- function(doc) {
    library(stringr)
    sdoc <- system('mystem -nl -e utf-8 ', intern=T, input=doc)
    # При получении нескольких вариантов mystem разделяет их
    # вертикальной чертой. Удалим черту и варианты.
    sdoc <- str_replace(sdoc, '\\|.*$', '')
    # Если mystem сомневается в результате, он добавляет знак вопроса. Удаляем.
    sdoc <- str_replace(sdoc, '\\?', '')
    sdoc <- paste(sdoc, collapse=" ")
    attributes(sdoc) <- attributes(doc)
    sdoc
    }

    Затем

    oblako <- tm_map(oblako, stripWhitespace)

    oblako <- tm_map(oblako, removeNumbers)
    oblako <- tm_map(oblako, removeWords, c(stopwords("russian"),"это", "наши"))
    oblako <- tm_map(oblako, removePunctuation)
    oblako <- tm_map(oblako, mystem)

    он выдает ошибку
    oblako <- tm_map(oblako, mystem)
    sh: 1: mystem: not found
    sh: 1: mystem: not found
    Предупреждение
    In mclapply(content(x), FUN, …) :
    all scheduled cores encountered errors in user code

    еще не понимаю строчку
    oblako wordcloud(oblako, random.order=F, max.words=80, min.freq=2, colors=”Blue”)
    Ошибка в UseMethod(“meta”, x) :
    нет подходящего метода для ‘meta’ применяемого к объекту класса “character”
    Вдобавок: Предупреждение
    In mclapply(unname(content(x)), termFreq, control) :
    all scheduled cores encountered errors in user code

    • Александр Матрунич
      Александр Матрунич 2014-12-03

      он выдает ошибку
      oblako <- tm_map(oblako, mystem) sh: 1: mystem: not found sh: 1: mystem: not found

      В операцоинной системе должна быть установлена программа mystem. В данном случае R передаёт управление операционной системе, чтобы та выполнила команду ‘mystem -nl -e utf-8 ‘. ОС пытается это сделать и не находит программу mystem.

      oblako wordcloud(oblako, random.order=F, max.words=80, min.freq=2, colors=”Blue”)

      Это я тоже не понимаю 🙂 Видимо, вы хотели запустить так:

      wordcloud(oblako, random.order=F, max.words=80, min.freq=2, colors=”Blue”)

  8. Матвей
    Матвей 2015-04-26

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

  9. Александр Матрунич
    Александр Матрунич 2015-04-27

    Матвей, вы работаете в Windows? Можете показать образец проблемного кода?

  10. Матвей
    Матвей 2015-05-01

    Работаю в Windows
    Код облака:
    wordcloud(vector, max.words = 100, random.order = F, scale = c(4, 1))

    Результат получается следующий:
    Латиница
    http://prntscr.com/707llc
    Кириллица
    http://prntscr.com/707k73

    Т.е. с кириллицей получается большой разброс между словами.

  11. Александр Матрунич
    Александр Матрунич 2015-05-05

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

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

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

    У text() есть параметр font, попробуйте задать здесь какой-нибудь системный шрифт Windows (Arial?).

    И такой же параметр попробуйте прямо в wordcloud()

  12. Матвей
    Матвей 2015-05-06

    Сама функция text() вроде выводит все верно. Код ниже располагает 4 строчки близко друг к другу (как понимаю, в основе параметра pos в т.ч. длина текста).

    plot(c(0, 1), c(0, 1), ann = F, bty = ‘n’, type = ‘n’, xaxt = ‘n’, yaxt = ‘n’)
    text(x = 0.5, y = 0.5,pos =1, enc2native(“ТЕКСТ ТЕКСТТЕКСТТЕКСТ ТЕКСТ”))
    text(x = 0.5, y = 0.5,pos =2, enc2native(“ТЕКСТ ТЕКСТТЕКСТТЕКСТ ТЕКСТ”))
    text(x = 0.5, y = 0.5,pos =3, enc2native(“ТЕКСТ ТЕКСТТЕКСТТЕКСТ ТЕКСТ”))
    text(x = 0.5, y = 0.5,pos =4, enc2native(“ТЕКСТ ТЕКСТТЕКСТТЕКСТ ТЕКСТ”))

    Возможно ли как-то увидеть код wordcloud (если он на R)?

  13. Александр Матрунич
    Александр Матрунич 2015-05-07

    Да, просто вводите название функции без скобок:
    > wordcloud

    А шрифт пробовали изменять?

    90%, что это специфика Windows. Надо какие-нибудь доп.параметры указывать для кириллических шрифтов.

  14. YesThisIsDog
    YesThisIsDog 2015-05-27

    Спасибо за отличную статью! Столкнулся с проблемой (Debian). Вылетает такая ошибка:

    Error in system("./mystem -n -e utf-8 ", intern = T, input = str) :
    'input' must be a character vector or 'NULL'

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

    str <- paste(doc, collapse=" ")

    повыше (до system), но теперь такое :

    Error in x$meta[[tag]] : subscript out of bounds
    Calls: wordcloud ... setNames -> lapply -> FUN -> meta.PlainTextDocument
    Execution halted

    Код такой:

    #!/usr/bin/env Rscript

    library("tm")
    library("wordcloud")
    library("RColorBrewer")

    mystem <- function(doc) {
    library("stringr")
    sdoc <- paste(doc, collapse=" ")
    sdoc <- system('./mystem -n -e utf-8 ', intern=T, input=sdoc)
    sdoc <- str_replace(sdoc, '\\|.*$', '')
    sdoc <- str_replace(sdoc, '\\?', '')

    attributes(sdoc) <- attributes(doc)
    sdoc
    }

    docs <- Corpus(DirSource("./ar"),
    readerControl = list(reader = readPlain,
    language="ru",
    load=T))

    docs <- tm_map(docs, content_transformer(tolower), lazy=TRUE)
    docs <- tm_map(docs, stripWhitespace, lazy=TRUE)
    docs <- tm_map(docs, removeNumbers, lazy=TRUE)
    docs <- tm_map(docs, removePunctuation, lazy=TRUE)
    docs <- tm_map(docs, mystem, lazy=TRUE)
    docs <- tm_map(docs, removeWords, stopwords("russian"), lazy=TRUE)
    docs <- tm_map(docs, removeWords, c("это", "который", "также", "быть"), lazy=TRUE)

    png("wordcloud.png", width=800, height=600)
    set.seed(1234)
    wordcloud(docs, random.order=F, max.words=200, colors=brewer.pal(7, "Oranges"))

  15. Евгений
    Евгений 2016-04-07

    При вызове функции
    Articles <- Corpus(DirSource(cname),
    readerControl = list(reader = readDOC,
    language = "ru",
    load = T))

    Возникает ошибка
    Error in system2("antiword", c(AntiwordOptions, shQuote(normalizePath(uri))), :
    '"antiword"' not found

    с чем это может быть свзяано?

    • Александр Матрунич
      Александр Матрунич 2016-04-08

      ‘”antiword”‘ not found

      Программа antiword не установлена или до неё не указан путь.

      • Евгений
        Евгений 2016-04-08

        Александр, не совсем понимаю, что это за программа и где её взять.
        У меня Windows и для него есть вот такой архив: http://www-stud.rbi.informatik.uni-frankfurt.de/~markus/antiword/
        Но его распаковка не даёт мне понимая, что делать дальше. Чувствую себя, чайником. Но правда не понимаю, как её установить и как считывать Word DOC документы в R

        • Александр Матрунич
          Александр Матрунич 2016-04-08

          Евгений!

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

          Когда вы даёте команду system2(“antiword”, …), R передаёт в операционную систему запрос выполнить команду antiword и передать этой команде последующие параметры. Винда этой программы не находит и возвращает ошибку. Пропишите полный путь к антиворду:

          system2(
            command = file.path("c:",
                                "путь",
                                "к", 
                                "папке", 
                                "antiword"),
            args = c(AntiwordOptions, shQuote(normalizePath(uri))))
          • Евгений
            Евгений 2016-04-08

            Спасибо!
            Но не сработало 🙂
            Error in paste(c(shQuote(command), env, args), collapse = ” “) :
            object ‘AntiwordOptions’ not found

            Как я понимаю в скаченной мной папке нету данных файлов.

            Задача обработать сотню файлов. Переводить вручную – долго и бессмысленно.
            Пытаюсь понять как через R переводить их в текстовый формат.
            Из английских источников понял, что есть два путь 1) Antiword 2) docx2txt
            Но с обоими пока не удаётся разобраться

  16. Александр Матрунич
    Александр Матрунич 2016-04-08

    Евгений, вы неправильно поняли 🙂

    object ‘AntiwordOptions’ not found

    Вы ж запускаете команду system2() и в одном из аргументов даёте инструкцию использовать объект AntiwordOptions, который у вас, видимо, не создан.

    Так что сначала подтяните матчасть по R, а затем уже за antiword беритесь. Так быстрее разберётесь.

    Кстати, конвертировать ворд в текст из командной строки и LibreOffice умеет.

  17. Maria
    Maria 2017-11-08

    Александр, добрый день!
    Спасибо за полезную статью. У меня следующая проблема: после перекодировки текстовых файлов в UTF-8 ( articles <- tm_map(articles, iconv, 'cp1251', 'UTF-8') в облаке вместо русских слов отражается какая-то абракадабра. Как Вы думаете, с чем это может быть связано?

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Мария, здравствуйте!

      Попробуйте без перекодировки совсем.

      Если не помогло, покажите вывод команды sessionInfo()

      Вы работаете в RStudio под Windows?

  18. Maria
    Maria 2017-11-09

    Александр, спасибо! Без перекодировки тоже не получается. Результат sessionInfo()
    > sessionInfo()
    R version 3.4.2 (2017-09-28)
    Platform: x86_64-w64-mingw32/x64 (64-bit)
    Running under: Windows 7 x64 (build 7601) Service Pack 1

    Matrix products: default

    locale:
    [1] LC_COLLATE=Russian_Russia.1251 LC_CTYPE=Russian_Russia.1251
    [3] LC_MONETARY=Russian_Russia.1251 LC_NUMERIC=C
    [5] LC_TIME=Russian_Russia.1251

    attached base packages:
    [1] stats graphics grDevices utils datasets methods base

    other attached packages:
    [1] readr_1.1.1 wordcloud_2.5 RColorBrewer_1.1-2
    [4] SentimentAnalysis_1.2-0 sentimentr_2.0.1 lexicon_0.5.0
    [7] readxl_1.0.0 tm_0.7-1 NLP_0.1-11
    [10] syuzhet_1.0.1

    loaded via a namespace (and not attached):
    [1] Rcpp_0.12.13 hms_0.3 devtools_1.13.3 textclean_0.3.1
    [5] R6_2.2.2 rlang_0.1.2 httr_1.3.1 tools_3.4.2
    [9] parallel_3.4.2 data.table_1.10.4-3 pacman_0.4.6 openNLP_0.2-6
    [13] git2r_0.19.0 withr_2.1.0 digest_0.6.12 textshape_1.5.0
    [17] tibble_1.3.4 rJava_0.9-9 openNLPdata_1.5.3-3 curl_3.0
    [21] memoise_1.1.0 slam_0.1-40 stringi_1.1.5 compiler_3.4.2
    [25] cellranger_1.1.0

    Работаю в Rstudio под Windows.

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Это, видимо, классические проблемы с кодировками под Windows.

      Нужно проверить, в какой кодировке сохранены ваши исходные файлы. Это у вас обычные текстовые файлы? Стандартным Блокнотом они нормально просматриваются?

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Попробуйте

      content(articles[[1]])
      dtm <- DocumentTermMatrix(articles) Terms(dtm)

      Взято отсюда.

      Нормальная кодировка?

  19. Maria
    Maria 2017-11-09

    Александр, это обычные текстовые файлы в кодировке Windows cp1251. Попробовала команды, вот что получается:
    > content(articles[[1]])
    [1] “ЦБ допустил возможность санации новых крупных банков с использованием средств Фонда консолидации банковского сектора. Главной целью регулятор считает недопущение дестабилизации «на макроуровне»\nЦентробанк допускает возможность санации крупных банков помимо «ФК Открытие» и Бинбанка. Об этом журналистам заявил первый зампред ЦБ Дмитрий Тулин, передает «Интерфакс».\n\nЦБ «не исключает возможности дальнейшего применения нового механизма оздоровления, он создавался как системное решение для будущих проблем, признаки которых могут быть сейчас, а могут обнаружиться позднее», ответил первый зампред Банка России на вопрос, есть ли еще крупные банки, которые будут санированы.\n\nТулин отметил, что главная задача ЦБ заключается в недопущении макроэкономической нестабильности. Выбор между отзывом лицензии и санацией он назвал выбором «между двумя плохими решениями», поскольку неплатежеспособность банка «всегда означает убытки для общества». Для банков («ФК Открытие» и Бинбанка) «самое худшее…
    dtm<-DocumentTermMatrix(articles)
    Terms(dtm)
    [1] "РІР" "РІРЅР" "РІРЅРѕР№"
    [4] "РІРѕР" "РІРѕРј" "РІРѕРїСЂРѕСЃ"
    [7] "РІС" "РІСЃР" "РіР"
    [10] "РіРґР" "РіРѕ" "РіСѓР"
    [13] "РґР" "РґРІСѓРјСЏ" "РґРјРёС"
    [16] "РґРЅР" "РґРѕРїСѓС" "РґРѕРїСѓСЃРєР"
    [19] "РґРѕРїСѓСЃС" "РґРѕСЂРѕРІР" "РґСЃС"
    [22] "РґСѓ" "РёР" "РёРґР"
    [25] "РёРё" "РёРјРё" "РёРЅ"
    [28] "РёРЅР" "РёРЅС" "РёС"
    [31] "РёСЃРєР" "РёСЃРїРѕР" "РёСЃС"
    [34] "Р№С" "Р№С€Р" "РєР"
    [37] "РєРё" "РєРѕРЅСЃРѕР" "РєРѕС"
    [40] "РєС" "РєСЂРѕСѓСЂРѕРІРЅР" "РєСЂРѕСЌРєРѕРЅРѕРјРёС"
    [43] "РєСЂС" "РєСЂСѓРїРЅС" "РєСЃВ"
    [46] "РјР" "РјРЅРѕР" "РјРѕР"
    [49] "РјРѕРіСѓС" "РјРїСЂР" "РЅР"
    [52] "РЅРёР" "РЅРёРё" "РЅРёСЂРѕРІР"
    [55] "РЅРёСЏ" "РЅРёСЏРјРёВ" "РЅРє"
    [58] "РЅРєР" "РЅРєРё" "РЅРєРѕРІ"
    [61] "РЅРєРѕРІСЃРєРѕРіРѕ" "РЅРѕРІРѕРіРѕ" "РЅРѕРІС"
    [64] "РЅРѕСЃС" "РЅС" "РѕР"
    [67] "РѕРІР" "РѕРј" "РѕРЅ"
    [70] "РѕРЅРґР" "РѕС" "РѕСЂ"
    [73] "РѕСЂР" "РѕСЂРѕРј" "РѕСЂС"
    [76] "РѕСЃСЊВ" "РїР" "РїРѕР"
    [79] "РїРѕРјРёРјРѕ" "РїРѕСЃРєРѕР" "РїСЂРёР"
    [82] "РїСЂРёРјР" "РїСЂРѕР" "СЂР"
    [85] "СЂРІС" "СЂРёР№" "СЂРѕР"
    [88] "СЂРѕСЃСЃРёРё" "СЂС" "СЂСѓР"
    [91] "СЃР" "СЃРёСЃС" "СЃРєРѕР№"
    [94] "СЃРѕР" "СЃРїРѕСЃРѕР" "СЃС"
    [97] "СЃСЂР" "СЃСЏ" "СѓР"
    [100] "СѓРґСѓС" "СѓРґС€Р" "СѓРєР"
    [103] "СѓС" "СѓСЂРЅР" "С€Р"
    [106] "СЊВ" "СЊР" "СЊРєСѓ"
    [109] "СЊРЅР" "СЊРЅРѕСЃС" "СЊСЃСЏ"
    [112] "СЊСЋ" "СЌС" "СЋС"
    [115] "СЏРІРёР" "СЏС" "1390"
    [118] "appleby" "bank" "gulfstream"
    [121] "new" "nyt" "the"
    [124] "times" "utah" "york"
    [127] "РІРѕСЃС" "вшиС" "РіРёСЃС"
    [130] "РґРѕРІР" "РґРѕРєСѓРјР" "РґСЂСѓРіРёР"
    [133] "РґСЃР" "РґСѓР" "РёРјР"
    [136] "РёРЅРѕСЃС" "РёРѕРЅРЅС" "РёСЂРјС"
    [139] "РёСЃР" "РёСЏРјРё" "Р№СЃРєРёС"
    [142] "РєРёРј" "РєРёС" "РєРѕР№"
    [145] "РєРѕРјРїР" "РјРё" "РјРёС"
    [148] "РјРѕРіРѕ" "РЅРё" "РЅРёР№"
    [151] "РЅРёРјР" "РЅРєС" "РЅРЅРѕРіРѕ"
    [154] "РЅРЅРѕРј" "РЅРѕРІР" "РЅСЃРєРёР"
    [157] "РЅСЃРєРѕР№" "РѕРІ" "РѕРіР"
    [160] "РѕРіРѕ" "РѕРґРёС" "РѕРґРЅРѕ"
    [163] "РѕРєР" "РѕРЅРёРґ" "РѕСЂРѕР"
    [166] "РѕСЏС" "РїРёСЃСЏС" "РїРёС€Р"
    [169] "РїРѕ" "РїРѕРґ" "РїРѕРєР"
    [172] "РїРѕРјРёРЅР" "РїРѕРїР" "РїРѕСЏРІР"
    [175] "РїСЂР" "СЂРёРєР" "СЂРёРєРё"
    [178] "СЂРёС" "СЂРёСЂРѕРІР" "СЂРѕСЃСЃРёСЏРЅРёРЅР"
    [181] "СЃРІРѕР" "СЃРјРё" "СЃРѕ"
    [184] "СЃРѕРІР" "СЃРїР" "СЃСЃР"
    [187] "СЃСЃС" "СЃС€Р" "СѓРіР"
    [190] "СѓРїСЂР" "СѓСЃР" "СѓСЋС"
    [193] "шорР" "СЊРЅС" "СЊС"
    [196] "СЊСЃРѕРЅ" "СЌРє" "СЋСЂРёРґРёС"
    [199] "СЏР" "СЏРІР" "СЏСЋС"
    Получается, что любой текст, который я перекодирую в UTF-8 (или RStudio, который делает это автоматически) не отображает русские символы. Как Вы думаете,может, можно поправить настройки WIndows?

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Я не уточнил, эти команды вы выполняли после iconv или без него?

      Попробуйте второй вариант.

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

  20. Maria
    Maria 2017-11-09

    Александр,спасибо за Ваши ответы! Я все делаю без конвертации, но буквы все равно не отображаются корректно, к сожалению… Ума не приложу, что еще можно сделать.

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      А если:

      articles <- Corpus(DirSource(dirpath, encoding = "cp1251"), readerControl = list(reader = readPlain, language = "ru", load = T)) content(articles[[1]]) Terms(DocumentTermMatrix(articles))

      • Александр Матрунич
        Александр Матрунич 2017-11-09

        И давайте проверим ваши кодировки:


        c("cp1251", "windows-1251", "CP1251", "WINDOWS-1251") %in% iconvlist()

        Попробуйте в encoding те значения, которые в этой команде дали TRUE.

  21. Maria
    Maria 2017-11-09

    Александр, не работает.

    По кодировкам:
    c(“cp1251”, “windows-1251”, “CP1251”, “WINDOWS-1251”) %in% iconvlist()
    [1] FALSE TRUE TRUE FALSE

    Пробовала в encoding подставить 2 и 3 вариант – результат тот же самый.

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Тот же самый результат в том смысле, что content() даёт нормальный текст, а Terms() нет? Правильно?

      Есть вариант, что функции tm некорректно выводят текст на экран. Попробуйте сразу запустить wordcloud(articles).

  22. Maria
    Maria 2017-11-09

    Да, content() даёт нормальный текст, а Terms() – абракадабру. Wordcloud же все равно требует загрузки пакета tm, также как и corpus?

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Да, загрузите корпус как обычно, но с опцией encoding = “CP1251”, а потом сразу wordcloud(articles).

      И ещё попробуйте plot(Terms(DocumentTermMatrix(articles)))

  23. Maria
    Maria 2017-11-09

    Александр, извините за назойливость. Но и это не работает. plot(Terms(DocumentTermMatrix(articles))) – рисует пустую координатную сетку. У вас в примере такой проблемы вообще не было? Какая у Вас версия Rsudio?

  24. Maria
    Maria 2017-11-09

    Ваши тексты были сохранены в блокноте? В какой кодировке?

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      У меня Linux, поэтому никаких проблем с кодировками нет. И, опять же, версия RStudio тут вряд ли влияет (у меня не старше месяца версия).

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

      А plot() ничего не рисует скорее всего из-за шрифтов. Т.е. это другая проблема.

      Покажите, пжл, str(articles[[1]])

      И проверьте, рисуется ли здесь русский текст:

      wordcloud(“Привет”)

  25. Maria
    Maria 2017-11-09

    Вот, что получилось:
    str(articles[[1]])
    List of 2
    $ content: chr “ЦБ допустил возможность санации новых крупных банков с использованием средств Фонда консолидации банковского се”| __truncated__
    $ meta :List of 7
    ..$ author : chr(0)
    ..$ datetimestamp: POSIXlt[1:1], format: “2017-11-09 11:58:36”
    ..$ description : chr(0)
    ..$ heading : chr(0)
    ..$ id : chr “1.txt”
    ..$ language : chr “russian”
    ..$ origin : chr(0)
    ..- attr(*, “class”)= chr “TextDocumentMeta”
    – attr(*, “class”)= chr [1:2] “PlainTextDocument” “TextDocument”

    Когда запускаю wordcloud(“Привет”), команда, вроде бы, выполняется. Но рисунка не появляется.

    • Александр Матрунич
      Александр Матрунич 2017-11-09

      Хорошо. Исходя из результатов str() мы видим, что внутри корпуса текст хранится в нормальном виде. И wordcloud() показывает, что он умеет работать с русским текстом под Windows.

      Теперь давайте проверим, на всех ли этапах обработки tm сохраняет кодировку:

      articles <- tm_map(articles, stripWhitespace)
      articles <- tm_map(articles, tolower)
      articles <- tm_map(articles, removeNumbers)
      articles <- tm_map(articles, removeWords, stopwords("russian"))
      articles <- tm_map(articles, removePunctuation)
      str(articles[[1]]$content)
      
      
      			
  26. Maria
    Maria 2017-11-09

    Только увидела: есть рисунок, отображает все корректно.

  27. Maria
    Maria 2017-11-10

    Александр, добрый день! Проверила, вот, что получилось:
    articles articles articles articles articles str(articles[[1]]$content)
    chr “принцмиллиардер альвалид потерял млрд ареста состояние саудовского принца альвалида ибн талала сократилось “| __truncated__

    • Александр Матрунич
      Александр Матрунич 2017-11-10

      ОК, всё как ожидалось.

      Смотрю исходный код wordcloud (можно посмотреть выполнив wordcloud без скобок). Там есть строка tdm <- TermDocumentMatrix(corpus) Т.е. в этом месте опять вызывается tm::TermDocumentMatrix, который из-за кодировок портит текст. Варианты вижу такие:

      1. Поменять локаль сессии R перед началом работы на UTF-8. Загрузить корпус и перекодировать из 1251 в UTF. Возможно, что tm заработает в такой ситуации.
      2. wordcloud может работать без пакета tm, если ему вместе с перечнем слов предоставить их частоту. Для подготовки корпуса (т.е. для определения частот) попробовать использовать другие пакеты, а не tm (я слышал о двух).

      Первый вариант требует меньше телодвижений, давайте попробуем его. Перезапустите R-сессию (в RStudio это ctrl-shift-F10 или из меню).

      Потом:
      Sys.setlocale(“LC_ALL”, “ru_RU.UTF-8”)

      Для проверки покажите вывод Sys.getlocale()

      Далее выполняйте обычные команды до wordcloud(), включая перекодировку из cp в utf.

  28. Maria
    Maria 2017-11-10

    Александр, спасибо! Не могу поменять локаль в RStudio.
    > Sys.setlocale(“LC_ALL”,”ru_RU.UTF-8″)
    [1] “”
    Warning message:
    In Sys.setlocale(“LC_ALL”, “ru_RU.UTF-8”) :
    OS reports request to set locale to “ru_RU.UTF-8” cannot be honored

    • Александр Матрунич
      Александр Матрунич 2017-11-10

      Хорошо. Возможно, есть какие-нибудь фокусы с локалью в Windows, но мне они не известны. 🙂 Предлагаю перейти ко второму варианту, если есть ещё энтузиазм. Готовы? 🙂

      Мы знаем, что wordcloud() рисует графики под Windows, но без пакета tm. Чтобы wordcloud() не обращался к tm::TermDocumentMatrix(), нужно для него заранее подготовить вектор слов и вектор частот, соответствующих словам.

      Стоп… ещё один вариант вспомнил. Вдруг всё же проблема в RStudio. Попробуйте ту же самую конструкцию, но в базовом R:

      articles <- Corpus(DirSource(dirpath, encoding = "cp1251"), readerControl = list(reader = readPlain, language = "ru", load = T)) content(articles[[1]]) Terms(DocumentTermMatrix(articles))

      • Александр Матрунич
        Александр Матрунич 2017-11-10

        Вернее CP1251 (из списка ваших кодировок)

  29. Maria
    Maria 2017-11-10

    Александр, энтузиазма очень много:)
    В базовом R никогда не работала. Те команды,что записаны (articles <- Corpus(DirSource(dirpath, encoding = "cp1251"), readerControl = list(reader = readPlain, language = "ru", load = T)) content(articles[[1]]) Terms(DocumentTermMatrix(articles))) в консоли не работают. Возможно, немного другой синтаксис.
    Насчет заранее подготовленного вектора слов: хотела как раз, чтобы это сделал за меня R, но и в этой команде (findFreqTerms(dtm,lowfreq=80)) выдает непонятные символы.
    Нашла пакет quanteda – облако получилось нормальным.

    • Александр Матрунич
      Александр Матрунич 2017-11-10

      Не понял, так теперь с quanteda всё получилось?

  30. Виктория
    Виктория 2018-01-31

    Александр, добрый вечер!

    Спасибо за статью! Подскажите, а как бороться с ошибками, допущенными в тексте?Как их исправлять? Есть ли хорошие функции в R или программы, похожие на MyStem?

  31. Виктория
    Виктория 2018-02-01

    Александр, спасибо за ответ!

    Помогите еще, пожалуйста, по использованию вашего кода.

    Использую на входе данные (уже обработанные заранее), например:

    > data_cor_t[[1]]$content
    [1] “борщ украине резко подорожал”
    > data_cor_t[[2]]$content
    [1] “правительство признало неизбежность роста цен бензин”

    Применяю функцию:
    mystem <- function(x) {
    doc <- system('C:/Users/Downloads/mystem-3.1-win-64bit/mystem -nl -e cp1251', intern=T, input=x)
    doc <- gsub("\\?", "", doc)
    doc <- gsub("\\|.*$", "", doc)
    doc <- paste(doc, collapse =" ")
    attributes(sdoc) <- attributes(doc)
    doc
    }

    data_cor_t <- tm_map(data_cor_t, mystem)

    Получается результат:
    [1] "борщ украина резко подорожать правительство признавать неизбежность рост цена бензин"
    Error in x$content[[i]] : subscript out of bounds

    Т.е. все слепилось в один документ. И корпус стал состоять не из двух документов, а одного.

    Что-то происходит не то на этапе конкатенации, но как это исправить?

    • Александр Матрунич
      Александр Матрунич 2018-02-02

      Виктория, попробуйте сначала исправить функцию mystem(). Обратите внимание на использование в оригинальной версии переменных doc и sdoc.

  32. Виктория
    Виктория 2018-02-02

    Александр, для чистоты эксперимента запустила оригинальный код функции. Отличие сейчас только в кодировке cp1251. Результат тот же: на выходе корпус из одного склеенного документа. При этом attributes(doc) выдает NULL.

    mystem <- function(doc) {
    sdoc <- system('C:/Users/Рыбки/Downloads/mystem-3.1-win-64bit/mystem -nl -e cp1251', intern=T, input=doc)
    sdoc <- str_replace(sdoc, '\\?', '')
    sdoc <- str_replace(sdoc, '\\|.*$', '')
    sdoc <- paste(sdoc, collapse=" ")
    attributes(sdoc) <- attributes(doc)
    sdoc
    }

    Замечу, что я пробовала оставить в функции только одну операцию paste

    mystem <- function(doc) {
    doc <- paste(doc, " ", collapse = " ")
    }

    И в этой ситуации все документы склеиваются.

    Пробовала убрать из параметров -n, чтобы строка не разбивалась, но результат опять тот же
    sdoc <- system('C:/Users/Рыбки/Downloads/mystem-3.1-win-64bit/mystem -l -e cp1251', intern=T, input=doc)

  33. Виктория
    Виктория 2018-02-03

    Александр, вариант с использованием функции lapply вместо tm_map работает корректно, но очень долго. И для больших дата сетов не подходит.

    data_cor_t <- Corpus(VectorSource(lapply(1:length(data_cor_t), function(i) mystem(data_cor_t[[i]]$content))))

    Также не помогает замена
    attributes(sdoc) <- attributes(doc)
    на
    sdoc <- PlainTextDocument(sdoc)

    Что еще можно попробовать?

    • Александр Матрунич
      Александр Матрунич 2018-02-03

      Пост был написан ещё в 2014 году, так я что не помню всех подробностей. 🙂 Теперь я бы попробовал использовать расширение tidytext – его сейчас разработчик активно продвигает. Плюс вместо stem можно попробовать расширение hunspell. Судя по документации, он умеет stemming, но нужно узнать, насколько хорошо поддерживается русский.

      А по поводу скорости – у вас был опыт, где tm_map работает значительно быстрее lapply? По идее, оба варианта должны быть быстрыми, т.к. написаны на C. Попробуйте сравнить с функцией purrr::map().

      • Виктория
        Виктория 2018-02-04

        Александр, по поводу скорости. Если взять стемминг Портера в функции tm_map, то функция отрабатывает мгновенного. lapply и map существенно дольше. Ниже результаты испытаний.

        > system.time(tm_map(data_cor_t, stemDocument, language = “russian”))
        пользователь система прошло
        0 0 0

        > system.time(Corpus(VectorSource(lapply(1:length(data_cor_t), function(i) mystem(data_cor_t[[i]]$content)))))
        пользователь система прошло
        0.03 0.11 6.36

        > system.time(Corpus(VectorSource(map(1:length(data_cor_t), function(i) mystem(data_cor_t[[i]]$content)))))
        пользователь система прошло
        0.04 0.12 6.43

        К сожалению, в пакете hunspell функции hunspell_stem работает со словами, а не с документами. Т.е. придется разбивать на слова, применять стемминг, а потом снова соединять. Получается, что возвращаемся к проблеме выше с функцией tm_map.

        По качеству стемминга hunspell_stem: на примере слова “молодежный” он приводит к форме, как mystem.

        Александр, но у Вас же код работает? Разница только в строке attributes(sdoc) <- attributes(doc), от которой ничего не зависит. И источник VectorSource.

        Сделала простой пример для тестирования.
        data_cor <- Corpus(VectorSource(as.character(c("Раз два три", "четыре пять шесть"))))
        mystem <- function(doc) {
        sdoc <- system('C:/Users/Downloads/mystem-3.1-win-64bit/mystem -ln -e cp1251', intern=T, input=doc)
        sdoc <- str_replace(sdoc, '\\?', '')
        sdoc <- str_replace(sdoc, '\\|.*$', '')
        sdoc <- paste(sdoc, collapse=" ")
        sdoc
        }
        f <- content_transformer(function(x) mystem(x))
        data_cor_t <- tm_map(data_cor, f)
        data_cor_t[[1]]$content

        Написала также письмо с тем же вопросом разработчикам пакета tm.

        • Александр Матрунич
          Александр Матрунич 2018-02-04

          Виктория, спасибо за интересные сведения по поводу скорости и hunspell. В tidytext, как я понял, функции стемминга нет, да?

          У меня код работал в 2014 году, а сейчас я не пробовал, поскольку ни stem не установлен, ни текстов сейчас нет. Т.е. возможно, что-то изменилось в пакете tm, что даёт такой результат.

          Попробуйте дать мне minimal reproducible example: т.е. полностью воспроизводимый кусок вашего кода, который я могу скопировать себе в R и проверить результат (mystem поставлю).

  34. Виктория
    Виктория 2018-02-04

    Александр, спасибо, вот пример кода, который можно запустить:
    data_cor <- Corpus(VectorSource(as.character(c("Раз два три", "четыре пять шесть"))))
    mystem <- function(doc) {
    sdoc <- system('C:/Users/Downloads/mystem-3.1-win-64bit/mystem -ln -e cp1251', intern=T, input=doc)
    sdoc <- str_replace(sdoc, '\\?', '')
    sdoc <- str_replace(sdoc, '\\|.*$', '')
    sdoc <- paste(sdoc, collapse=" ")
    sdoc
    }
    data_cor_t data_cor_t[[1]]$content
    [1] “раз два три четыре пять шесть”

    вместо:

    > data_cor[[1]]$content
    [1] “Раз два три”

    Я бегло просмотрела функции из tidytext, но отдельную функцию стемминга не нашла.

  35. Виктория
    Виктория 2018-02-04

    Почему-то отобразился не весь ответ. Поэтому дублирую:

    Александр, спасибо, вот пример кода, который можно запустить:
    data_cor <- Corpus(VectorSource(as.character(c("Раз два три", "четыре пять шесть"))))
    mystem <- function(doc) {
    sdoc <- system('C:/Users/Downloads/mystem-3.1-win-64bit/mystem -ln -e cp1251', intern=T, input=doc)
    sdoc <- str_replace(sdoc, '\\?', '')
    sdoc <- str_replace(sdoc, '\\|.*$', '')
    sdoc <- paste(sdoc, collapse=" ")
    sdoc
    }
    data_cor_t <- tm_map(data_cor, content_transformer(mystem))
    data_cor_t[[1]]$content

    • Александр Матрунич
      Александр Матрунич 2018-02-04

      Похоже, paste() всё портит.


      > library(tm)
      Loading required package: NLP
      > data_cor data_cor
      <>
      Metadata: corpus specific: 1, document level (indexed): 0
      Content: documents: 2

      Когда используем только str_replace(), то получаем два документа:


      > mystem tm_map(data_cor, content_transformer(mystem))
      <>
      Metadata: corpus specific: 1, document level (indexed): 0
      Content: documents: 2

      Когда paste0() – один:


      > mystem tm_map(data_cor, content_transformer(mystem))
      <>
      Metadata: corpus specific: 1, document level (indexed): 0
      Content: documents: 1

      Т.е. как будто он применяется сразу ко всему содержимому.

  36. катя куц
    катя куц 2018-11-28

    Здравствуйте можно ли из загруженного html файла получить 5слов до и 5 после определенной фрази

  37. Игорь
    Игорь 2019-05-04

    Александр , добрый день!

    на windows 10 облако построило с функцией:

    mystem <- function(doc) {
    sdoc <- system('./mystem -ln -e cp1251', intern=T, input=doc)
    sdoc <- str_replace(sdoc, '\\?', '')
    sdoc <- str_replace(sdoc, '\\|.*$', '')
    # sdoc <- paste(sdoc, collapse=" ")
    sdoc
    }

    Спасибо!) Хорошая статья и работа с комментариями!

Leave a Reply

Your email address will not be published. Required fields are marked *

Защита от спама *