Превращаем временной ряд в светофор

от автора

«Мы сделаем вас счастливыми! Вы будете счастливыми!»
«Отроки во Вселенной» (1974)

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

Аллегория вполне понятная, пытаться объяснять что-либо — в 99% случаев процедура бессмысленная и энергозатратная. Поэтому ниже пример, как двумя экранами кода можно быстренько превратить временные ряды, которые почти всегда встречаются в больших количествах, в светофор.

Все предыдущие публикации.

Приступаем к процессу «осчастливливания».
Потребуются клей, бумага, скотч, и немного R.

Обычно временные ряды проглядывают на глубину 2-4 недель. Рядов может быть много, ОЧЕНЬ много и их надо как-то привести к светофорной раскраске.

Воспользуемся фактом небольшой глубины и соберем на коленке пульверизатор на основе линейной регрессии. Коэффициент $k$ нам определит цвет краски (красный/зеленый), а стат. значимость даст необходимый желтый для нестабильного поведения. Поскольку пишем на R, то никаких циклов. Базовую идею подсматриваем в книге «R for Data Science», глава «Many models».

Подключаем пакеты

library(tidyverse) library(lubridate) library(glue) library(scales) library(stringi) library(jsonlite) library(RColorBrewer) library(extrafont) library(hrbrthemes) library(DBI) library(anytime) library(tictoc) library(checkmate) library(data.table) library(ggplot2) library(ggthemes) library(cli) library(gt) library(lme4) # modeling

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

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

Сформируем каркасы 12 функций.

set.seed(12) raw_df <-  1:12 %>%   tibble(id = .,           k = (id - 1) %/% 4 - 1,          b = runif(length(.), 10, 30)) %>%   rowwise() %>%   mutate(data = list(     tibble(x = 0:13, y = k * runif(1, 0, 3)*x + b))     )

Сформируем датасет в именах и значениях реальных данных.

signal_tbl <- raw_df %>%   unnest(data) %>%   mutate(date_msk = today() + x,           value = y + rnorm(nrow(.), sd = 3.5)) %>%   mutate_at("id", as.factor)  signal_tbl %>%   ggplot(aes(date_msk, value, group = id)) +   geom_point() +   facet_wrap(~id, ncol = 4)

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

OLS [код]

lm_tbl <- signal_tbl %>%   select(id, date_msk, value) %>%   nest(-id) %>%   mutate(model = map(data, ~lm(value ~ date_msk, data = .x))) %>%   mutate(m_params = map(model, broom::tidy)) %>%   unnest(m_params) %>%   filter(term == "date_msk") %>%   setDT() %>%   .[, id_trend := fifelse(estimate < 0,                            "Падение показателя",                            "Рост показателя")] %>%   .[p.value > 0.05, id_trend := "Достоверно неизвестно"] %>%   as_tibble()

Рисуем внятную табличку с большими буквами.

Табличка gt [код]

lm_tbl %>%   select(id, estimate, std.error, p.value, id_trend) %>%   mutate(grp = p.value < 0.05) %>%   arrange(desc(grp), desc(estimate)) %>%   gt() %>%   cols_hide(columns = grp) %>%   fmt_number(     columns = p.value,     decimals = 4,     use_seps = FALSE   ) %>%   data_color(     c(estimate),     colors = scales::col_numeric(       c("#f87274", "white", "#63be7b"),       na.color = "transparent",       domain = NULL     )   ) %>%   # снимем раскраску с незначимых строк   tab_style(     style = list(       cell_fill(color = "white"),       cell_text(color = "black")       ),     locations = cells_body(rows = p.value > 0.05)   )

Строим финальную картинку, согласуем цвета с корпоративным брендбуком.

Светографики [код]

lm_tbl %>%   select(id, data, estimate, id_trend) %>%   unnest(data) %>%   ggplot(aes(date_msk, value, colour = id_trend, group = id)) +   geom_point(alpha = 0.8) +   ggthemes::scale_colour_tableau() +   geom_smooth(se = FALSE, alpha = 0.5) +   scale_x_date(labels = scales::date_format("%d.%m"),                 breaks = scales::date_breaks("2 days"),                guide = guide_axis(n.dodge = 2)) +   scale_y_continuous(labels = scales::label_percent(accuracy = 1),                      breaks = scales::breaks_pretty(n = 3)) +   facet_wrap(~id, ncol = 3, scales = "free") +   theme_ipsum_rc() +   labs(x = "Дата", y = "Показатель", colour = "Динамика")

Собственно говоря, все.

Предыдущая публикация — «Важно ли DS аналитику знать про software development?»


ссылка на оригинал статьи https://habr.com/ru/post/712408/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *