Матрунич Консалтинг

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

Author: Александр Матрунич (Page 1 of 6)

Gramps: приложение для исследований и анализа в генеалогии

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

Приложение Gramps разрабатывается сообществом, распространяется свободно, доступно для любых операционных систем, исходный программный код открыт. Базовый язык программы — английский, но интерфейс переведён на многие языки, включая русский. Хотя иногда вы можете столкнуться с ситуацией, когда какой-то из специфических отчётов или расширений на русский переведён не полностью (здесь, кстати, вы можете помочь, но это тема отдельного разговора).

Структура, лежащая в основе Gramps, серьёзная и достойна важного сотрудника Российской академии наук. Основные логические элементы программы — это люди, события, места, цитаты, заметки и файлы. Они являются нитями, которые переплетены между собой, и этот “вязанный свитер” составляет историю вашей семьи.

Главное окно Gramps на вкладке Люди.

Главное окно Gramps на вкладке Люди.

Записи о людях и отношениях между ними

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

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

Записи о событиях

События — это записи о том, когда-то что-то с кем-то произошло, и мы хотим это зафиксировать. Ключевая информация о событии включает его тип, описание, место, время и человека, с ним связанного. Любые из указанных элементов могут быть упущены, если они не известны.

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

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

Записи о местах

Запись о месте указывает, где произошло то или иное событие. Место имеет собственное название, тип (город, деревня, страна) и географические координаты. Место может быть частью другого места: например, деревня входит в волость, которая входит в район, который входит в область, которая входит в страну. С началом межпланетных перелётов придётся указывать и планету 🙂

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

Цитаты, источники, хранилища

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

Цитата — это конкретная часть источника, например, с определённой страницы. Может быть сделано несколько цитат из разных частей документа. Одна и та же цитата может подтверждать сразу несколько фактов или событий.

Хранилище объединяет группу источников. Например, у вашей бабушки есть коробка с фотоальбомами и семейными документами. Вы можете создать источник, который так и будет называться: “Коробка у бабушки”. Далее в нём будет несколько источников: жёлтый фотоальбом, фотоальбом деда “ДМБ 1956” и мешочек с письмами и документами. В жёлтом фотоальбоме есть фотография бабушки на фоне входа на фабрику “Красный треугольник”, а в мешочке — грамота с того же предприятия. Фотография будет цитатой из альбома, грамота — из мешочка для подтверждения работы бабушки на фабрике.

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

Файлы в альбомах

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

Отчёты и книги

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

Мы можем сфокусироваться на отдельном человеке, на его предках или потомках, на определённом событии (кто его участники и свидетели) или на географическом месте (что, с кем и когда происходило в этой деревне).

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

Часть отчётов идёт “в коробке” вместе с Gramps. Это самые популярные отчёты, и они точно переведены на русский язык. Другая часть доступна в виде расширений к Gramps, их нужно скачивать дополнительно (средствами самой программы). Если же вы не смогли найти ничего подходящего, то что-то специальное нужно очень сильно, тогда есть смысл изучить, как в Gramps можно делать свои собственные шаблоны отчётов.

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

Советы начинающим

Как записывать отчество и отображать его на отечественный лад

Необычным для русскоязычного пользователя будет то, что в отличие от имени и фамилии, для отчества не выделено отдельного поля. Оно попадает в группу “множественных фамилий” с типом имяобразования “отчество” (или “патроним”, то есть родовое имя). Не стоит пугаться, после добавления двух-трёх отчеств вы привыкните. Авторы выбрали такое решение, поскольку отчество присутствует не во всех культурах, и не для каждой страны отдельное поле под него будет актуально. Кстати, помимо отчества в программе доступна ещё целая дюжина типов имяобразований. В истории моей семьи пригодился тип “матроним”, что можно вольно назвать “матчество”: человек для образования своего отчества выбрал имя матери.

Если не смогли разобраться, посмотрите пошаговую инструкцию в Викиучебнике. Я рекомендую использовать именно второй способ, то есть не объединять имя с отчеством в одной строке. Это позволит вам проводить поиск по отчеству, а также скрывать или отображать отчество в отчётах.

Как начинать работать в Gramps

История семьи — это запутанное дело, и не для каждой ситуации есть только один правильный вариант фиксации. Поэтому не стремитесь с самого начала всё делать “правильно”, просто обращайте внимание, какие особенности есть у того или иного подхода. Позже вы сможете выбрать лучший вариант.

А ещё позднее история расставит всё по местам. Главное — это успеть её записать.

Визуальная диагностика простой линейной регрессии с ggvis

Продолжаю тему с однофакторым регрессионным анализом в R. Теперь мне интересно применить инструменты визуализации, доступные в R-библиотеке ggvis, для диагностики регрессионной модели. Здесь же мы применяем перенаправление с помощью функции %>%.

Напомню, что я использую данные, сопровожающие книгу An Introduction to Statistical Learning with Applications in R. Подготовка данных и построение модели было произведено в предыдущей публикации. Так что будем считать, что мы продолжаем творить в пространстве той публикации.

Нелинейность взаимосвязи

data.frame(predict = predict(autolm),
           resids  = residuals(autolm)) %>%
  ggvis(~predict, ~resids) %>% 
  layer_points() %>%
  add_axis("x", title = "Предсказанные значения") %>%
  add_axis("y", title = "Остатки") %>%
  layer_smooths(stroke := 'red')
Точечный график со сглаживанием в ggvis

Точечный график со сглаживанием в ggvis

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

Корреляция остатков

data.frame(id = seq_len(dim(Auto)[1]),
           resids  = residuals(autolm)) %>%
  ggvis(~id, ~resids) %>% 
  layer_paths() %>%
  add_axis("x", title = "Порядковый номер наблюдения") %>%
  add_axis("y", title = "Остатки")
Визуальная оценка взаимосвязи остатков

Визуальная оценка взаимосвязи остатков

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

Непостоянная дисперсия остатков

