Аналіз текстів (text mining) в R реалізовується за допомогою пакету tm

Аналізувати можна різні типи текстів: html-сторінки, pdf-файли, документи в docx та інші. У цій статті розглянемо як можна аналізувати в R документи у форматах html, docx та txt. Це дозволить нам прослідкувати, як формати аналізованих документів впливають на результати самого аналізу. Це дозволить у майбутньому при аналізі враховувати ці особливості.

Для того, щоб продемонструвати можливості R в аналізі тестів, ми візьмемо для роботи три тексти з Хабру:

Ці тексти ми завчасно зберегли у форматах txt та docx на локальному диску.

Підготовка до аналізу

Завантаження текстів

Тексти для аналізу потрібно підготувати. Особливо, якщо ми працюємо не з документами на локальному диску, а із матеріалами сайтів. Їх потрібно позбавити зайвого коду і лишити тільки сам текст. Є багато різних способів, як це зробити. Одним із найпростіших є використання функції htmlToText, яка використовує команди з пакетів RCurl та XML

library(RCurl)
library(XML)
htmlToText <- function(input, ...) {
  require(RCurl)
  require(XML)
  evaluate_input <- function(input) {    
    if(file.exists(input)) {
      char.vec <- readLines(input, warn = FALSE)
      return(paste(char.vec, collapse = ""))
    }
    if(grepl("</html>", input, fixed = TRUE)) return(input)
    if(!grepl(" ", input)) {
      if(!file.exists("cacert.perm")) download.file(url="http://curl.haxx.se/ca/cacert.pem", destfile="cacert.perm")
      return(getURL(input, followlocation = TRUE, cainfo = "cacert.perm"))
    }
    return(NULL)
  }
  convert_html_to_text <- function(html) {
    doc <- htmlParse(html, asText = TRUE)
    text <- xpathSApply(doc, "//text()[not(ancestor::script)][not(ancestor::style)][not(ancestor::noscript)][not(ancestor::form)]", xmlValue)
    return(text)
  }
  collapse_text <- function(txt) {
    return(paste(txt, collapse = " "))
  }
  html.list <- lapply(input, evaluate_input)
  text.list <- lapply(html.list, convert_html_to_text)
  text.vector <- sapply(text.list, collapse_text)
  return(text.vector)
}

Тепер застосуємо цю функцію до html-сторінок

input <- "https://habrahabr.ru/post/217545/"
input2 <- "https://habrahabr.ru/company/itinvest/blog/262155/"
input3 <-  "https://habrahabr.ru/post/232515/" 

Конвертуємо тепер це в текст за допомогою вище створеної функції:

txt <- htmlToText(input)
txt2 <- htmlToText(input2)
txt3 <- htmlToText(input3)

Усі тексти об’єднаємо в один список:

text <- c(txt,txt2,txt3)

Отже, три тексти з html-сторінок майже готові до аналізу. Тепер прочитаємо доківський файл. Він також засорений різного роду кодом, подібно до html-сторінки. Для його очищення від нього вже також є написані функції.

Для читання доківських файлів найкраще використовувати функцію read_docx з пакету qdapTools:

library(qdapTools)
docx <- read_docx("text.docx")
docx2 <- read_docx("text2.docx")
docx3 <- read_docx("text3.docx")

Також об’єднаємо в список:

word <- list(docx,docx2,docx3)

Документи у форматі txt найзручніші для роботи, адже не містять зайвого коду. Їх читання в пакеті tm трохи відмінне.

Усі тексти, які маємо намір проаналізувати спочатку треба зберегти в окрему директорію. Потім подібним чином вказаки адресу цієї папки:

cname <- file.path("~", "new_media", "text")   
cname 
## [1] "~/new_media/text"
dir(cname)
## [1] "text.txt"  "text2.txt" "text3.txt"

Очистка текстів

Тепер запустимо сам пакет tm і сформуємо корпуси слів. Для документів word і html ця процедура буде однаковою, там на вхід ідуть списки. Для txt на вхід йде директорія, тому команада трохи інша:

library(tm)   
corpus <- Corpus(VectorSource(text)) 
corpus2 <- Corpus(VectorSource(word)) 
corpus3 <- Corpus(DirSource(cname)) 

