Использование R для анализа и визуализации данных


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

По сути, чтобы получить подобный отчет нам надо будет написать три блока кода:

  1. Собрать данные со страниц сайта

  2. Подготовить таблицы и построить графики

  3. Подготовить текст и построить облака слов

Коротко опишем код по каждому блоку.

Сбор данных со страниц сайта

Используем библиотеку library('rvest'), чтобы иметь возможность загружать страницы сайта и разбирать их текст.

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

for (j in c(1:84)) {

Сформируем переменную, которая будет содержать адрес конкретной страницы сайта, которую мы хотим считать.

url <- paste0('https://www.strahnadzor.ua/comments/?page=', as.character(j))

Получим ее html-код в переменную webpage.

webpage <- read_html(url)

Далее нам необходимо понять в каком разделе страницы находятся данные с названием компании. Можно установить специализированное приложение, например, SelectorGadget (https://chrome.google.com/webstore/detail/selectorgadget/mhjhnkcfbdhnjickkkdbjoemdmbfginb). Но можно и просто выполнив команду inspect по правой кнопке мыши в Хроме.

В нашем случае название компании содержится в блоке '.feeling_х .date a'', где «х» обозначает оценку страхователя от 0 до 5. Так как нас эта оценка интересует, то откроем цикл

for (f in c(0:5)) { в котором будем на странице собирать отзывы в разрезе оценок и сохранять их вместе с названиями компаний.

Формируем строку с нужным блоком оценок

feeling_string<-paste0('.feeling_', as.character(f))

Формируем текст с названием нужного блока

paste(feeling_string, '.date a')

Копируем часть html-кода из нужной секции с помощью команды html_nodes(‘страница’,’секция’)

ic_data_html <- html_nodes(webpage,paste(feeling_string, '.date a'))

Извлекаем текст из html-кода (в нашем случае название компании) командой

ic_data <- html_text(ic_data_html)

Аналогично извлекаем город страхователя и другие данные

# город страхователя

reviewercity_data_html<-html_nodes(webpage,paste(feeling_string,'.date span:nth-child(5)'))

reviewercity_data <- append(reviewercity_data,html_text(reviewercity_data_html))

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

Так как на странице размещается по 10 отзывов, то откроем цикл

for (i in c(1:10)) {

и сформируем строку с адресом

urlreview <- paste0('https://www.strahnadzor.ua/comments/',reviewnumber_data[(j-1)*10+i])

Дальше аналогично. Считываем html-код и получаем нужные нам данные

webpagereview <- read_html(urlreview)

reviewtext_data_html<-html_nodes(webpagereview,'h1')

reviewtext_data1 <- html_text(reviewtext_data_html)

reviewtext_data<-append(reviewtext_data,reviewtext_data1[1])

Используем команду as.factor(), чтобы сделать часть данных категориальными, в частности данные с названиями страховых компаний, оценок страхователей и т.п.

# страховая компания

ic_data<-as.factor(ic_data)

После того, как собрали и подготовили все данные, формируем итоговую таблицу (dataframe)

review_df<-data.frame(q=qnt, id=reviewnumber_data, InsCompany=ic_data, RDate=reviewdate_data,

RTime=reviewtime_data, Name=reviewername_data, Feeling=feeling_data, FeelingText=feelingtext_data, Hour=hour_data, Minutes=minutes_data, Month=month_data, OMonth=ordered_month_data, CountMessage=countmessage_data, City=CityName, Subject=reviewtext_data, SubjectL=nchar(reviewtext_data, type = "chars"), Text=reviewfulltext_data, TextL=nchar(reviewfulltext_data, type = "chars"))

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

Подготовка таблиц и построение графиков

Я не буду здесь копипастить весь код R для подготовки данных и графиков. Приведу только несколько примеров.

Так как нам надо будет строить графики, где фигурируют ТОП-10 или ТОП-20 компаний, то заготовим табличку (текстовый вектор) с перечнем компаний с наибольшим количеством отзывов.

Считаем количество отзывов в разрезе СК. Сделать это можно многими способами, например так

Qnt_df<-aggregate(q ~ InsCompany, data = review_df, sum)

Сортируем по количеству отзывов

TopQnt<-Qnt_df[order(Qnt_df$q,decreasing = TRUE),]

Отбираем первые 10 записей. Они и будут ТОП-10 СК

TopQnt<-head(TopQnt,n=10)

Строим текстовый вектор из названий ТОП-10 СК

TopInsCompany<-TopQnt$InsCompany

Рассмотрим пример с построением графика распределения количества отзывов по времени суток

Чтобы его построить нам необходима таблица в которой бы содержались данные о количестве отзывов с оценками в разрезе времени суток. Создадим ее одной строчкой кода

HourFeeling_df<-aggregate(q~Hour+FeelingText, data= review_df, sum), где

review_df – исходная таблица со всеми данными

FeelingText – оценки страхователя в текстовом виде

  • '1. Автор восхищен'

  • '2. Автор доволен'

  • '3. Автор спокоен'

  • '4. Автор волнуется'

  • '5. Автор зол'

  • '6. Нет оценки'

Hour – час суток, когда был оставлен отзыв

Перейдем к построению графиков.

Будем использовать известную библиотеку ggplot2. О ней есть много информации в сети Интернет, так что не буду описывать все ее возможности.

library('ggplot2')

Разберем основные параметры кода для построения графика, который сохраним в переменную «p».

p <- ggplot(HourFeeling_df, aes(x = Hour, y = q, fill = FeelingText)) +

HourFeeling_df – таблица с данными, которую мы сформировали ранее одной строчкой кода. На этих данных и будет основан график.

x = Hour – по оси х будет откладываться время суток (часы)

y = q – по оси y будет откладываться количество отзывов

fill = FeelingText – для заполнения графика возьмем данные оценки страхователя

Таким образом мы сформировали основу для графика – базовый слой.

Сформируем теперь слой с графиком.

geom_bar(…, position = "stack", …) +

geom_bar – формирует столбчатую диаграмму

position = "stack" – означает, что категориальные данные с оценкой страхователя (FeelingText)надо расположить в столбик.

Если нам надо посчитать долю каждой оценки в течение часа, чтобы получить такой график

то просто меняем это параметр на «fill» geom_bar(…, position = " fill ", …) +

и получаем нужное.

Теперь «раскрасим» наш график. Для этого воспользуемся командой

scale_fill_brewer('',palette = "RdYlGn", direction = -1)+

которая означает, что для «раскраски» данных надо взять палитру "RdYlGn" из пакета ‘RColorBrewer’ и отображать ее в обратном порядке direction = -1

Мы выбрали именно такую палитру, так как данные у нас отображают оценку по шкале от хороших к плохим и данных у нас 6 категорий.

Детально палитру можно посмотреть по ссылке http://colorbrewer2.org/#type=diverging&scheme=RdYlGn&n=6

Если бы мы выполнили описанный код, то получили бы такой вот график

Но параметр времени «Hour» цикличен и нам показалось, что более интересно и наглядно его можно отобразить на «циферблате». Поэтому перейдем к другой системе координат командой

coord_polar(start = 0) +

где start = 0 указывает на начальное смещение в радианах от стартовой точки – 12 часов

Дальнейший код связан с «оформительством» и мало интересен

Сохраняем рисунок на диск командой

ggsave('HourFeeling_Q1.png', p, width = 7, height = 7, dpi=300)

Если будет интересен код любого другого графика из статьи «О чем говорят страхователи…», то задавайте вопрос на facebook.com/DDM.center.ua/ или в комментариях под статьей в блоге https://www.ddm.center/blog

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

Ранее в статье «О чем говорят в Игре Престолов» я уже описывал код R для получения облака слов. Чтобы не повторяться, здесь опишу только некоторые отличия.

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

Для начала сгруппируем оценки в два вектора

PositiveVector<-c('1. Автор восхищен', '2. Автор доволен', '3. Автор спокоен')

NegativeVector<-c('4. Автор волнуется', '5. Автор зол', '6. Нет оценки')

Из нашей общей таблицы сформируем два текстовых блока, отбирая оценки, которые входят в первый и во второй векторы

PositiveFeelingFullText_df<-filter(insur_df, FeelingText %in% PositiveVector)

NegativeFeelingFullText_df<-filter(insur_df, FeelingText %in% NegativeVector)

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

PositiveDoc<-enc2utf8(tolower(paste(as.vector(PositiveFeelingFullText_df$Text),collapse = " ")))

NegativeDoc<-enc2utf8(tolower(paste(as.vector(NegativeFeelingFullText_df$Text),collapse = " ")))

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

dv<-c(PositiveDoc,NegativeDoc)

docs <- data.frame(docs = dv, row.names=c('Positive','Negative'))

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

ds <- DataframeSource(docs)

articles<-Corpus(ds,readerControl = list(reader = readPlain, language = "ru",load = T))

Дальше стандартная очистка данных и подготовка матрицы для построение облака слов.

tdm <- TermDocumentMatrix(articles,control = list(tokenize=scan_tokenizer))

m <- as.matrix(tdm)

v <- sort(rowSums(m),decreasing=TRUE)

d <- data.frame(word = names(v),freq=v)

Ну и, собственно, облако

wordcloud2(d, size = 1,minRotation = pi/6, gridSize =0, maxRotation = -pi/6, rotateRatio = .7,color=pal, backgroundColor="seashell", shape = 'circle', widgetsize=c(900,480))

Также строим сравнительное облако слов

colnames(m) <- c("Позитивные оценки","Негативные оценки")

comparison.cloud(m,scale=c(8,1),max.words=1500, random.order=FALSE,rot.per=.1, colors=pal1, use.r.layout=TRUE,title.size=3)

Кому интересно, можно еще такую вот дендрограмму построить

my.df <- as.data.frame(inspect(tdm))

my.df.scale <- scale(my.df)

d <- dist(my.df.scale,method="euclidean")

fit <- hclust(d, method="ward.D2")

plot(fit)

Надеюсь, эта статья была интересной и может быть даже полезной

Загрузите отчет в pdf-формате

#анализтекстов #Облакослов #R #визуализация #данные

Избранные посты
Недавние посты
Архив
Поиск по тегам
Тегов пока нет.
Мы в соцсетях
  • Facebook Basic Square
  • Twitter Basic Square
  • Google+ Basic Square
НАВИГАЦИЯ
КОНТАКТЫ

info@DDM.center

Телефон: +380 67 341 7101

  • LinkedIn - White Circle
  • Facebook - White Circle
  • Twitter - White Circle

© 2017 DDM.center