data.frame(predict = predict(autolm),
           rstuds  = rstudent(autolm)) %>%
  ggvis(~predict, ~rstuds) %>% 
  layer_points() %>%
  add_axis("x", title = "Предсказанные значения") %>%
  add_axis("y", title = "Стьюдентизированные остатки")
Стьюдентизированные остатки и предсказанные значения: точечный график в ggvis

Стьюдентизированные остатки и предсказанные значения: точечный график в ggvis

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

autolm1 <- update(autolm, log(.) ~ .)
data.frame(predict = predict(autolm1),
           rstuds  = rstudent(autolm1)) %>%
  ggvis(~predict, ~rstuds) %>% 
  layer_points() %>%
  add_axis("x", title = "Предсказанные значения (log)") %>%
  add_axis("y", title = "Стьюдентизированные остатки")
Точечный график стьюдентизированных остатков и натурального логарифма предсказанных значений

Точечный график стьюдентизированных остатков и натурального логарифма предсказанных значений

Выбросы

Auto %>%
  mutate(rstud = ifelse(abs(rstudent(autolm)) > 3, 'Больше 3', 'Не больше 3'),
         label = row.names(Auto),
         label = ifelse(rstud == 'Больше 3', label, '')) %>% 
  ggvis(~kpl, ~ horsepower, fill = ~rstud) %>%
  layer_points() %>%
  add_axis("x", title = "Километров на литр") %>%
  add_axis("y", title = "Лошадиных сил") %>%
  add_legend("fill", title = "Стьюд.остатки") %>%
  layer_model_predictions(stroke := "red", model = 'lm') %>%
  layer_text(text := ~label, dy := -5, dx := 5)
Визуальное определение предикатов-выбросов

Визуальное определение предикатов-выбросов

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

Точки с избыточным влиянием на модель (High Leverage Points)

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

data.frame(leverage = hatvalues(autolm),
           rstuds  = rstudent(autolm),
           label = row.names(Auto)) %>%
  mutate(label = ifelse(leverage > .025, label, '')) %>% 
  ggvis(~leverage, ~rstuds) %>% 
  layer_points() %>%
  add_axis("x", title = "Leverage") %>%
  add_axis("y", title = "Стьюдентизированные остатки") %>%
  layer_text(text := ~label, dy := -5, dx := 5)
Точечный график с оценкой влияния наблюдений на модель

Точечный график с оценкой влияния наблюдений на модель

Обогащённая графика с диагностикой модели

data.frame(predict = predict(autolm),
           resids  = residuals(autolm),
           rstuds  = rstudent(autolm),
           leverage = hatvalues(autolm)) %>%
  ggvis(~predict, ~resids, fill = ~abs(rstuds), size = ~leverage) %>% 
  layer_points() %>%
  add_axis("x", title = "Предсказанные значения") %>%
  add_axis("y", title = "Остатки")  %>%
  add_legend("size", title = "Влияние на модель") %>% 
  add_legend("fill", title = "Модуль стьюд.ост.", 
             properties = legend_props(legend = list(y = 100)))
График, обобщающий оценку модели: выбросы, влияние отдельных значений, нелинейность взаимосвязи

График, обобщающий оценку модели: выбросы, влияние отдельных значений, нелинейность взаимосвязи

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

Отчётливо видно, что наблюдения с наибольшим влиянием встречаются в том секторе, где наблюдения встречаются реже.

Однофакторный линейный регрессионный анализ в R

На основе книги An Introduction to Statistical Learning with Applications in R авторов Gareth James, Daniela Witten, Trevor Hastie и Robert Tibshirani. Бесплатная копия книги в PDF-формате, или заказ бумажной копии книги на Amazon.

library(ISLR)
library(ggvis)
library(dplyr)

Подготовка данных

Работаем с массивом Auto из пакета ISLR.

# Загружаем массив Auto в пространство пользователя
data(Auto)

# Структура массива
str(Auto)
## 'data.frame':    392 obs. of  9 variables:
##  $ mpg         : num  18 15 18 16 17 15 14 14 14 15 ...
##  $ cylinders   : num  8 8 8 8 8 8 8 8 8 8 ...
##  $ displacement: num  307 350 318 304 302 429 454 440 455 390 ...
##  $ horsepower  : num  130 165 150 150 140 198 220 215 225 190 ...
##  $ weight      : num  3504 3693 3436 3433 3449 ...
##  $ acceleration: num  12 11.5 11 12 10.5 10 9 8.5 10 8.5 ...
##  $ year        : num  70 70 70 70 70 70 70 70 70 70 ...
##  $ origin      : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ name        : Factor w/ 304 levels "amc ambassador brougham",..: 49 36 231 14 161 141 54 223 241 2 ...
# Первые строки массива
head(Auto)
##   mpg cylinders displacement horsepower weight acceleration year origin
## 1  18         8          307        130   3504         12.0   70      1
## 2  15         8          350        165   3693         11.5   70      1
## 3  18         8          318        150   3436         11.0   70      1
## 4  16         8          304        150   3433         12.0   70      1
## 5  17         8          302        140   3449         10.5   70      1
## 6  15         8          429        198   4341         10.0   70      1
##                        name
## 1 chevrolet chevelle malibu
## 2         buick skylark 320
## 3        plymouth satellite
## 4             amc rebel sst
## 5               ford torino
## 6          ford galaxie 500
# Конвертируем миль (1.609 км) на галлон (3.79 л) в км на литр
Auto$kpl <- Auto$mpg * 1.609 / 3.79

Построение модели

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

  1. Существует ли взаимосвязь между мощностью и пробегом.
  2. Насколько сильна взаимосвязь между мощностью и пробегом.
  3. Взаимосвязь между мощностью и пробегом прямая или обратная.
  4. Каково прогнозное значение пробега на километр при мощности 98 лошадиных сил. Каковы 95% доверительный интервал и интервал предсказания.
# Задаем модель
autolm <- lm(kpl ~ horsepower, data = Auto)

