Добавить строки в сгруппированные данные с помощью 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 (или любым другим более эффективным пакетом/функцией). Любые предложения будут высоко оценены!
Ответы
Ответ 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)