суббота, 29 августа 2020 г.

Временные ряды в R : tsibble объекты

Для работы с временными рядами в соответствии с принципами организации и хранения “опрятных данных” (“tidy data”) и использовании  инструментов из группы tidyverse группа исследователей под руководством проф. Роба Хиндмана (Rob Hyndman) разработала новый формат объекта tsibble, реализованный в пакете tsibble.

Временной ряд можно представить себе как список чисел (измерений) вместе с некоторой информацией о том, когда эти числа были записаны (индекс). Эта информация может быть сохранена как tsibbleобъект в R.

Он характеризуется следующими свойствами:

  • данные хранятся в табличном виде;
  • в таблице должны присутствовать как минимум два столбца — со значениями наблюдаемой во времени количественной переменной и с упорядоченными по возрастанию (т.е. от прошлого к будущему) временными отметками (столбец с временными отметками называется индексирующим — index;
  • кроме того, в таблицу могут входить одна или несколько группирующих переменных (key) — значения этих переменных указывают на принадлежность каждого наблюдения к соответствующему временному ряду;
  • любое наблюдение в таблице можно уникально идентифицировать по сочетанию значений индексирующей и группирующих переменных.
Создать такой объект можно с помощью функции tsibble :

month_index <- seq.Date(from = as.Date("2018-01-01"),
                        to = as.Date("2019-12-01"), 
                        by = "month")

rev <- c(21520,20356,25922,31087,30442,27584,22787,21281,28781,32347,44638,50456,
           26951,27145,28687,32506,28532,29739,21817,29583,27777,34017,40004,44561)

y <- tsibble(Month = yearmonth(month_index), Observation = rev, index = Month)
y

# A tsibble: 24 x 2 [1M]
      Month Observation
      <mth>       <dbl>
 1 2018 янв       21520
 2 2018 фев       20356
 3 2018 мар       25922
 4 2018 апр       31087
 5 2018 май       30442
 6 2018 июн       27584
 7 2018 июл       22787
 8 2018 авг       21281
 9 2018 сен       28781
10 2018 окт       32347
# ... with 14 more rows


В этом примере был создан объект tsibble, представляющий месячные продажи в магазине с января 2018 по декабрь 2019. «[1M]» в первой строке, указывающее, что это данные за месяц.
В зависимости от частоты наблюдений при создании объекта могут использоваться другие функции класса времени.
ЧастотаФункция
Годовойstart:end
Ежеквартальныйyearquarter()
Ежемесячноyearmonth()
Еженедельноyearweek()
Ежедневноas_date()ymd()
Субдневныйas_datetime()
Для создания объектов класса tsibble из других объектов данных служит функция as_tsibble(), которая имеет следующие аргументы:
  • x — объект с данными, подлежащий преобразованию в объект класса tsibble (это может быть, например, числовой вектор, матрица, таблица с данными (data.frame или tibble) и др.).
  • index — переменная с временными отметками (указывается без кавычек). Допускается использование временных отметок на шкале от наносекунд до года.
  • key — одна или несколько группирующих, или ключевых, переменных, которые уникально определяют каждый хранящийся в таблице временной ряд. Названия переменных указываются без кавычек и объединяются с помощью функции конкатенации c(). По умолчанию этот аргумент равен NULL, т.е. предполагается, что группирующих переменных в таблице нет.
  • regular — логический аргумент, который указывает на регулярность учета хранящихся в таблице наблюдений. Значение TRUE (принято по умолчанию) предполагает, что учет выполнялся с одинаковым интервалом (например, каждую минуту, час, день, и т.п.).
  • validate — логический аргумент (по умолчанию равен TRUE), позволяющий выполнить проверку уникальности каждого наблюдения по сочетанию значений переменных index и key. Если вы уверены, что каждое наблюдение уникально, то такую проверку можно отключить (FALSE) — это приведет к более быстрому выполнению команды as_tsibble() в случае с большими наборами данных.
  • .drop — логический аргумент, позволяющий исключить из таблицы “пустые” временные ряды, т.е. такие сочетания значений группирующих переменных, для которых значения x отсутствуют.
Рассмотрим как можно сделать объект tsibble из датафрейма, у нас есть данные по 44 магазинам по месяцам с января 2015 по декабрь 2019 с  выручками и заработной платой персонала

> shop_rev
# A tibble: 2,640 x 4
   ds         shop    rev  wage
   <date>     <chr> <dbl> <dbl>
 1 2015-01-01 Sh1   98046  8824
 2 2015-01-01 Sh2   46233  3699
 3 2015-01-01 Sh3   17023  1532
 4 2015-01-01 Sh4   43381  3470
 5 2015-01-01 Sh5   49419  4942
 6 2015-01-01 Sh6   29154  2624
 7 2015-01-01 Sh7   46008  5521
 8 2015-01-01 Sh8   45281  3622
 9 2015-01-01 Sh9   50929  5602
10 2015-01-01 Sh10  52140  6257
# ... with 2,630 more rows

Сделаем из него объект tsibble

t_shop_rev <-shop_rev %>%
  mutate(ds = yearmonth(ds)) %>%
  as_tsibble(key = shop,index = ds)
t_shop_rev

# A tsibble: 2,640 x 4 [1M]
# Key:       shop [44]
         ds shop     rev  wage
      <mth> <chr>  <dbl> <dbl>
 1 2015 янв Sh1    98046  8824
 2 2015 фев Sh1    70041  7705
 3 2015 мар Sh1   102630 12316
 4 2015 апр Sh1   103127 10313
 5 2015 май Sh1   115185 13822
 6 2015 июн Sh1    90927 10911
 7 2015 июл Sh1    84353  9279
 8 2015 авг Sh1    93958  9396
 9 2015 сен Sh1    95731  9573
10 2015 окт Sh1   180711 18071
# ... with 2,630 more rows


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

> shop_rev_sex
# A tibble: 5,280 x 4
   ds         shop  sex       y
   <date>     <chr> <chr> <dbl>
 1 2015-01-01 Sh1   male  40199
 2 2015-01-01 Sh2   male  24966
 3 2015-01-01 Sh3   male   8682
 4 2015-01-01 Sh4   male  23426
 5 2015-01-01 Sh5   male  27674
 6 2015-01-01 Sh6   male  17492
 7 2015-01-01 Sh7   male  25765
 8 2015-01-01 Sh8   male  24905
 9 2015-01-01 Sh9   male  26483
10 2015-01-01 Sh10  male  27113
# ... with 5,270 more rows

Также сделаем из него объект tsibble

t_shop_rev_sex <-shop_rev_sex %>%
  mutate(ds = yearmonth(ds)) %>%
  as_tsibble(key = c(shop,sex),index = ds)
t_shop_rev_sex

# A tsibble: 5,280 x 4 [1M]
# Key:       shop, sex [88]
         ds shop  sex        y
      <mth> <chr> <chr>  <dbl>
 1 2015 янв Sh1   female 57847
 2 2015 фев Sh1   female 35021
 3 2015 мар Sh1   female 48236
 4 2015 апр Sh1   female 45376
 5 2015 май Sh1   female 57592
 6 2015 июн Sh1   female 43645
 7 2015 июл Sh1   female 40489
 8 2015 авг Sh1   female 41342
 9 2015 сен Sh1   female 42122
10 2015 окт Sh1   female 81320
# ... with 5,270 more rows

Работа с tsibble объектами


Для работы с объектами tsibble можно использовать функции select(), которая позволяет выбрать определенные столбцы, в то время как с filter() можно выбрать определенные строки.

t_shop_rev %>%
  filter(shop=="Sh1") %>%
  select(ds,shop, rev)

# A tsibble: 60 x 3 [1M]
# Key:       shop [1]
         ds shop     rev
      <mth> <chr>  <dbl>
 1 2015 янв Sh1    98046
 2 2015 фев Sh1    70041
 3 2015 мар Sh1   102630
 4 2015 апр Sh1   103127
 5 2015 май Sh1   115185
 6 2015 июн Sh1    90927
 7 2015 июл Sh1    84353
 8 2015 авг Sh1    93958
 9 2015 сен Sh1    95731
10 2015 окт Sh1   180711
# ... with 50 more rows


Еще одна полезная функция - summarise() объединять данные по ключам. Например, мы можем рассчитать общую выручку в месяц независимо от ключей shop или sex.

t_shop_rev_sex %>%
  filter(shop=="Sh1") %>%
  select(ds, shop, sex, y) %>%
  summarise(TotalRev = sum(y))

 A tsibble: 60 x 2 [1M]
         ds TotalRev
      <mth>    <dbl>
 1 2015 янв    98046
 2 2015 фев    70042
 3 2015 мар   102630
 4 2015 апр   103127
 5 2015 май   115184
 6 2015 июн    90927
 7 2015 июл    84353
 8 2015 авг    93959
 9 2015 сен    95732
10 2015 окт   180711
# ... with 50 more rows

Для отбора по периодам используется функция filter_index

#По февраль 2015
t_shop_rev %>%
  filter(shop=="Sh1") %>%
  filter_index(~"2015-02")

#с января по июнь 2015
t_shop_rev %>%
  filter(shop=="Sh1") %>%
  filter_index("2015-01"~"2015-06")

# с августа 2016 и до конца
t_shop_rev %>%
  filter(shop=="Sh1") %>%
  filter_index("2016-08" ~ .)


# интервал периодов
t_shop_rev %>%
  filter(shop=="Sh1") %>%
  filter_index(~"2015-02", "2015-08" ~ "2015-09", "2015-12" ~ "2016-02")

# 2015 год
t_shop_rev %>%
  filter(shop=="Sh1") %>%
  filter_index("2015")


Агрегирование наблюдений


Под агрегирование при работе с временными рядами является понимается расчет показателей за определенный календарный период (например, средние или суммарные значения за день, неделю, месяц, квартал и т.п.). В пакете  для таких вычислений используется связка из двух функций: index_by() и summarise(). Первая из этих функций входит в состав пакета tsibble и аналогична group_by() из пакета dplyr. Как следует из ее названия, index_by() группирует данные по заданному пользователем периоду времени. Для указания необходимого периода применяются такие функции из пакета tsibble, как yearweek() (неделя), yearmonth() (месяц) и yearquarter() (квартал). Кроме того, можно также использовать базовую as.Date() и многие функции из пакета lubridate. Вторая функция из указанной выше связки — summarise() — входит в состав пакета dplyr и служит для вычисления необходимых агрегированных величин.

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


  t_shop_rev_qv <- t_shop_rev %>% 
    group_by_key() %>% 
    index_by(year_qv  = ~ yearquarter(.)) %>% 
    summarise(
      avg_rev = mean(rev),
      avg_wage = mean(wage),
      n = n()
    )
  t_shop_rev_qv

# A tsibble: 880 x 5 [1Q]
# Key:       shop [44]
   shop  year_qv avg_rev avg_wage     n
   <chr>   <qtr>   <dbl>    <dbl> <int>
 1 Sh1   2015 Q1  90239     9615      3
 2 Sh1   2015 Q2 103080.   11682      3
 3 Sh1   2015 Q3  91347.    9416      3
 4 Sh1   2015 Q4 175729.   17582      3
 5 Sh1   2016 Q1 109201    10649      3
 6 Sh1   2016 Q2 102430    11007.     3
 7 Sh1   2016 Q3  99987     9901.     3
 8 Sh1   2016 Q4 169136    16866.     3
 9 Sh1   2017 Q1  87836.    9136      3
10 Sh1   2017 Q2 101203    10436.     3
# ... with 870 more rows

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



















 




Комментариев нет:

Отправить комментарий