# Результаты анализа
summary(autolm)
## 
## Call:
## lm(formula = kpl ~ horsepower, data = Auto)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -5.761 -1.384 -0.146  1.173  7.185 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 16.95430    0.30461    55.7   <2e-16 ***
## horsepower  -0.06701    0.00274   -24.5   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.08 on 390 degrees of freedom
## Multiple R-squared:  0.606,  Adjusted R-squared:  0.605 
## F-statistic:  600 on 1 and 390 DF,  p-value: <2e-16

Коэффициент horsepower составляет -0.067, т.е. при увеличении мощности автомобиля на одну лошадиную силу пробег снижается на 0.07 км на литр топлива. Наличие этой взаимосвязи подтверждается p-значением t-статистики: t равен -24.5, а вероятность получить такое значение t при независимых переменных (т.е. p-значение) стремится к нулю (<2e-16).

Прогнозирование

# Прогнозируем пробег при мощности 98 л.с.
# Доверительный интервал
confint <- predict(autolm,
                   newdata = data.frame(horsepower = 98),
                   interval = 'confidence')
confint
##     fit   lwr  upr
## 1 10.39 10.18 10.6

Если мы возьмём несколько разных автомобилей с мощностью двигателя 98 л.с., то средний пробег этих машин на литр топлива с вероятностью 95% попадёт в интервал от 10.2 до 10.6 км.

# Интервал предсказания
predint <- predict(autolm,
                   newdata = data.frame(horsepower = 98),
                   interval = 'prediction')
predint
##     fit   lwr   upr
## 1 10.39 6.287 14.49

Если мы возьмём какой-то конкретный автомобиль с мощностью двигателя 98 л.с., то его пробег на литр топлива с вероятностью 95% попадёт в интервал от 6.3 до 14.5 км.

Auto %>% 
  ggvis(~horsepower, ~kpl) %>%
  layer_points() %>%
  layer_model_predictions(model = 'lm', se = T)

Точечный график и линия тренда

Диагностика

После построения регрессионной модели имеет смысл проверить наличие следующих проблем:

  1. Нелинейная взаимосвязь между независимыми и зависимой переменными.
  2. Корреляция остатков между собой.
  3. Непостоянная дисперсия остатков (гетероскедастичность).
  4. Наличие выбросов.
  5. Избыточное влияние отдельных наблюдений.
  6. Коллинеарность предикатов.
par(mfrow = c(2, 3))
plot(autolm, which = 1:6, caption = 
       list("Прогноз и остатки", "Квантили", "Разброс-Положение",
            "Расстояние Кука", "Влияние и остатки", 
            expression("Влияние и Кук " * h[ii] / (1 - h[ii]))))
Визуальная диагностика регрессионной модели

Визуальная диагностика регрессионной модели

Точечный график предсказанных значений и остатков позволяет обнаружить закономерности распределения последних. График квантилей помогает определить нормальность остатков. График “Разброс-положение” даёт возможность оценить монотонность распределения остатков (гетероскедастичность). С помощью графика “Остатки-влияние” можно определить точки с большим влиянием на модель.

Как определить длину пути между адресами

Проблема и цель проекта

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

Подбор инструментов

Преимущества свободных данных и софта

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

  • Проект подразумевает обработку данных для внутренних целей, а лицензионные договоры Google и Яндекса требуют использования их сервисов только для создания общедоступных публикаций в виде карт. Т.е. использование услуг этих компаний в нужных нам целях будет незаконным. Конечно, вероятность того, что Яндекс обратит внимание на незначительную нагрузку, которую мы генерируем, очень мала. Но с точки зрения развития бизнеса или его продажи в будущем, лучше сразу отказаться от включения в работу предприятия заведомо нелегальных алгоритмов.
  • В процессе работы будут постепенно «всплывать» ошибки в используемой базе данных: например, какие-то адреса будут неправильно преобразовываться в координаты. Если мы работаем на основе картографического сервиса Яндекса, то в случае обнаружения ошибок (в нашем опыте такие ошибки у Яндекса были), каждый ошибочный адрес придётся обрабатывать как исключение, поскольку сам Яндекс по нашему запросу исправит эти ошибки только через несколько месяцев. При использовании данных из базы OpenStreetMap, мы можем сами внести исправление в базу, и оно практически сразу станет доступно для нашего приложения.
  • При необходимости внести какие-либо изменения в работу алгоритмов по геокодированию или прикладке маршрутов, мы можем отказаться от использования открытого API, а запустить эти сервисы на своём оборудовании, поскольку и база данных дорожной сети, и программное обеспечение доступны на условиях свободных лицензий.

Схема работы

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

  1. Геокодирование, т.е. преобразование текстовой строки, содержащей адрес, в географические координаты.
  2. Прокладка маршрута и вычисление его длины.
Open Source Routing Machine

Open Source Routing Machine

Геокодирование российских адресов

Международный сайт OpenStreetMap.org для геокодирования использует программу Nominatim. У нас есть опыт работы с API Nominatim через статистический пакет R. Исходные коды R-скриптов доступны в репозитории на github.

Для национального проекта OpenStreetMap.ru разработано собственное приложение для поиска адресов и точек интереса. Приложение «заточено» под специфику адресов в России, »понимает« нумерацию домов в духе »14 К2 С1« и может искать дома с двойным адресом. У поисковика доступно API, документация опубликована в форуме. Например, для определения координат дома по адресу «Псков, Маркса, 23» следует отправить запрос вида http://openstreetmap.ru/api/search?q=Псков, Маркса, 23. Ответ вернётся в формате JSON, координаты хранятся в полях lat и lon.

Для снижения количества ошибок геокодирования и уменьшения объёма лишней информации в ответе в строку запроса рекомендуется добавить параметры точки начала поиска (координаты центра города; аргументы запроса lat и lon), поиск только по адресам (stype=addr), количество ответов установить равным 1 (cnt=1).

Прокладка маршрута

Корифей OpenStreetMap и ведущий новостного блога ШТОСМ Илья Зверев порекомендовал использовать для маршрутизации Open Source Routing Machine. У разработчиков запущен демо-сервер с доступным API (Илья просил не более 20 запросов в минуту, также существует ряд требований).