Перевіримо, чи подібні у нас вийшли файли:

summary(corpus) 
##   Length Class             Mode
## 1 2      PlainTextDocument list
## 2 2      PlainTextDocument list
## 3 2      PlainTextDocument list
summary(corpus2) 
##   Length Class             Mode
## 1 2      PlainTextDocument list
## 2 2      PlainTextDocument list
## 3 2      PlainTextDocument list
summary(corpus3)
##           Length Class             Mode
## text.txt  2      PlainTextDocument list
## text2.txt 2      PlainTextDocument list
## text3.txt 2      PlainTextDocument list

Усе добре, продовжуємо роботу.

Видалимо з масивів пунктуацію:

docs <- tm_map(corpus, removePunctuation)
docs2 <- tm_map(corpus2, removePunctuation)
docs3 <- tm_map(corpus3, removePunctuation)

Так само замінимо на пропуски різні зайві символи:

for(j in seq(docs))   
{   
  docs[[j]] <- gsub("/", " ", docs[[j]])   
  docs[[j]] <- gsub("@", " ", docs[[j]])   
  docs[[j]] <- gsub("\\|", " ", docs[[j]])   
}  

for(j in seq(docs2))   
{   
  docs2[[j]] <- gsub("/", " ", docs2[[j]])   
  docs2[[j]] <- gsub("@", " ", docs2[[j]])   
  docs2[[j]] <- gsub("\\|", " ", docs2[[j]])   
} 

for(j in seq(docs3))   
{   
  docs3[[j]] <- gsub("/", " ", docs3[[j]])   
  docs3[[j]] <- gsub("@", " ", docs3[[j]])   
  docs3[[j]] <- gsub("\\|", " ", docs3[[j]])   
} 

Подібним чином можна заміняти різні слова, символи та скорочення на інші (наприклад txt <- gsub("анализировать", "анализ", txt) - ця команда замінить всі “анализировать” на “анализ” в документі txt)

Видалимо числа:

docs <- tm_map(docs, removeNumbers) 
docs2 <- tm_map(docs2, removeNumbers) 
docs3 <- tm_map(docs3, removeNumbers) 

Зробимо всі слова написаними маленькими літерами:

docs <- tm_map(docs, tolower) 
docs2 <- tm_map(docs2, tolower) 
docs3 <- tm_map(docs3, tolower) 

Тепер видалимо стоп-слова (сполучники, займенники і тп). У пакеті tm є готовий список російських стоп-слів, однак він не повний й інколи тексти місьтять специфічні для них стоп-слова (наприклад, назва сайту, де цей текст опублікований)

docs <- tm_map(docs, removeWords, stopwords("russian"))   
docs2 <- tm_map(docs2, removeWords, stopwords("russian"))   
docs3 <- tm_map(docs3, removeWords, stopwords("russian"))  

Слова, яких нема в списку стоп-слів можна видалити подібним чином окремо. Забігаючи наперед скажу, що в списку стоп-слів немає слова “это”:

docs <- tm_map(docs, removeWords, c("хабр", "хабрахабр", "это")) 
docs2 <- tm_map(docs2, removeWords, c("хабр", "хабрахабр", "это")) 
docs3 <- tm_map(docs3, removeWords, c("хабр", "хабрахабр", "это")) 

Пакет SnowballC допоможе нам ще краще підготувати тексти до аналізу.

Зокрема функція stemDocument дозволить уніфікувати однокореневі слова (для англійських слів, звісно, вона працює краще):

library(SnowballC)   
docs <- tm_map(docs, stemDocument)
docs2 <- tm_map(docs2, stemDocument)   
docs3 <- tm_map(docs3, stemDocument)   

Також видалимо зайві пробіли і пропуски:

docs <- tm_map(docs, stripWhitespace)
docs2 <- tm_map(docs2, stripWhitespace)
docs3 <- tm_map(docs3, stripWhitespace)

І завершуємо підготовку даних переформатуванням у PlainTextDocument, з яким працює пакет tm:

docs <- tm_map(docs, PlainTextDocument) 
docs2 <- tm_map(docs2, PlainTextDocument) 
docs3 <- tm_map(docs3, PlainTextDocument) 

Аналіз текстів

Аналіз частот

Зробимо матрицю слів:

dtm <- DocumentTermMatrix(docs)   
dtm2 <- DocumentTermMatrix(docs2)  
dtm3 <- DocumentTermMatrix(docs3) 

Порахуємо частоту, з якою зустрічаються слова:

freq <- colSums(as.matrix(dtm))
freq2 <- colSums(as.matrix(dtm2))  
freq3 <- colSums(as.matrix(dtm3))  

Упорядкуємо їх за частою:

ord <- order(freq)  
ord2 <- order(freq2) 
ord3 <- order(freq3)

І поглянемо на результат, вивівши 6 найпопулярніших термінів:

freq[head(ord)] 
##   данных      данные     августа    алгоритм       метод вероятность 
##       62          61          56          50          39          29
freq2[head(ord2)] 
##   hyperlink    данные     метод   решений  pagerank       knn 
##         128        43        36        26        26        23 
freq3[head(ord3)] 
##   данных   данные    метод  решений pagerank обучения  
##       59       43       36       26       26       23 

Результати вийшли відмінні. Цьому є своє пояснення. У випадку html-документа анлізувалася не лише сама стаття, а і коментарі (“марта” - це від того, що на сайті ставилася дата коментаря (числа ми видалили, а місяць лишився)). Плюс коментарі додали частот багатьом словам, які зустрічалися в тексті. У випадку word-документа найбільшу популярність отримав термін hyperlink. Це зумовлено тим, що у збережених текстах було багато гіперпосилань, які при переформатуванні позначалися додатково цим терміном. Його у майбутньому потрібно буде відсівати на етапі відсіву стоп-слів. Аналіз txt документа прогнозовано дав найменш засорені дані. Це логічно, бо до нього не потрібно застосовувати очистку від коду.

Для виявлення “штучно” популярних слів можна ще подивитися на частоту частот:

head(table(freq), 100) 
## freq
##    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
## 3113  658  355  158  112   63   38   42   20   30   16   14   12   10    3 
##   16   17   18   19   20   21   23   24   25   26   29   39   47   50   56 
##    8    5    1    3    4    2    3    1    1    3    2    1    1    1    1 
##   61   62 
##    1    1

Де частоти починають порушувати нормальний розподіл, там потрібно уважніше дивитися на терміни з такими частотами - швидше за все така ненормальна популярність зумовалена технічними особливостями тексту і їх потрібно прибрати з аналізу.

Можемо вивести найпопулярніші слова і таким чином:

freq <- sort(colSums(as.matrix(dtm)), decreasing=TRUE)   
head(freq, 14) 
##        данных        данные       августа      алгоритм         марта 
##            62            61            56            50            47 
##         метод   вероятность       которые      например       решений 
##            39            29            29            26            26 
##      pagerank        почему           knn классификатор 
##            26            25            24            23
freq2 <- sort(colSums(as.matrix(dtm2)), decreasing=TRUE)   
head(freq2, 14) 
##     hyperlink        данных      алгоритм        данные         метод 
##           128            59            45            43            36 
##       решений      pagerank      обучения           knn       которые 
##            26            26            23            23            22 
##   вероятность  используется классификатор         набор 
##            21            19            19            19
freq3 <- sort(colSums(as.matrix(dtm3)), decreasing=TRUE)   
head(freq3, 14) 
##        данных      алгоритм        данные         метод       решений 
##            59            45            43            36            26 
##      pagerank           knn      обучения       которые   вероятность 
##            26            24            23            22            21 
##  используется классификатор         набор     параметры 
##            19            19            19            19

Можна просто ці слова подати без вказівки на частоту:

