предположим, что у меня есть «сырой» фрейм данных, который выглядит следующим образом (упрощенно):
raw <- data.frame(year.start = c(2004, 2004, 2004, 2004, 2004, 2010, 2010, 2010),
year.end = c(2006, 2006, 2006, 2005, 2005, 2012, 2012, 2012),
id = c("A","A","A","B","B","C","C","C"))
Он состоит из двух столбцов с годами, которые обозначают период от year.start до year.end. Кроме того, каждый период относится к группе товаров "id". Моя цель - создать новый столбец, в котором период разбит на отдельные годы для каждой группы соответственно. Следовательно, цель должна выглядеть следующим образом:
goal <- data.frame(year.start = c(2004, 2004, 2004, 2004, 2004, 2010, 2010, 2010),
year.end = c(2006, 2006, 2006, 2005, 2005, 2012, 2012, 2012),
id = c("A","A","A","B","B","C","C","C"),
year.goal = c(2004, 2005, 2006, 2004, 2005, 2010, 2011, 2012))
Есть ли какой-нибудь гладкий способ сделать это? Я действительно понятия не имею... Заранее спасибо!
Решение с использованием dplyr
.
library(dplyr)
raw2 <- raw %>%
group_by(id) %>%
mutate(year.goal = min(year.start):max(year.end)) %>%
ungroup()
raw2
# # A tibble: 8 x 4
# year.start year.end id year.goal
# <dbl> <dbl> <fct> <int>
# 1 2004 2006 A 2004
# 2 2004 2006 A 2005
# 3 2004 2006 A 2006
# 4 2004 2005 B 2004
# 5 2004 2005 B 2005
# 6 2010 2012 C 2010
# 7 2010 2012 C 2011
# 8 2010 2012 C 2012
Решение с использованием data.table
.
library(data.table)
setDT(raw)
raw2 <- raw[, year.goal := min(year.start):max(year.end), by = id]
raw2[]
# year.start year.end id year.goal
# 1: 2004 2006 A 2004
# 2: 2004 2006 A 2005
# 3: 2004 2006 A 2006
# 4: 2004 2005 B 2004
# 5: 2004 2005 B 2005
# 6: 2010 2012 C 2010
# 7: 2010 2012 C 2011
# 8: 2010 2012 C 2012
Решение с использованием основания R.
dat_list <- split(raw, f = raw$id)
dat_list2 <- lapply(dat_list, function(x) {
x$year.goal <- x$year.start[1]:x$year.end[1]
return(x)
})
raw2 <- do.call(rbind, dat_list2)
raw2
# year.start year.end id year.goal
# A.1 2004 2006 A 2004
# A.2 2004 2006 A 2005
# A.3 2004 2006 A 2006
# B.4 2004 2005 B 2004
# B.5 2004 2005 B 2005
# C.6 2010 2012 C 2010
# C.7 2010 2012 C 2011
# C.8 2010 2012 C 2012
Решение с использованием tidyverse
.
library(tidyverse)
raw2 <- raw %>%
group_by_all() %>%
nest() %>%
mutate(year.goal = map2(year.start, year.end, `:`)) %>%
unnest()
raw2
# # A tibble: 8 x 4
# year.start year.end id year.goal
# <dbl> <dbl> <fct> <int>
# 1 2004 2006 A 2004
# 2 2004 2006 A 2005
# 3 2004 2006 A 2006
# 4 2004 2005 B 2004
# 5 2004 2005 B 2005
# 6 2010 2012 C 2010
# 7 2010 2012 C 2011
# 8 2010 2012 C 2012
Еще одно dplyr
решение.
library(dplyr)
raw2 <- raw %>%
group_by(id) %>%
mutate(year.goal = first(year.start) + row_number() - 1) %>%
ungroup()
raw2
# # A tibble: 8 x 4
# year.start year.end id year.goal
# <dbl> <dbl> <fct> <dbl>
# 1 2004 2006 A 2004
# 2 2004 2006 A 2005
# 3 2004 2006 A 2006
# 4 2004 2005 B 2004
# 5 2004 2005 B 2005
# 6 2010 2012 C 2010
# 7 2010 2012 C 2011
# 8 2010 2012 C 2012
Ну, только для первого решения, другое решение dplyr работает отлично!
@Niklas Не знаю, что случилось. Если первое решение работает для примера набора данных, но не для набора данных реального мира, это означает, что между набором данных примера и набором данных реального мира есть некоторые ключевые различия.
Вау, спасибо большое!!! очевидно, есть много разных способов решить эту проблему :) Только один дополнительный вопрос: в моих исходных данных я получаю следующую ошибку: «Ошибка: столбец
year.goal
должен быть длиной 6 (размер группы) или один, не 5". У вас есть идеи, откуда может появиться ошибка?