Предположим, мы хотим узнать длину маршрута между адресами Маркса, 23 и Рижский, 69 в городе Пскове. Через API OpenStreetMap.ru мы узнаём координаты:

Маркса, 23
57.818023681640625, 28.342592239379883
Рижский, 69
57.812679290771484, 28.28318214416504

Полученные координаты мы отправляем на API Open Source Routing Machine в виде запроса http://router.project-osrm.org/viaroute?loc=57.818023681640625,28.342592239379883&loc=57.812679290771484,28.28318214416504. Ответ приходит в формате JSON, в поле total_time содержится предполагаемое время на дорогу (в нашем случае 467 секунд), в поле total_distance — длина маршрута (4582 метра).

OSRM позволяет прокладывать маршрут сразу между последовательностью точек, но не более 25.

Подготовлено для кафе «Моя Италия»

Что такое грамматика графики ggplot2 (ч.3)

Вы открыли продолжение статьи об основах ggplot2. Читайте начало в

  1. Что такое грамматика графики ggplot2 (ч.1)
  2. ggplot2: сопоставления, визуальные средства, статистические преобразования и слои

Подписи осей графика в ggplot2

Снова вернёмся к начальному графику из первой части:

fig <- ggplot(data = cars, aes(x = speed, y = dist)) + geom_point()
fig

ggplot(data = cars, aes(x = speed, y = dist)) + geom_point()

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

Ggplot2 автоматически взял названия для осей из имён переменных, которые мы использовали для построения графика. Авторы ggplot2 предлагают сразу несколько вариантов того, как можно изменить названия осей. Можно использовать функции ylab(), xlab():

fig + xlab("Скорость, миль в час") +
  ylab("Тормозной путь, футы")
ggplot(data = cars, aes(x = speed, y = dist)) + geom_point() + xlab("Скорость, миль в час") + ylab("Тормозной путь, футы")

ggplot(data = cars, aes(x = speed, y = dist)) + geom_point() + xlab("Скорость, миль в час") + ylab("Тормозной путь, футы")

Аналогично можно использовать функцию labs():

fig + labs(x = "Скорость, миль в час",
           y = "Тормозной путь, футы")

Здесь мы получим аналогичный график, поэтому не привожу его.

Следующий вариант будет удобен, если помимо названия вы хотите сделать в оси дополнительные изменения: например, изменить расположение основных и вспомогательных линий сетки, задать собственный диапазон значений оси. В нашем случае функция для определения этих параметров называется scale_x_continuous(). К чему такое сложное название функции? Давайте вспомним про то, что пакет ggplot2 — это не очередное R-расширение для создания диаграмм, а целая концепция графической грамматики. И с этой точки зрения, подпись горизонтальной оси — это не просто текстовая строка, расположенная под абсциссой, а элемент инструкции (guide), которая призвана помочь человеку, смотрящему на график, правильно понять, что за информация передаётся с помощью горизонтальной оси. Поэтому логично поместить все параметры одного элемента графика в одну функцию. А функции labs() и ylab()/xlab() — это лишь удобные ярлыки, созданные для уменьшения нагрузки на суставы ваших пальцев и клавиатуру.

Итак, пересилим себя и зададим названия осей с помощью функций scale_*:

fig + scale_x_continuous(name = "Скорость, миль в час") +
  scale_y_continuous(name = "Тормозной путь, футы")

Расширим наше использование scale_* и «поиграем» с характеристиками осей.

fig + scale_x_continuous(name = "Скорость, миль в час",
                         breaks = c(7, 10, 20),
                         limits = c(6, 22)) +
  scale_y_continuous(name = "Тормозной путь, футы",
                     limits = c(5, 50),
                     breaks = NULL)
Точечный график ggplot2 с модификацией осей через scale_continuous()

Точечный график ggplot2 с модификацией осей через scale_continuous()

Здесь по горизонатальной оси мы «обрезали» края графика, выходящие за пределы менее 6 и более 22 миль в час, и указали, чтобы линии сетки проходили только по точкам 7, 10 и 20 миль в час. Аналогичная операция проведена для вертикальной оси, только целиком убраны горизонтальные линии сетки и соответствующие подписи.

Работа с легендами графика

Добавим к графику цвет.

fig2 <- ggplot(data = cars, aes(speed, dist, color = speed)) + geom_point()
fig2
Точечный график ggplot2 с окраской точек

Точечный график ggplot2 с окраской точек

Обратите внимание, я не стал в функции aes() указывать названия аргументов x и y. Так можно делать, так как, если вы не указываете в aes() имена первых двух аргументов, то aes() «думает», что первым аргументом является положение по горизонтали, а вторым — по вертикали.

Чтобы задать собственное название легенды, мы опять обращаемся к функции из семейства scale_*.

fig2 + scale_color_continuous("Скорость") #Снова не указываю имя аргумента
Точечный крафик ggplot2 с исправленным названием цветовой легенды

Точечный крафик ggplot2 с исправленным названием цветовой легенды

Название графика

Название графика можно добавить одной из двух функций: ggtitle() или labs().

fig2 + scale_color_continuous("Скорость") +
  ggtitle("Влияние скорости автомобиля\nна длину тормозного пути") +
  xlab("Скорость, миль в час") +
  ylab("Тормозной путь, футов")
График ggplot2 с названием, именованными осями и легендой

График ggplot2 с названием, именованными осями и легендой

Дополнительную информацию о настройке внешнего вида графика можно почерпнуть на англоязычном сайте одного из разработчиков ggplot2 Уинстона Чанга Cookbook for R

Вы прочитали продолжение статьи. Начало читайте в:

  1. Что такое грамматика графики ggplot2 (ч.1)
  2. ggplot2: сопоставления, визуальные средства, статистические преобразования и слои

Что такое грамматика графики ggplot2 (ч.2)

Продолжение. Читайте начало в Что такое грамматика графики ggplot2 (ч.1)

Читайте продолжение в Названия элементов графика ggplot2: название графика, осей, легенд