findFreqTerms(dtm, lowfreq=15) 
##  [1] "августа"       "алгоритм"      "алгоритма"     "апреля"       
##  [5] "вероятность"   "всё"           "давайте"       "данные"       
##  [9] "данных"        "делает"        "дерева"        "именно"       
## [13] "использует"    "используется"  "классификатор" "компании"     
## [17] "которые"       "который"       "ксредних"      "марта"        
## [21] "метод"         "набор"         "например"      "нужно"        
## [25] "обучения"      "очень"         "параметры"     "поскольку"    
## [29] "почему"        "пример"        "просто"        "работы"       
## [33] "реклама"       "решений"       "такое"         "требует"      
## [37] "является"      "cart"          "data"          "knn"          
## [41] "pagerank"      "svm"
findFreqTerms(dtm2, lowfreq=15)
##  [1] "алгоритм"      "вероятность"   "давайте"       "данные"       
##  [5] "данных"        "делает"        "дерева"        "использует"   
##  [9] "используется"  "классификатор" "которые"       "ксредних"     
## [13] "метод"         "набор"         "например"      "нужно"        
## [17] "обучения"      "параметры"     "почему"        "пример"       
## [21] "решений"       "требует"       "является"      "cart"         
## [25] "hyperlink"     "knn"           "pagerank"      "svm"
findFreqTerms(dtm3, lowfreq=15)
##  [1] "алгоритм"      "вероятность"   "давайте"       "данные"       
##  [5] "данных"        "делает"        "дерева"        "использует"   
##  [9] "используется"  "классификатор" "которые"       "ксредних"     
## [13] "метод"         "набор"         "например"      "нужно"        
## [17] "обучения"      "параметры"     "почему"        "пример"       
## [21] "решений"       "требует"       "является"      "cart"         
## [25] "knn"           "pagerank"      "svm"

А можна дати в табличному вигляді:

wf <- data.frame(word=names(freq), freq=freq)   
wf2 <- data.frame(word=names(freq2), freq=freq2)  
wf3 <- data.frame(word=names(freq3), freq=freq3)  
head(wf)  
##              word freq
## данных     данных   62
## данные     данные   61
## августа   августа   56
## алгоритм алгоритм   50
## марта       марта   47
## метод       метод   39
head(wf2)  
##                word freq
## hyperlink hyperlink  128
## данных       данных   59
## алгоритм   алгоритм   45
## данные       данные   43
## метод         метод   36
## решений     решений   26
head(wf3) 
##              word freq
## данных     данных   59
## алгоритм алгоритм   45
## данные     данные   43
## метод       метод   36
## решений   решений   26
## pagerank pagerank   26

Ясна річ, що слів у документах може бути дуже багато, але нас цікавлять найбільш вживані. Маловживані часто є потреба видалити. Для цього застосовується функція removeSparseTerms. Вона видаляє зайві слова не за сумарною частотою вживаності, а більше за частотою появи в усіх документах. Тобто важливіше для слова бути хоча б раз в усіх документах, чим багато разів в одному.

dtms <- removeSparseTerms(dtm, 0.1)
dtms2 <- removeSparseTerms(dtm2, 0.1)
dtms3 <- removeSparseTerms(dtm3, 0.1)

Поглянемо на результати:

