Подтвердить что ты не робот

Добавить строки в сгруппированные данные с помощью dplyr?

Мои данные находятся в формате data.frame, таком как данные примера:

data <- 
structure(list(Article = structure(c(1L, 1L, 3L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 1L, 2L, 1L
), .Label = c("10004", "10006", "10007"), class = "factor"), 
Demand = c(26L, 780L, 2L, 181L, 228L, 214L, 219L, 291L, 104L, 
72L, 155L, 237L, 182L, 148L, 52L, 227L, 2L, 355L, 2L, 432L, 
1L, 156L), Week = c("2013-W01", "2013-W01", "2013-W01", "2013-W01", 
"2013-W01", "2013-W02", "2013-W02", "2013-W02", "2013-W02", 
"2013-W02", "2013-W03", "2013-W03", "2013-W03", "2013-W03", 
"2013-W03", "2013-W04", "2013-W04", "2013-W04", "2013-W04", 
"2013-W04", "2013-W04", "2013-W04")), .Names = c("Article", 
"Demand", "Week"), class = "data.frame", row.names = c(NA, -22L))

Я хотел бы обобщить колонку спроса за неделю и статью. Для этого я использую:

library(dplyr)
WeekSums <- 
  data %>%
   group_by(Article, Week) %>%
   summarize(
    WeekDemand = sum(Demand)
   )

Но поскольку некоторые статьи не были проданы в определенные недели, количество строк на статью отличается (только недели с продажами показаны в DataSrams WeekSums). Как я могу настроить свои данные так, чтобы каждая статья имела одинаковое количество строк (по одной на каждую неделю), в том числе недели с требованием 0?

Результат должен выглядеть следующим образом:

  Article     Week WeekDemand
1   10004 2013-W01       1215
2   10004 2013-W02        900
3   10004 2013-W03        774
4   10004 2013-W04       1170
5   10006 2013-W01        0
6   10006 2013-W02        0
7   10006 2013-W03        0
8   10006 2013-W04         5
9   10007 2013-W01         2
10   10007 2013-W02        0
11   10007 2013-W03        0
12   10007 2013-W04        0

Я пробовал

WeekSums %>%
  group_by(Article) %>%
  if(n()< 4) rep(rbind(c(Article,NA,NA)), 4 - n() )

но это не работает. В моем первоначальном подходе я решил эту проблему, объединив фрейм данных недельных чисел 1-4 с моим файлом rawdata для каждой статьи. Таким образом, у меня есть 4 недели (строки) для каждой статьи, но реализация с циклом for очень неэффективна, и поэтому я пытаюсь сделать то же самое с dplyr (или любым другим более эффективным пакетом/функцией). Любые предложения будут высоко оценены!

4b9b3361

Ответ 1

Без dplyr это можно сделать следующим образом:

as.data.frame(xtabs(Demand ~ Week + Article, data))

даяние:

       Week Article Freq
1  2013-W01   10004 1215
2  2013-W02   10004  900
3  2013-W03   10004  774
4  2013-W04   10004 1170
5  2013-W01   10006    0
6  2013-W02   10006    0
7  2013-W03   10006    0
8  2013-W04   10006    5
9  2013-W01   10007    2
10 2013-W02   10007    0
11 2013-W03   10007    0
12 2013-W04   10007    0

и это можно переписать как конвейер magrittr или dplyr следующим образом:

data %>% xtabs(formula = Demand ~ Week + Article) %>% as.data.frame()

as.data.frame() в конце можно было бы опустить, если было предложено широкое решение формы.

Ответ 2

Поскольку dplyr находится в активной разработке, я думал, что опубликую обновление, которое также включает tidyr:

library(dplyr)
library(tidyr)

data %>%
  expand(Article, Week) %>%
  left_join(data) %>%
  group_by(Article, Week) %>%
  summarise(WeekDemand = sum(Demand, na.rm=TRUE))

Что производит:

   Article     Week WeekDemand
1    10004 2013-W01       1215
2    10004 2013-W02        900
3    10004 2013-W03        774
4    10004 2013-W04       1170
5    10006 2013-W01          0
6    10006 2013-W02          0
7    10006 2013-W03          0
8    10006 2013-W04          5
9    10007 2013-W01          2
10   10007 2013-W02          0
11   10007 2013-W03          0
12   10007 2013-W04          0

Используя tidyr >= 0.3.1, теперь это можно записать как:

data %>% 
  complete(Article, Week) %>%  
  group_by(Article, Week) %>% 
  summarise(Demand = sum(Demand, na.rm = TRUE))

Ответ 3

Я думал, что предоставил dplyr -еское решение.

  • используйте expand.grid() для создания парных комбинаций, которые вы ищете.
  • используйте left_join() для объединения в данные спроса (заполнение остальных с помощью NA).

Решение:

full_data <- expand.grid(Article=data$Article,Week=data$Week)
out <- left_join(tbl_dt(full_data),data)
out[is.na(out)] <- 0    # fill with zeroes for summarise below.

Затем, как и раньше:

WeekSums <- out %>%
            group_by(Article, Week) %>%
            summarise(
                     WeekDemand = sum(Demand)
                     )

Программирование Fxnal?

Если вы часто используете это преобразование, возможно, удобную функцию:

xpand <- function(df, col1, col2,na_to_zero=TRUE){

    require(dplyr)

    # to substitute in the names "as is" need substitute then eval.
    xpand_call <- substitute(     
        expanded <- df %>%
                    select(col1,col2) %>%
                    expand.grid()
    )

    eval(xpand_call)                       

    out <- left_join(tbl_dt(expanded), df)         # join in any other variables from df.

    if(na_to_zero) out[is.na(out)] <- 0    # convert NAs to zeroes?

    return(out)
}

Таким образом вы можете:

expanded_df <- xpand(df,Article,Week)

Ответ 4

В этой ситуации вы также можете использовать dcast и melt.

   library(dplyr)
   library(reshape2)
   data %>%
      dcast(Article ~ Week, value.var = "Demand", fun.aggregate = sum) %>%
      melt(id = "Article") %>%
      arrange(Article, variable)