Визуальные средства и геометрические объекты

Визуальные средства для отрисовки геометрических объектов типа «точка» (point) — это расположение по горизонтали (x) и вертикали (y), цвет границы (colour) и цвет заливки (fill), размер (size), форма (shape), прозрачность (alpha). Обязательными для создания точечного графика являются только первые два параметра: положение по вертикали и горизонтали. В примере с автомобилями мы привязали скорость к положению по горизонтали, а тормозной путь — к положению по вертикали. Оставшиеся визуальные средства можно было бы использовать для передачи на графике другой информации, если бы она содержалась в исходном массиве данных cars. Или мы можем продублировать информацию, передаваемую через положение, другими визуальными средствами. «Нагрузим» цвет точки скоростью.

ggplot(data = cars, aes(x = speed, y = dist, color = speed)) + geom_point()
ggplot(data = cars, aes(x = speed, y = dist, color = speed)) + geom_point()

ggplot(data = cars, aes(x = speed, y = dist, color = speed)) + geom_point()

Алгоритм определил, что speed — это числовая (интервальная) переменная и, по умолчанию для этого типа, предложил палитру в виде градации от тёмно-синего до голубого. Чем выше скорость, тем светлее точка. Также, поскольку наш график «обзавёлся» дополнительной информацией, передаваемой через цвет, то алгоритм сам добавил в картинку легенду со значениями цвета. В наших силах также выбрать другую цветовую палитру, дать другое название легенде и разместить легенду в другом месте графика, но сейчас не будем на это отвлекаться.

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

ggplot(data = cars, aes(x = speed, 
                        y = dist, 
                        color = speed, 
                        size = dist)) + geom_point()
ggplot(data = cars, aes(x = speed, y = dist, color = speed, size = dist)) + geom_point()

ggplot(data = cars, aes(x = speed, y = dist, color = speed, size = dist)) + geom_point()

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

Статистические преобразования

Вернёмся к самому первому графику из первой части:

ggplot(data = cars, aes(x = speed, y = dist)) + geom_point()

ggplot(data = cars, aes(x = speed, y = dist)) + geom_point()

В этом примере схема построения графика на первый взгляд выглядит так:

  1. Берётся массив данных cars.
  2. Переменная speed сопоставляется положению по горизонтали (абсциссе), переменная dist — положению по вертикали (ординате).
  3. На графике отображаются точки с соответствующими координатами.

Между вторым и третим пунктом остался незамеченным важный элемент: статистическое преобразование данных. Подход ggplot2 подразумевает, что для отрисовки графического объекта исходные данные нужно преобразовать. Например, для перед построением гистограммы алгоритм соответствующего статистического преобразования должен посчитать, сколько наблюдений попадает в каждый интервал, а затем передать данные о границах каждого интервала и о количестве элементов в алгоритм построения геометрического объекта. В нашем случае, когда рисуются точки, данные никак преобразовывать не нужно, поэтому на этапе преобразования используется stat_identity() — тождественное преобразование, то есть без изменений.

Взглянем на распределение длин тормозных путей и построим график, требующий более сложных вычислений: «Ящик с усами». Он покажет нам информацию о медиане, квартилях и наличии выбросов. Поскольку график такого типа удобно использовать для сравнения групп, то мы разделим наш массив на две группы: в первой автомобили, у которых скорость 15 миль в час и меньше, а во второй — у кого больше.

ggplot(data = cars, aes(x = speed > 15, y = dist)) + geom_boxplot()
ggplot(data = cars, aes(x = speed > 15, y = dist)) + geom_boxplot()

ggplot(data = cars, aes(x = speed > 15, y = dist)) + geom_boxplot()

Более полная схема построения графика следующая:

  1. Берётся массив данных cars.
  2. Результат выполнения выражения cars$speed > 15 сопоставляется абсциссе, переменная dist — ординате. При этом абсцисса (x) из числовой переменной (мили в час) превратилась в категориальную (логическую: больше 15 миль в час или нет), поэтому все наблюдения разбились на эти две категории.
  3. Данные передаются статистическому преобразованию stat_boxplot(), которое из предыдущего шага знает, что cars$speed > 15 нужно использовать для деления массива на группы, а dist — для расчёта статистик, необходимых для отрисовки «ящиков с усами».
  4. Результаты работы stat_boxplot(), а это для каждой группы медиана, квартили, границы нижнего и верхнего «усов», передаются алгоритму отрисовки.

Нам не понадобилось явно задавать stat_boxplot() в коде, т.к. это статистическое преобразование вызывается по умолчанию при отрисовке «ящиков с усами». Явно указывать статистику имело бы смысл в такой ситуации, когда наш массив уже содержит все необходимые данные для geom_boxplot() (медиану, квартили и пр.), и мы бы захотели изменить способ статистического преобразования: geom_boxplot(stat="identity")

Слои графика

Каждый раз, когда вы в R добавляете к своему ggplot2-объекту новые geom_*() или stat_*(), на вашем графике появляется новый слой. Добавим к нашим «ящикам» слой с точками.

ggplot(data = cars, aes(x = speed > 15, y = dist)) +
  geom_boxplot() + 
  geom_point()
ggplot(data = cars, aes(x = speed > 15, y = dist)) + geom_boxplot() + geom_point()

ggplot(data = cars, aes(x = speed > 15, y = dist)) + geom_boxplot() + geom_point()

Здесь сначала по старой схеме были отрисованы «ящики», а затем на основе тех же самых данных, тех же самых сопоставлений добавлены точки.

Читайте первую часть статьи в Что такое грамматика графики ggplot2 (ч.1)

Читайте продолжение статьи в Названия элементов графика ggplot2: название графика, осей, легенд

Оптимизация расходов на услуги сотовой связи (черновик)

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

Управленческая проблема

Я задался вопросом, схожим с тем, который мучил интервьюеров, когда решил сменить мой текущий тарифный план «Дело чести» от «Теле2» на что-нибудь свеженькое. Принимать решение «на основе интуиции» не хочется, когда под боком есть статистические данные, и можно принять data-driven decision («решение на основе данных»). Подобная задача может стать перед организацией, которая хочет оптимизировать расходы на связь подбором более выгодных тарифов.

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