inspect(dtms)  
## <<DocumentTermMatrix (documents: 3, terms: 285)>>
## Non-/sparse entries: 855/0
## Sparsity           : 0%
## Maximal term length: 23
## Weighting          : term frequency (tf)
## 
##               Terms
## Docs           августа алгоритмы анализ архитектура балансе бесконечного
##   character(0)       6         1      2           1       5            1
##   character(0)       4         4      3           1       3            1
##   character(0)      46         2      6           1       5            1
##               Terms
## Docs           большим большую будут быстро вакансии вашем версия вещей
##   character(0)       3       1     1      2        1     1      1     1
##   character(0)       4       1     5      2        2     1      1     1
##   character(0)       1       1     2      2        1     1      1     1
##               Terms
## Docs           взять виде видим видите вместо внеземной войдите войти
##   character(0)     2    3     4      1      1         1       1     1
##   character(0)     2    1     2      4      4         1       1     1
##   character(0)     1    1     2      1      1         1       1     1
##               Terms
## Docs           вопрос времени время всем всему встречается второй выше
##   character(0)      6       4     5    5     1           2      2    3
##   character(0)      5       1     1    1     1           1      2    3
##   character(0)      1       8     4    1     1           1      3    4
##               Terms
## Docs           гиктаймс говоря года график давайте дайджест данные данных
##   character(0)        1      2    3      8       4        2     10      4
##   character(0)        1      1    1      1      11        2     43     57
##   character(0)        1      2    2      3       1        2      8      1
##               Terms
## Docs           движения деанонимизируем делать дело добавить довольно
##   character(0)        1               1      2    1        5        2
##   character(0)        1               1      2    1        2        6
##   character(0)       12               1      3    4        1        2
##               Terms
## Docs           должны достаточно доступна других жизни задача
##   character(0)      2          3        1      1     2      1
##   character(0)      2          4        1      3     1      2
##   character(0)      1          3        1      1     3      2
##               Terms
## Docs           зарегистрированные зародилась знает значение значению
##   character(0)                  1          1     3        1        4
##   character(0)                  1          1     1        2        2
##   character(0)                  1          1     1        1        4
##               Terms
## Docs           значения значит идеи избранное изменён именно инженерия
##   character(0)        1      5    2         2       8      7         2
##   character(0)        5      1    1         1       1      8         1
##   character(0)        1      2    1         2       5      1         2
##               Terms
## Docs           инструменты интеллекта интересно интересные инфо
##   character(0)           4          2         3          5    1
##   character(0)           2          2         2          3    1
##   character(0)           4          2         2          5    1
##               Terms
## Docs           искусственного используется исследование исследования
##   character(0)              2            1            2            1
##   character(0)              2           17            1            1
##   character(0)              2            2            1            1
##               Terms
## Docs           истории каждой каждый каламбуры карт картинка качестве
##   character(0)       1      1      1         2    5        7        1
##   character(0)       3      5     10         2    3        1        1
##   character(0)       1      1      1         2    5        2        1
##               Terms
## Docs           клиентов количество комментарии комментарий компании
##   character(0)        5          1           3           8        7
##   character(0)        4         10           2           1        6
##   character(0)        5          1           3           5        2
##               Terms
## Docs           контент которая которую которые который круг купил лекция
##   character(0)       1       1       1       7       3    1     1      2
##   character(0)       1       4       2      18       9    1     1      1
##   character(0)       1       2       3       4       6    1     1      2
##               Terms
## Docs           либо материалов материалы меньше меняют месяц метод
##   character(0)    1          2         5      2      1     4     1
##   character(0)    1          2         4      2      1     1    35
##   character(0)    2          2         4      1      1     1     3
##               Terms
## Docs           механика миллиардов мира мобильная могу могут мти найти нам
##   character(0)        1          1    2         1    2     1   1     1   3
##   character(0)        1          1    2         1    1    10   1     2   6
##   character(0)        1          1    2         1    1     1   1     1   1
##               Terms
## Docs           например насколько начинающего наша наши неделю неделя
##   character(0)        5         1           1    2    5      3      2
##   character(0)       15         2           2    1    1      2      1
##   character(0)        6         2           1    1    4      2      2
##               Terms
## Docs           неплохо несколько ниже ниичоси никто новости новую нужно
##   character(0)       1         2    2       2     2       4     1     4
##   character(0)       1         4    1       1     1       4     2    13
##   character(0)       1         1    2       2     2       5     1     6
##               Terms
## Docs           образом образца объектноориентированное одним одной одном
##   character(0)       3       1                       2     2     2     1
##   character(0)       4       1                       1     1     2     1
##   character(0)       1       1                       2     1     3     1
##               Terms
## Docs           оказалось окна операционку определить опытного оставлять
##   character(0)         1    1           1          1        2         1
##   character(0)         2    1           1         11        1         1
##   character(0)         1    2           1          1        1         1
##               Terms
## Docs           очень ошибки параметры пасхалка первом первый переменная
##   character(0)     8      4         1        1      2      2          4
##   character(0)     6      1        17        1      2      2          2
##   character(0)     3      1         2        1      1      1          4
##               Terms
## Docs           песочница плату повесть поводу поддержки подписчики
##   character(0)         2     1       2      1         1          1
##   character(0)         2     1       1      1         1          1
##   character(0)         2     1       2      1         1          1
##               Terms
## Docs           пожалуйста позволяет поиск показать получаем получается
##   character(0)          1         1     1        1        1          2
##   character(0)          1         2     1        3        2          1
##   character(0)          1         1     2        1        3          2
##               Terms
## Docs           получить пользователей пользователи помогает помощь помощью
##   character(0)        1             1            3        4      2       4
##   character(0)        1             2            4        3      2       2
##   character(0)        3             1            3        4      2       5
##               Terms
## Docs           понимаю поскольку последнюю похожие почему поэтому правила
##   character(0)       1         1         2       1      3       3       2
##   character(0)       1        15         2       1     14       6       4
##   character(0)       3         1         2       1      8       2       1
##               Terms
## Docs           приложения пример примере примерно причин пришли проблема
##   character(0)          1      7       1        1      1      1        3
##   character(0)          2     12       3        2      1      1        3
##   character(0)          2      2       1        3      1      1        2
##               Terms
## Docs           проблемы проверить программирование программная продаваемые
##   character(0)        1         1                4           2           1
##   character(0)        1         1                1           1           1
##   character(0)        1         1                4           2           1
##               Terms
## Docs           проектируем прозрачность просто профиль прощай проще
##   character(0)           1            1      9       1      2     2
##   character(0)           1            1      6       1      1     2
##   character(0)           1            1      2       1      2     1
##               Terms
## Docs           публикации работа работать работе равной разделы разница
##   character(0)          5      1        1      1      4       2       1
##   character(0)          4      1        4      2      2       2       1
##   character(0)          5      1        2      7      4       2       1
##               Terms
## Docs           разное разрабатывает разработка раннера рано
##   character(0)      1             1          4       1    1
##   character(0)      1             1          3       1    1
##   character(0)      1             1          4       1    1
##               Terms
## Docs           распространенные регистрация результаты рейтинг реклама
##   character(0)                1           1          4       2       9
##   character(0)                1           1          2       2       1
##   character(0)                1           1          3       2       9
##               Terms
## Docs           сайт сайте самое самые самый свежих своих сделали семинары
##   character(0)    2     1     4     2     1      2     5       2        1
##   character(0)    4     1     2     2     1      2     3       1        1
##   character(0)    2     2     4     1     1      2     5       1        1
##               Terms
## Docs           систем скомпрометировал слишком слова служба случае
##   character(0)      1                5       2     1      1      1
##   character(0)      1                3       1     1      1      6
##   character(0)      1                5       1     1      1      1
##               Terms
## Docs           собственному современная соглашение создание спасибо
##   character(0)            4           1          1        1       5
##   character(0)            2           1          1        1       1
##   character(0)            4           1          1        2       1
##               Terms
## Docs           спецпроекты способ сразу стала стартапам статье статьи
##   character(0)           3      1     2     3         1      2      2
##   character(0)           1      3     1     1         1      1      2
##   character(0)           3      4     2     1         1      4      4
##               Terms
## Docs           статью стоит сутки такая также таким такое такому тарифы
##   character(0)      1     4     1     5     1     3     4      1      1
##   character(0)      3     6     1     1     6     3    12      1      1
##   character(0)      3     2     1     3     2     1     5      1      1
##               Terms
## Docs           телефоны теме тестдрайв тех типизации тостер точке уровень
##   character(0)        1    1         1   5         2      1     1       2
##   character(0)        1    3         1   3         2      1     1       6
##   character(0)        1    2         1   1         2      1     1       1
##               Terms
## Docs           услуги успешно учетные фона фрилансим фронтенда функций
##   character(0)      1       1       1    1         1         2       2
##   character(0)      1       1       1    1         1         2       2
##   character(0)      1       2       1    1         1         2       2
##               Terms
## Docs           хабы хотим хотя человека читаемое чтото эта языковая
##   character(0)    4     1    4        1        1     4   1        2
##   character(0)    2     1    5        1        1     1   3        2
##   character(0)    4     2    1        1        1     6   2        2
##               Terms
## Docs           яндексе anniversary facebook feed frontendразработчики
##   character(0)       2           1        2    1                    1
##   character(0)       1           1        1    1                    1
##   character(0)       2           1        1    1                    1
##               Terms
## Docs           fuchsia geektimes google htmlверстальщика ibm javascript
##   character(0)       1         1      2                1   1          1
##   character(0)       1         1      6                1   1          1
##   character(0)       1         1      3                1   1          1
##               Terms
## Docs           kicad microsoft phpдайджест pokemon qeda robot saday
##   character(0)     1         1           4       1    1     1     2
##   character(0)     1         1           2       1    1     1     1
##   character(0)     1         1           4       1    1     1     2
##               Terms
## Docs           tinkoff update vpnаккаунтов watson web whatsapp windows
##   character(0)       5      1            1      1   1        1       2
##   character(0)       3      1            1      1   1        1       2
##   character(0)       5      1            1      1   1        1       2
inspect(dtms2)
## <<DocumentTermMatrix (documents: 3, terms: 54)>>
## Non-/sparse entries: 162/0
## Sparsity           : 0%
## Maximal term length: 38
## Weighting          : term frequency (tf)
## 
##               Terms
## Docs           анализ большую будут видим вместо времени выше график
##   character(0)      1       1     1     3      1       1    2      3
##   character(0)      2       1     1     1      1       4    3      3
##   character(0)      3       1     4     1      4       1    3      1
##               Terms
## Docs           давайте данные делать достаточно значение значит именно
##   character(0)       3      4      2          3        1      3      2
##   character(0)       1      1      2          2        1      2      1
##   character(0)      11     38      1          4        2      1      8
##               Terms
## Docs           исследования каждой количество которая которые который
##   character(0)            1      1          1       1       5       3
##   character(0)            1      1          1       2       3       3
##   character(0)            1      4          9       4      14       8
##               Terms
## Docs           меньше метод нам например неплохо ниже нужно очень
##   character(0)      1     1   1        2       1    2     2     2
##   character(0)      1     1   1        2       1    1     3     1
##   character(0)      2    34   6       14       1    1    12     6
##               Terms
## Docs           позволяет показать получается получить помощью поэтому
##   character(0)         1        1          2        1       2       2
##   character(0)         1        1          2        3       1       1
##   character(0)         2        2          1        1       1       6
##               Terms
## Docs           просто проще работать работе результаты самое самый способ
##   character(0)      1     1        1      1          3     1     1      1
##   character(0)      1     1        1      7          2     2     1      4
##   character(0)      6     2        3      2          2     1     1      3
##               Terms
## Docs           сразу статье статьи таким такое точке хотим человека чтото
##   character(0)     1      1      1     3     1     1     1        1     1
##   character(0)     1      3      4     1     2     1     2        1     2
##   character(0)     1      1      1     3    11     1     1        1     1
##               Terms
## Docs           httpshabrahabrruflowsdevelopразработка hyperlink
##   character(0)                                      1        29
##   character(0)                                      1        20
##   character(0)                                      1        79
inspect(dtms3)
## <<DocumentTermMatrix (documents: 3, terms: 53)>>
## Non-/sparse entries: 159/0
## Sparsity           : 0%
## Maximal term length: 12
## Weighting          : term frequency (tf)
## 
##               Terms
## Docs           анализ большую будут видим вместо времени выше график
##   character(0)      1       1     1     3      1       1    2      3
##   character(0)      2       1     1     1      1       4    3      3
##   character(0)      3       1     4     1      4       1    3      1
##               Terms
## Docs           давайте данные делать достаточно значение значит именно
##   character(0)       3      4      2          3        1      3      2
##   character(0)       1      1      2          2        1      2      1
##   character(0)      11     38      1          4        2      1      8
##               Terms
## Docs           исследования каждой количество которая которые который
##   character(0)            1      1          1       1       5       3
##   character(0)            1      1          1       2       3       3
##   character(0)            1      4          9       4      14       8
##               Terms
## Docs           меньше метод нам например неплохо ниже нужно очень
##   character(0)      1     1   1        2       1    2     2     2
##   character(0)      1     1   1        2       1    1     3     1
##   character(0)      2    34   6       14       1    1    12     6
##               Terms
## Docs           позволяет показать получается получить помощью поэтому
##   character(0)         1        1          2        1       2       2
##   character(0)         1        1          2        3       1       1
##   character(0)         2        2          1        1       1       6
##               Terms
## Docs           просто проще работать работе разработка результаты самое
##   character(0)      1     1        1      1          1          3     1
##   character(0)      1     1        1      7          1          2     2
##   character(0)      6     2        3      2          1          2     1
##               Terms
## Docs           самый способ сразу статье статьи таким такое точке хотим
##   character(0)     1      1     1      1      1     3     1     1     1
##   character(0)     1      4     1      3      4     1     2     1     2
##   character(0)     1      3     1      1      1     3    11     1     1
##               Terms
## Docs           человека чтото
##   character(0)        1     1
##   character(0)        1     2
##   character(0)        1     1

