假设我有一个如下所示的data.frame:
df <- data.frame(group = c("group1","group1", "group2", "group2"),
year = c(2000, 2001, 2000, 2001),
value = c(10, 13, 2, 5))
我希望按每个组进行分组,然后添加一行,然后对第3列进行计算。例如,新数据框看起来像这样(计算只是value(-1)+value(-2)
)
df <- data.frame(group = c("group1","group1", "group1", "group2", "group2", "group2"),
year = c(2000, 2001, 2002, 2000, 2001, 2002),
value = c(10, 13, 23, 2, 5, 7))
我尝试过使用dplyr,但我似乎无法弄明白。所以我对任何解决方案持开放态度,不过如果有一个dplyr会很棒!
此外,我希望能够在未来的十个时期内做到这一年,所以这一年将是最终数据框架中从2000年到2011年的序列。
答案 0 :(得分:3)
这是一种类似Fibonacci的计算,使用for
循环编写起来非常简单,而不是使用矢量化操作。 R中应谨慎使用for
循环,因为错误地使用它们会导致代码速度变慢,但如果通过事先用tidyr::complete
扩展data.frame预先分配内存,则可以将函数编写为很容易包含循环:
library(tidyverse)
df <- data.frame(group = c("group1","group1", "group2", "group2"),
year = c(2000, 2001, 2000, 2001),
value = c(10, 13, 2, 5))
fibonacci <- function(x){
for(i in seq(3, length(x))){
x[i] <- x[i-1] + x[i-2]
}
x
}
df2 <- df %>%
group_by(group) %>%
complete(year = 2000:2005) %>%
mutate(value = fibonacci(value))
df2
#> # A tibble: 12 x 3
#> # Groups: group [2]
#> group year value
#> <fctr> <dbl> <dbl>
#> 1 group1 2000 10
#> 2 group1 2001 13
#> 3 group1 2002 23
#> 4 group1 2003 36
#> 5 group1 2004 59
#> 6 group1 2005 95
#> 7 group2 2000 2
#> 8 group2 2001 5
#> 9 group2 2002 7
#> 10 group2 2003 12
#> 11 group2 2004 19
#> 12 group2 2005 31
如果要避免循环和矢量化,请使用Fibonacci序列的公式表达式。来自Wikipedia,
fibonacci2 <- function(u0, u1, n){
phi <- (1 + sqrt(5)) / 2
psi <- 1 - phi
a <- (u1 - u0 * psi) / sqrt(5)
b <- (u0 * phi - u1) / sqrt(5)
a * phi^n + b * psi^n
}
df3 <- df %>%
group_by(group) %>%
complete(year = 2000:2005) %>%
mutate(value = fibonacci2(value[1], value[2], seq.int(0L, length(value) - 1)))
df3
#> # A tibble: 12 x 3
#> # Groups: group [2]
#> group year value
#> <fctr> <dbl> <dbl>
#> 1 group1 2000 10
#> 2 group1 2001 13
#> 3 group1 2002 23
#> 4 group1 2003 36
#> 5 group1 2004 59
#> 6 group1 2005 95
#> 7 group2 2000 2
#> 8 group2 2001 5
#> 9 group2 2002 7
#> 10 group2 2003 12
#> 11 group2 2004 19
#> 12 group2 2005 31
有点奇怪(可能是由于正确的预分配和R添加JIT编译循环),两者之间的时间差异很小。基准测试很棘手,因为该系列趋势超过.Machine$double.xmax
并在大约第1475年转向Inf
,但是在每个方法的新输入上复制到1,475,000次计算,
microbenchmark::microbenchmark(
fibonacci = replicate(1000, {
x <- double(1475);
x[1:2] <- rnorm(2);
fibonacci(x)
}),
fibonacci2 = replicate(1000, {
x <- double(1475);
x[1:2] <- rnorm(2);
fibonacci2(x[1], x[2], seq.int(0L, length(x) - 1L))
})
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> fibonacci 249.4110 255.9866 264.2625 261.6491 272.0018 295.3266 100
#> fibonacci2 202.3588 209.0647 219.0509 214.2429 223.5476 375.7604 100