Программа исследования

Проблема и цель исследования

Минимум
Проблема заключается в том, что клиенту неизвестно, какой из предлагаемых тарифов позволит понести наименьшие затраты. Цель — определить такой тариф. Поскольку проект пилотный, а, к тому же, я не собираюсь менять своего оператора, то остановимся на тарифах только от Теле2.
Максимум
Непонятно, какие технические трудности могут появиться при реализации идеи по подбору тарифа в виде вэб-сервиса. Цель — в процессе работы над пилотным проектом рассмотреть возможности его переноса на бизнес-рельсы.

Объект, предмет и выборочная совокупность

Объектом исследования становится использование мной услуг сотовой связи. Предмет — различия в среднемесячной стоимости услуг при их расчёте по разным тарифам Теле2.

В качестве выборки мы возьмём мою историю звонков/сообщений и трафика за апрель 2014 года.

Схема моделирования и анализа

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

Чтобы определить выгодный тариф для моего «усреднённого» месяца, нам потребуется перенести выводы эксперимента с выборочной выборки (апрель 2014) на генеральную совокупность. Для этого мы воспользуемся методом Bootstrapping.

Вся обработка данных, расчёты и визуализация произведены на языке программирования R. Исходный код скриптов опубликован в репозитории на github.

Результаты пилотного исследования

Перспективы создания веб-сервиса или предложения услуги по выбору тарифа

Приложение: описание резализации пилотного проекта

Подготовка данных

Подготовка данных обычно занимает самую большую часть времени. Наш проект — не исключение.

Преобразование PDF в Excel

Истончиком данных послужила детализация расходов (стоимость — 15 рублей). Рассматривался вариант использования истории напрямую из телефона, но у детализации от оператора есть преимущества: в документе указываются сведения о стоимости каждой операции, и это позволяет проверить, правильно ли работает наш алгоритм, а также гораздо проще разобраться, находился ли телефон в роуминге, на какой телефон совершён вызов (на псковский Теле2 или на Теле2 в соседнем регионе и пр.). Плюс к этому, из истории телефона не вытащишь посессионные объёмы трафика (по крайней мере, из моего).

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

Первые строки массива после импорта в R приведены ниже. Все телефонные номера заменены на случайные.

> head(data)
                  date       plan                 type             number seconds  sum  pay
1  2014-04-01 08:42:48 Дело чести      Internet-трафик Трафик: 13915 байт      NA 0.63 0.10
2  2014-04-01 08:43:54 Дело чести      Internet-трафик Трафик: 53514 байт      NA 0.63 0.10
3  2014-04-01 09:00:05         БВ         Входящее SMS       +12468335597       0 0.00 0.00
4  2014-04-01 09:26:15 Дело чести Исходящий на Мегафон       +79211162647      14 0.35 0.35
5  2014-04-01 10:29:36         БВ         Входящее SMS               7031       0 0.00 0.00

Перенос выводов о выгодности от конкетного месяца на «усреднённый» месяц

Суть метода «бутстреп» заключается в том, что из всей моей апрельской истории (в ней 520 телефонных событий) случайным (вероятностным) образом составляется множество (несколько тысяч) выборок объёмом 520 элементов. Каждый элемент может попасть в выборку несколько раз или не попасть вообще. Т.е. мы получаем массив из нескольких тысяч выборок, которые почти одинаковы, но немного (а иногда сильно) отличаются друг от друга. Другими словами, мы создали несколько тысяч альтернатив моему «телефонному» апрелю 2014 года. Поскольку апрель, по моим ощущениям, в плоскости использования телефона не имел радикальных отличий от других месяцев (в апреле, как и в другие месяцы, я не звонил на спутниковые телефоны, не болтал часами в международном роуминге, не отправлял SMS в какие-нибудь голосования), я могу с достаточной доли уверенности сказать, что многие из имеющихся сгенерированных выборок могли также быть получены и из других месяцев. Посчитав по каждой из нескольких тысяч выборок стоимость услуг для каждого из тарифов, мы можем определить среднюю цену моего месяца по тарифу и доверительные интервалы. Это даст нам возможность сравнить тарифы, понять, есть ли между ними значимые отличия и выбрать самый выгодный.

Если описание алгоритма Bootstrap показалось вам достаточно сложным, не переживайте: он реализован в R, и нам останется лишь передать данные и параметры подсчёта программе, а затем получить результаты.

Сравнение речей президентов России, Белоруссии и Украины с помощью облака слов

Сравнение поздравительных речей Путина, Лукашенко и Турчинова на День Победы

Сравним речи, которые произнесли руководители России, Белоруссии и Украины 9 мая 2014 года.
Сделаем это с помощью визуализации текстов в виде облака слов.

Облако слов со сравнением частот слов в речах Путина, Лукашенко и Турчинова

Облако слов со сравнением частот слов в речах Путина, Лукашенко и Турчинова

Как интерпретировать график? Размер шрифта, которым изображено слово, показывает относительную частоту, с которой данное слово встречалось в речи. Цвет показывает, в речи какого из президентов данное слово занимает наибольшую долю. Например, слово «победа» (и его формы) встречалось у Лукашенко 5 раз, у Путина – 3, у Турчинова – 5. Понятно, что слово должно попасть или к Лукашенко, или к Турчинову. Но у Лукашенко слово «победа» занимает 0,89% от массива учтённых слов, а у Турчинова – 2,8%, соответственно оно попадает в украинскую часть графика.

У Лукашенко много слов с маленьким размеров шрифта – это значит, что он говорил больше, чем остальные спикеры, размер словаря его выступления больше, и на каждое слово у белорусского президента приходится меньшая относительная частота. Действительно, у Лукашенко зафиксировано 562 слова, у Путина – 229, у Турчинова – 177.

Чем схожи выступления спикеров? Это можно проверить с помощью облака сходства. Здесь приведены слова, которые встречались одновременно у всех трёх выступающих. Чем больше размер шрифта, тем выше средняя доля встречаемости слова.

Облако сходства текстов выступлений Лукашенко, Путина и Турчинова на День Победы

Облако сходства текстов выступлений Лукашенко, Путина и Турчинова на День Победы

При подготовке из текстов выступлений были удалены стоп-слова (предлоги и пр.), а оставшиеся слова были приведены к исходной словоформе с помощью программы MyStem от компании Яндекс. Поскольку определение первичной словоформы происходит в автоматическом режиме без учёта контекста, некоторые слова преобразованы некорректно. Например, слово «дуг» в речи Путина в оригинале звучало как «Дуге». Обработка данных произведена в среде статистической обработки данных R. Более подробно о создании графиков в виде облака слов можно ознакомиться в публикации Обработка естественно-языковых текстов в R: облако слов.

Источники информации

Обработка естественно-языковых текстов в 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)
Облако слов из новостей о Псковском городском молодёжном центре

Облако слов из новостей о Псковском городском молодёжном центре

Как выбрать и зарегистрировать имя для сайта

Как работает система имен DNS

Любой компьютер или другое цифровое устройство при подключении к Интернету получает уникальный адрес. Нам, обычным пользователям, привычен адрес в виде доменного имени, например, matrunich.com. Но для самих компьютеров и серверов родным является цифровой адрес IP (Internet Protocol), который (в 4-й версии) состоит из четырёх чисел от 0 до 255. Для matrunich.com таким адресом является 192.185.41.207. Естественно, запомнить адрес matrunich.com человеку проще, чем набор из четырёх чисел (более того, в IP версии 6, которая постепенно приходит на смену IP версии 4, набор чисел будет на несколько порядков больше).

Именно для удобства пользователей ещё на заре становления Интернета было предложено ввести возможность создавать для серверов, в дополнение к числовым адресам, легко запоминаемые имена. Сейчас эта система называется DNS – Domain Name System – система имён доменов. Слово domain на русский можно перевести как зона, область или более исторично: удел, владение, царство. Первая версия DNS появилась в 1983 году.

