Урок 3 Перебор строк функцией rowwise()

3.1 Описание

В этом видео мы разберёмся с функцией rowwise(), из пакета dplyr.

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

В основе урока лежит статья “dplyr 1.0.0: working within rows”.

3.2 Видео

3.3 Код

#devtools::install_github("tidyverse/dplyr")
library(dplyr)

# test data
df <- tibble(
  student_id = 1:4, 
  test1 = 10:13, 
  test2 = 20:23, 
  test3 = 30:33, 
  test4 = 40:43
)

df

# попытка посчитать среднюю оценку по студету
df %>% mutate(avg = mean(c(test1, test2, test3, test4)))

# используем rowwise для преобразования фрейма
rf <- rowwise(df, student_id)
rf

rf %>% mutate(avg = mean(c(test1, test2, test3, test4)))

# тоже самое с использованием c_across
rf %>% mutate(avg = mean(c_across(starts_with("test"))))

# ###########################
# некоторые арифметические операции векторизированы по умолчанию
df %>% mutate(total = test1 + test2 + test3 + test4)

# этот подход можно использовать для вычисления среднего
df %>% mutate(avg = (test1 + test2 + test3 + test4) / 4)

# так же вы можете использовать некоторые специальные функции
# для вычисления некоторых статистик
df %>% mutate(
  min = pmin(test1, test2, test3, test4), 
  max = pmax(test1, test2, test3, test4), 
  string = paste(test1, test2, test3, test4, sep = "-")
)
# все векторизированные функции будут работать быстрее чем rowwise
# но rowwise позволяет векторизировать любую функцию

# ##################################
# работа со столбцами списками
df <- tibble(
  x = list(1, 2:3, 4:6),
  y = list(TRUE, 1, "a"),
  z = list(sum, mean, sd)
)

# мы можем перебором обработать каждый список
df %>% 
  rowwise() %>% 
  summarise(
    x_length = length(x),
    y_type = typeof(y),
    z_call = z(1:5)
  )

# ##################################
# симуляция случайных данных
df <- tribble(
  ~id, ~ n, ~ min, ~ max,
  1,   3,     0,     1,
  2,   2,    10,   100,
  3,   2,   100,  1000,
)

# используем rowwise для симуляции данных
df %>%
  rowwise(id) %>%
  mutate(data = list(runif(n, min, max)))

df %>%
  rowwise(id) %>%
  summarise(x = runif(n, min, max))

# ##################################
# функция nest_by позволяет создавать столбцы списки
by_cyl <- mtcars %>% nest_by(cyl)
by_cyl

# такой подход удобно использовать при построении линейной модели
# используем mutate для подгонки моели под каждую группа данных
by_cyl <- by_cyl %>% mutate(model = list(lm(mpg ~ wt, data = data)))
by_cyl
# теперь с помощью summarise 
# можно извлекать сводки или коэфициенты построенной модели
by_cyl %>% summarise(broom::glance(model))
by_cyl %>% summarise(broom::tidy(model))

3.4 Упражнения

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

# тестовый набор данных
set.seed(400)
year <- 2000:2005
sales <- sapply(
  month.abb, 
  FUN = function(x) round(runif(n = 6, min = 100, max = 400), 0)
  )

sales <- as.data.frame(sales, row.names = year)
sales$year <- year
sales
#>      Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec year
#> 2000 145 174 342 185 117 313 314 102 382 220 226 297 2000
#> 2001 156 251 286 280 179 176 317 323 247 194 233 263 2001
#> 2002 319 182 329 155 240 177 146 244 370 300 197 187 2002
#> 2003 209 187 238 296 393 234 366 314 198 213 206 234 2003
#> 2004 379 126 263 261 136 201 352 351 362 203 304 183 2004
#> 2005 221 275 374 318 127 376 257 193 340 190 225 273 2005

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

Ваша задача не переворачивая таблицу, добавить в неё 4 столбца:

  • winter_avg_sales - средний объём продаж за зимные месяца;
  • spring_avg_sales - средний объём продаж за весенние месяца;
  • summer_avg_sales - средний объём продаж за летние месяца;
  • autumn_avg_sales - средний объём продаж за осенние месяца;

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

Результат вычислений будет выглядить вот так:

# A tibble: 6 x 5
# Rowwise: 
   year winter_avg_sales spring_avg_sales summer_avg_sales autumn_avg_sales
  <int>            <dbl>            <dbl>            <dbl>            <dbl>
1  2000              322             226              145              227 
2  2001              174             192.             179.             295.
3  2002              106             352.             215.             258.
4  2003              105             260.             334.             206.
5  2004              167             192.             239              254.
6  2005              210             191.             271.             235