Как я могу добавить строку со средним значением каждого числового столбца

#r #dataframe #dplyr #pivot-table #tidyverse

Вопрос:

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

образец фрейма данных приведен ниже

 dat <- c('2000-01-15','2003-01-15','2000-02-15',
         '2003-02-15','2000-04-15','2002-04-15',
         '2000-12-15','2002-12-15','2003-12-13', "2003-12-15",'2002-02-21','2002-01-25','2003-04-24')

df <- data.frame(date =as.Date(dat), id = c(1,2,3,4,5,6,7,8,9,10,11,12,13),
                 sales = c(134,211,2000,234,421,400,34,1233,1222,1034,8034,1234,2331))

df <- df %>% 
  mutate(year = format(date, "%Y"),
                    month = format(date, "%b")) %>% select(-date) %>%
  group_by(year,month) %>%
  summarise(revenue = sum(sales))

df2 <- df %>% pivot_wider(id_cols = year, names_from = month, values_from = revenue)
 

Отсюда я хочу сделать

 rbind(df2, summarise_all(df2, mean))
 

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

Мой желаемый результат должен быть

   year    Apr   Dec   Feb   Jan
  <chr> <dbl> <dbl> <dbl> <dbl>
1 2000    421    34  2000   134
2 2002    400  1233  8034  1234
3 2003   2331  2256   234   211
4 mean   1051. 1174. 3423.  526.
 

Ответ №1:

Мы можем adorn_totals добавить строку суммы в конце, а затем разделить на общее количество строк — 1

 library(dplyr)
library(janitor)
df2 %>% 
    adorn_totals(name = "mean") %>%
    mutate(across(where(is.numeric), 
          ~ replace(., n(), .[n()]/(n()-1)))) %>%
    as_tibble
 

-выход

 # A tibble: 4 x 5
  year    Apr   Dec   Feb   Jan
  <chr> <dbl> <dbl> <dbl> <dbl>
1 2000   421    34  2000   134 
2 2002   400  1233  8034  1234 
3 2003  2331  2256   234   211 
4 mean  1051. 1174. 3423.  526.
 

Или другой вариант-использовать summarise with across для объединения ( c() ) mean значения в конце

 df2 %>%
    ungroup %>% 
    summarise(year = c(year, 'mean'),
         across(where(is.numeric), ~ c(., mean(.))))
 

-выход

 # A tibble: 4 x 5
  year    Apr   Dec   Feb   Jan
  <chr> <dbl> <dbl> <dbl> <dbl>
1 2000   421    34  2000   134 
2 2002   400  1233  8034  1234 
3 2003  2331  2256   234   211 
4 mean  1051. 1174. 3423.  526.
 

Или использовать add_row с tibble

 library(tibble)
df2 %>% 
   ungroup %>% 
   add_row(year = 'mean', !!! colMeans(.[-1]))
# A tibble: 4 x 5
  year    Apr   Dec   Feb   Jan
  <chr> <dbl> <dbl> <dbl> <dbl>
1 2000   421    34  2000   134 
2 2002   400  1233  8034  1234 
3 2003  2331  2256   234   211 
4 mean  1051. 1174. 3423.  526.
 

Ответ №2:

Базовый вариант R —

 rbind(df2, data.frame(year = 'mean', t(colMeans(df2[-1]))))

#  year    Apr   Dec   Feb   Jan
#  <chr> <dbl> <dbl> <dbl> <dbl>
#1 2000   421    34  2000   134 
#2 2002   400  1233  8034  1234 
#3 2003  2331  2256   234   211 
#4 mean  1051. 1174. 3423.  526.
 

Если вы не знаете положения числовых столбцов и хотите определить их динамически, вы можете использовать —

 cols <- sapply(df2, is.numeric)
rbind(df2, data.frame(year = 'mean', t(colMeans(df2[cols]))))