Отже, на прикладі частот ми переконалися, що технічні особливості аналізованих текстів можуть дещо спотворювати результати. Найкраще аналізувати тексти, збережені у форматі txt. Але часто доводиться працювати із вордівськими документами, в яких моуть інколи проскакувати слова-команди. При роботі з html-файлами потрібно зважати, що аналізується не просто текст за посиланням, а і коментарі під ним, “шапка” сайту, одним словом - все, що відображається разом із цим текстом. В принципі для кожного сайту окремо можна прописати код так, аби аналізувалася тільки стаття за посиланням, але типового рішення, яке б сміливо застосовувалося по шаблону до всіх сайтів неможливо зробити. Аналізувати саме html-сторінки краще тоді, коли нема часу зберегти потрібний для аналізу контент у текстовий файл.

Графік частот

На прикладі корпусу з файлів txt зробимо різні варіанти аналізу. Побудуємо стовпчикову діаграму частот, з якими зустрічаються слова (10 і більше разів):

library(ggplot2)   
p <- ggplot(subset(wf3, freq>10), aes(word, freq))    
p <- p + geom_bar(stat="identity")   
p <- p + theme(axis.text.x=element_text(angle=45, hjust=1))   
p 

Кореляція

Глянемо, з якими словами разом зустрічаються в тексті:

