add_row并做一些计算

时间:2017-07-07 03:07:48

标签: r dplyr

假设我有一个如下所示的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年的序列。

1 个答案:

答案 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