Далеко не каждый компьютер и не каждое цифоровое устройство обладают именем в DNS. Смысл регистрировать DNS-имя есть только для тех компьютеров и устройств, к которым будут постоянно обращаться пользователи с других компьютеров. Другими словами, вы можете зарегистрировать доменное имя и для своего смартфона, офисного или домашнего компьютера или роутера, но обычно в этом нет необходимости. [expand title=”Хотя, что-то в этом есть: сделать адрес в духе http://телефонматрунича.рф и запустить на своём телефоне маленький сайтик :)” targtag=”small”]Дополнительно для такого эксперимента по запуску сайта на своём телефоне мне придётся заплатить своему сотовому оператору, чтобы моему телефону выделили статический, т.е. постоянный, IP-адрес, платить за Интернет-трафик, который будут генерировать посетители сайтика, установить на телефон программу веб-сервера и постоянно держать её запущенной, чтобы сайтик был доступен круглосуточно. В итоге, вряд ли посетители сайта будут очень довольны, т.к. всё равно сайт будет достаточно медленным и не всегда доступным (например, когда телефон будет находится вне зоны покрытия). Для сайта проще зарегистрировать обычный, но дешёвый и надёжный веб-хостинг[/expand]

Схематично DNS – это таблица, в первой колонке которой записаны зарегистрированные доменные имена, а во второй – соответствующие этим именам IP-адреса. Когда пользователь набирает в браузере адрес matrunich.com, программа обращается к DNS-серверу и передаёт ему имя сайта. DNS-сервер ищёт в своей таблице такое имя и в ответе браузеру передаёт IP-адрес сайта. Далее браузер на полученный IP-адрес делает запрос: мол, пришлите мне вашу заглавную страницу. И так понеслось взаимодействие далее уже не на уровне DNS-имени, а с помощью IP-адресов.

Поскольку доменных имён очень много (например, в мае 2013 года общее количество имён оценивалось в 252 миллиона), а DNS-серверы есть как минимум у каждого Интернет-провайдера, то синхронизация такой мега-таблицы (вернее иерархической системы таблиц) между серверами происходит не сразу. Поэтому когда кто-то на одном краю земли зарегистрировал новое доменное имя, то информация о этом попасть в DNS-сервер, расположенный на другом краю земли, может в течение несколько дней. Т.е. какие-то пользователи смогут зайти на этот сайт сразу (кто пользуется тем же DNS-сервером, что и свежеиспечённый владелец имени), а какие-то – позже.

Структура доменного имени

Адрес сайта, или доменное имя, состоит как минимум из двух частей. Каждая часть отделяется точкой. Первая (справа) часть – это домен верхнего уровня. Примерами доменов верхнего уровня являются: ru, рф, co, uk, us, com, biz, org, info. Верхние домены, состоящие из двух букв, являются национальными, т.е. принадлежащими той или иной стране. В России сразу три нацдомена: ru, рф и su. Последний достался нам в наследство от СССР. У Украины домен ua, у Белоруссии – by, у Эстонии – ee.

Пользователь может зарегистрировать имя практически в любой доменной зоне. У разных стран свои правила выдачи доменных имен в своей национальной зоне. Впечатляющий список ссылок на правила регистрации доменных имён во всевозможных зонах первого уровня приведён на сайте компании RU-CENTER.

Какое доменное имя выбрать для своего сайта

Идеальное доменное имя легко запоминается клиентами.

Ваш бренд
Если у вашего бизнеса уже есть собственная торговая марка, то стоит включить её в название сайта.
География
Если ваше предприятие работает в определённом городе или регионе, и вы уверены, что вы не будете проводить в будущем территориальных экспансий, т.е. расширять свой бизнес на соседние города, то в доменное имя стоит включить название города.
Домен верхнего уровня
Если ваш бизнес работает в России, то, в первую очередь, пробуйте искать имена в зоне ru, поскольку большинство ваших клиентов будут ожидать, что сайт находится в этой зоне. Зону рф я бы использовал, как дополнительный домен. Если ваш бизнес нацелен на западные рынки или не имеет привязки к региону, ищите сначала имя в зоне com. Другие зоны используйте уже во вторую очередь.
Ключевые слова
Если предыдущих пунктов вам недостаточно, чтобы найти хорошее свободное имя, попробуйте добавить в имя ключевое слово. Сложным остаётся момент с транслитирацией русских слов в латиницу. В случае, если русское слово можно написать разными способами, я бы рекомендовал зарегистрировать все имеющиеся варианты. Благодаря этому вы не потеряете клиентов, которые транслитерируют русский в латиницу по-другому чем вы, а также обезопасите себя от недобросовестных конкурентов, которые могут создать сайт, имя которого похоже на имя вашего сайта, и будут забирать себе ваших клиентов, которые ошиблись в написании.
Не умничайте
Избегайте сложных слов. Чем проще и однозначнее пишется слово, тем лучше.
Проверка на уникальность и авторские права
Создавая сайт для своего бизнеса вы выходите с ограниченной территории своего города/области в громадное пространство Интернета. Резко возрастают шансы, что планируемое название вашего сайта сильно похоже на сайт совсем другого бизнеса за 2000 километров от вас. Чтобы не портить жизнь себе и людям, проверяйте.
Тёмное прошлое доменного имени
Существует некоторая вероятность, что домен, который вы хотите зарегистрировать, был зарегистрирован раньше, использован, а затем не продлён. Т.е. домен после неуплаты удалён, а ссылки на старый сайт в Интернете остались. И если прошлая версия сайта была совсем не о том, о чём будет ваш сайт, то наличие таких нетематических ссылок будет мешать. Проверить наличие таких ссылок можно в Google с помощью запроса типа link:matrunich.com. Замените matrunich.com на проверяемый адрес.
Долой минусы и цифры
Старайтесь не использовать в доменном имени дефисы и цифры: такие адреса сложнее воспринимать на слух (вдруг будуте рекламироваться на радио), да и набирать их сложнее.

Когда вы начнёте выбирать доменное имя, то столкнётесь с тем, что множество имён уже занято (та же самая ситуация, когда регистрируете бесплатный почтовый ящик). Это неудивительно: по данным АНО «Координационный центр национального домена сети Интернет» на 6 мая 2014 года было зарегистрировано 4933943 домена в зоне ru, и 819300 – в зоне рф. Чтобы не перебирать имена по отдельности, воспользуйтесь сервисом пакетной проверки доменов от регистратора REG.RU.

Стоимость регистрации домена

Как нам уже стало понятно, доменное имя – это всего лишь строка в таблицах DNS-серверов, сопоставляющая имя и IP-адрес. И когда вы платите за регистрацию, вы оплачиваете услугу по добавлению своей строчки в DNS-таблицы, а также скидываетесь на поддержку инфраструктуры, обеспечивающей работу DNS. Сколько стоит такая услуга? Цены на домены в зонах ru и рф варьируют в большом диапазоне: 99 рублей от 2domains.ru, 300 рублей от 101domain.ru, 600 рублей от RU-CENTER. Почему такой разброс и не обманут ли при дешёвом варианте?

Минимальная цена, которую платит регистратор (т.е. организация, которая предоставляет услуги по регистрации) координатору национального домена (АНО «Координационный центр национального домена сети Интернет», ей поручена организация функционирования доменных зон ru/рф), составляет 70 рублей. Эта сумма фигурирует в документе «Финансовые условия деятельности регистраторов». Всё, что выше – идёт регистратору. В этом же документе указана рекомендованная цена регистрации для конечного пользователя: 500 рублей за регистрацию, 350 рублей – за продление. Очевидно, что рекомендованная цена установлена, чтобы определить некий средний уровень стоимости услуги по стране. Но запрета на снижение цены нет. В некоторых случаях вы даже можете получить домен бесплатно, когда, например, покупаете услугу хостинга. В этом варианте хостинг-провайдер просто включает цену регистрации домена в общую сумму, а домен продоставляет «в подарок».

Так что цена не является показателем надёжности регистратора. Самыми надёжными, наверно, можно считать регистраторы, которые аккредитованы Координационным центром. Хотя, конечно, ничто не мешает и аккредитованным организациям обанкротиться и исчезнуть с рынка.

Я пользуюсь услугами регистратора 2domains.ru, у него нет аккредитации, но он является партнёром аккредитованного регистратора REG.RU и стоимость регистрации и продления домена для физического лица составляет 99 рублей.

Аналогичная ситуация и на рынке международных доменов. К тому же, сейчас появляется всё больше дополнительных зон первого уровня, а также поговоривают о том, что можно будет регистрировать свой домен первого уровня: например, я смогу зарегистрировать себе домен .matrunich – не знаю, правда, что с ним делать 🙂 Благодаря увеличению количества альтернатив, снижаются цены и на имена в классических доменах, таких как .com. Раньше я не мог найти вариант дешевле 10 долларов (возможно, плохо искал), теперь даже у авторитетных регистраторов .com можно зарегистрировать меньше, чем за 3 доллара (по крайней мере, на первый год).


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


Процедура регистрации доменного имени

Для регистрации домена в зонах ru и рф на физическое лицо, согласно пункта 9.5.2 Правил регистрации доменных имен в доменах .RU и .РФ, необходимо предоставить информацию для идентификации этого физлица: фамилия, имя отчество, дата рождения, место жительства, сведения о документе, удостоверяющем личность. При регистрации на юрлицо (пункт 9.5.3) потребуется полное наименование юридического лица на русском, наименование латинскими буквами, юридический адрес и ИНН. Регистратор доменных имён 2domains.ru, которым пользуюсь я, для подтверждения указанных сведений просит сканы документов.

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


Если вы выбираете хостинг для сайта, то я рекомендую хостинг-провайдера HostGator


Page 1 of 6

Powered by WordPress & Theme by Anders Norén