findAssocs(dtms3, c("данные" , "анализ"), corlimit=0.98)
## $данные
##      будут     вместо   значение     именно     каждой количество 
##       1.00       1.00       1.00       1.00       1.00       1.00 
##    которые    который     меньше      метод        нам   например 
##       1.00       1.00       1.00       1.00       1.00       1.00 
##  позволяет   показать     просто      проще   работать    давайте 
##       1.00       1.00       1.00       1.00       1.00       0.99 
##      нужно      очень    поэтому      такое 
##       0.99       0.99       0.99       0.99 
## 
## $анализ
## которая 
##    0.98

Хмара слів

Побудуємо хмарку слів. Для термінів, які зустрічаються більше 25 разів:

library(wordcloud)
wordcloud(names(freq3), freq3, min.freq=25)

Для 100 найпопулярніших термінів:

wordcloud(names(freq3), freq, max.words=100) 

Додамо ранжування за кольором:

wordcloud(names(freq3), freq3, min.freq=20, scale=c(5, .1), colors=brewer.pal(6, "Dark2")) 
dark2 <- brewer.pal(6, "Dark2")   
wordcloud(names(freq3), freq3, max.words=100, rot.per=0.2, colors=dark2) 

Кластерний аналіз

Тепер зробимо ієрархічний кластерний аналіз.

Для цього відберемо найбільш вживані слова:

dtmss <- removeSparseTerms(dtm3, 0.15) 

І зробимо дендрограму:

library(cluster)   
d <- dist(t(dtmss), method="euclidian")   
fit <- hclust(d=d, method="ward")   
## The "ward" method has been renamed to "ward.D"; note new "ward.D2"
fit 
## 
## Call:
## hclust(d = d, method = "ward")
## 
## Cluster method   : ward.D 
## Distance         : euclidean 
## Number of objects: 53
plot(fit, hang=-1) 

Цей графік можна зробити кращим через додавання виділення. Виділимо 6 кластерів:

plot.new()
plot(fit, hang=-1)
groups <- cutree(fit, k=6)   # "k=" defines the number of clusters you are using   
rect.hclust(fit, k=6, border="red") # draw dendogram with red borders around the 5 clusters  

Але можна застосувати і k-means кластеризацію. Це ми також зробимо:

library(fpc)   
d <- dist(t(dtmss), method="euclidian")   
kfit <- kmeans(d, 2)   
clusplot(as.matrix(d), kfit$cluster, color=T, shade=T, labels=2, lines=0)  

Це все тренувальні дані. От коли їх буде більше і метою буде не просто показати можливості аналізу текстових даних, то інтерпретація має бути цікавою.

Таким чином, ми розглянули основи аналізу текстових даних в R. Однак R і пакет tm пропонують масу різних маніпуляцій з текстами, застосування яким ще можна знайти.