使用两个data.frame计算R中的累积增长

使用两个data.frame计算R中的累积增长,r,R,我举了一个例子,说明我想用最简单的方法实现什么,我一直坚持着 我有两个data.frame,一个带有值,另一个带有百分比: table <- structure(list(a = 1:10, b = 11:20, c = 21:30, type = c("g", "g", "g", "g", "g", "g", "g", "g",

我举了一个例子,说明我想用最简单的方法实现什么,我一直坚持着

我有两个data.frame,一个带有值,另一个带有百分比:

table <- structure(list(a = 1:10, b = 11:20, c = 21:30, type = c("g", 
"g", "g", "g", "g", "g", "g", "g", "g", "g")), row.names = c(NA, 
-10L), class = "data.frame")

growth <- structure(list(type = c("g", "g2"), a = c(1, 1), b = c(1.1, 1.3
), c = c(1.2, 1.1)), class = "data.frame", row.names = c(NA, 
-2L))
第二个名为
growth
,如下所示:

    a  b  c type
1   1 11 21    g
2   2 12 22    g
3   3 13 23    g
4   4 14 24    g
5   5 15 25    g
6   6 16 26    g
7   7 17 27    g
8   8 18 28    g
9   9 19 29    g
10 10 20 30    g
  type a   b   c
1    g 1 1.1 1.2
2   g2 1 1.3 1.1
我想要实现的是,例如在
表的第一行中
对象:

type
列给出了表
growth
中的增长
g
,然后:

a = 1 * 1, b = (1*1)*1.1 + 11, c = ((1*1)*1.1 + 11)*1.2 + 21
对于数据帧的每一行,都是这样

编辑:有很多好的答案值得一看。标记的解决方案是因为它更具可读性和灵活性

df=merge(table,growth,by="type")

data.frame(
  "a"=(df$a.x*df$a.y),
  "b"=(df$a.x*df$a.y*df$b.y+df$b.x),
  "c"=(df$a.x*df$a.y*df$b.y+df$b.x)*df$c.y+df$c.x
)

    a    b     c
1   1 12.1 35.52
2   2 14.2 39.04
3   3 16.3 42.56
4   4 18.4 46.08
5   5 20.5 49.60
6   6 22.6 53.12
7   7 24.7 56.64
8   8 26.8 60.16
9   9 28.9 63.68
10 10 31.0 67.20
下面的一种更一般的方法是,在没有特殊原因的情况下,以.y结尾的列

df=merge(table,growth,by="type")

cls=colnames(df)[grepl("\\.y",colnames(df))]

for (i in 1:length(cls)) {
  if (i==1) {
    df[cls[i]]=df[gsub("\\.y","\\.x",cls[i])]*df[cls[i]]
  } else {
    df[cls[i]]=df[cls[i-1]]*df[cls[i]]+df[gsub("\\.y","\\.x",cls[i])]
  }
}

   type a.x b.x c.x a.y  b.y   c.y
1     g   1  11  21   1 12.1 35.52
2     g   2  12  22   2 14.2 39.04
3     g   3  13  23   3 16.3 42.56
4     g   4  14  24   4 18.4 46.08
5     g   5  15  25   5 20.5 49.60
6     g   6  16  26   6 22.6 53.12
7     g   7  17  27   7 24.7 56.64
8     g   8  18  28   8 26.8 60.16
9     g   9  19  29   9 28.9 63.68
10    g  10  20  30  10 31.0 67.20
库(tidyverse)
f%
选择(-id)

以显示它对
n
列数有效。让我们假设初始数据如下

> table
    a  b  c  d  e type
1   1 11 21 31 41    g
2   2 12 22 32 42    g
3   3 13 23 33 43    g
4   4 14 24 34 44    g
5   5 15 25 35 45    g
6   6 16 26 36 46    g
7   7 17 27 37 47    g
8   8 18 28 38 48    g
9   9 19 29 39 49    g
10 10 20 30 40 50    g

> growth
  type a   b   c   d    e
1    g 1 1.1 1.2 1.3 1.25
2   g2 1 1.3 1.1 1.2 1.15

#then
table %>% 
  mutate(id = row_number()) %>% 
  pivot_longer(-c(id, type), values_to = "Val1") %>%
  left_join(growth %>% 
              pivot_longer(-type, values_to = "Val2"), 
            by = c("type", "name")) %>% 
  group_split(id) %>%
  map_df(~accumulate2(.x$Val1, 
                      .x$Val2, 
                      .init = 0, 
                      ~(..1 * ..3) + ..2 )[-1] %>% 
           set_names(paste0("x", seq_len(nrow(.x))))) %>%
  bind_cols(table, .)

    a  b  c  d  e type x1   x2    x3      x4     x5
1   1 11 21 31 41    g  1 12.1 35.52  77.176 137.47
2   2 12 22 32 42    g  2 14.2 39.04  82.752 145.44
3   3 13 23 33 43    g  3 16.3 42.56  88.328 153.41
4   4 14 24 34 44    g  4 18.4 46.08  93.904 161.38
5   5 15 25 35 45    g  5 20.5 49.60  99.480 169.35
6   6 16 26 36 46    g  6 22.6 53.12 105.056 177.32
7   7 17 27 37 47    g  7 24.7 56.64 110.632 185.29
8   8 18 28 38 48    g  8 26.8 60.16 116.208 193.26
9   9 19 29 39 49    g  9 28.9 63.68 121.784 201.23
10 10 20 30 40 50    g 10 31.0 67.20 127.360 209.20
前面的答案 这一个不是硬编码的,并且基于单个管道中的
tidyverse
语法样式。我假设您的新列命名为
x
y
,&
z
。如果有人能把它缩短,我会更高兴

table %>% 
  mutate(id = row_number()) %>% 
  pivot_longer(-c(id, type), values_to = "Val1") %>%
  left_join(growth %>% 
              pivot_longer(-type, values_to = "Val2"), 
            by = c("type", "name")) %>% 
  group_split(id) %>%
  map_df(~accumulate2(.x$Val1, 
                      .x$Val2, 
                      .init = 0, 
                      ~(..1 * ..3) + ..2 )[-1] %>% 
           set_names(paste0("x", seq_len(nrow(.x))))) %>%
  bind_cols(table, .)

    a  b  c type  x1  x2    x3
1   1 11 21    g  1 12.1 35.52
2   2 12 22    g  2 14.2 39.04
3   3 13 23    g  3 16.3 42.56
4   4 14 24    g  4 18.4 46.08
5   5 15 25    g  5 20.5 49.60
6   6 16 26    g  6 22.6 53.12
7   7 17 27    g  7 24.7 56.64
8   8 18 28    g  8 26.8 60.16
9   9 19 29    g  9 28.9 63.68
10 10 20 30    g 10 31.0 67.20
我已经正确地缩进了上述语法,以便容易理解

  • 这两个数据的轴心都变长了,并连接起来,分别得到
    Val1
    Val2
    两个值
  • 从现在起,每个a/b/c行都在一列中,我将每个行拆分为一个单独的列表
  • 为了对列表中的每个项目执行相同的操作,我使用了map函数。因为我们可能需要以数据帧的方式很好地构造最终输出,所以我在这里使用了另外两种方法
    • 改为使用
      map\u df
    • 将每个输出的名称设置为x1/x2/x3(map_df的要求)
  • 现在,为了在Val1和val2上迭代执行操作,我使用了
    acgregate2
    ,以便可以执行预期的操作
都做完了


注意,此语法适用于n个变量,而不仅仅是3个。唯一需要注意的是名称,如果您愿意,也可以对其进行软编码。

这里是我认为您可能感兴趣的另一个解决方案:

library(dplyr)
library(tidyr)
library(stringr)
library(purrr)


growth %>% 
  rename_with(~ str_to_upper(.x), a:c) %>% 
  right_join(table, by = "type") %>%
  relocate(a, b, c, type) %>%
  mutate(pmap(list(a, b, c, A, B, C), function(a, b, c, A, B, C) {
    a1 <- A * a
    b1 <- a1 * B + b
    c1 <- b1 * C + c
    cbind(a1, b1, c1) %>%
      set_names(c("a1", "b2", "c1"))
  })) %>% 
  unnest_wider(8) %>%
  select(-c(A, B, C))


# A tibble: 10 x 7
       a     b     c type     a1    b2    c1
   <int> <int> <int> <chr> <dbl> <dbl> <dbl>
 1     1    11    21 g         1  12.1  35.5
 2     2    12    22 g         2  14.2  39.0
 3     3    13    23 g         3  16.3  42.6
 4     4    14    24 g         4  18.4  46.1
 5     5    15    25 g         5  20.5  49.6
 6     6    16    26 g         6  22.6  53.1
 7     7    17    27 g         7  24.7  56.6
 8     8    18    28 g         8  26.8  60.2
 9     9    19    29 g         9  28.9  63.7
10    10    20    30 g        10  31    67.2

库(dplyr)
图书馆(tidyr)
图书馆(stringr)
图书馆(purrr)
增长%>%
将_重命名为(~str_to_upper(.x),a:c)%>%
右联接(表,by=“type”)%>%
重新定位(a、b、c、类型)%>%
变异(pmap(列表(a,b,c,a,b,c),函数(a,b,c,a,b,c){
a1%
选择(-c(A,B,c))
#一个tibble:10x7
a b c类型a1 b2 c1
11121G12.135.5
2 12 22 g 2 14.2 39.0
3 13 23 g 3 16.3 42.6
4 14 24 g 4 18.4 46.1
5 15 25克5 20.5 49.6
6 16 26 g 6 22.6 53.1
7 17 27 g 7 24.7 56.6
8 18 28 g 8 26.8 60.2
9 19 29 g 9 28.9 63.7
102030G1067.2

在最终输出中,是否要更改所有3列(
a
b
c
)对于
?不是严格必需的,也可以保存在3个新列中。@AnilGoyal当然。我一直在测试不同的方法,我已经标记了一个解决方案。您的解决方案非常聪明,但不够灵活,不能满足我的需要。我相信它在其他情况下会非常方便。如果我有,我想要不硬编码的东西列
d
应该也能工作……亲爱的Anil,请查看我的解决方案。我花了将近2个小时来获得正确的输出数据结构。我将在完全检查后恢复。@AnoushiravanR,请检查修改后的答案,确认它实际上独立于初始列数。
累加
系列(实际上
reduce
family)在
purrr
中,在这些情况下效果很好。所以这是我一直以来的偏好。我肯定会的。这听起来是一个有趣的解决方案,谢谢你提醒我注意。例如,如果这个案例涉及3列以上的内容,我可以轻松地将代码扩展到3个以上的变量,但它没有那么灵活和灵活像你的一样适应,它会变得有点冗长。策略是有效的,但正如OP所说的,一旦变量增加,它就会造成混乱。因此,在我看来,累积策略将是最合适的。我不太熟悉累积策略,但肯定有更好的方法来实现这一点。我只是想达到预期的效果输出,然后当然再重新思考如何优化。策略很好,但请检查下面OP的评论,即他/她希望保留打开其他列的选项。因此,此处不推荐任何硬编码的内容。:)哦,你说得对。我没有看到列的数量可能会增加。所以我想我必须熟悉
累积
函数,看看是否可以用另一种方式修改我的代码以更好地适应这种情况。@AnilGoyal非常感谢你的评论。
library(dplyr)
library(tidyr)
library(stringr)
library(purrr)


growth %>% 
  rename_with(~ str_to_upper(.x), a:c) %>% 
  right_join(table, by = "type") %>%
  relocate(a, b, c, type) %>%
  mutate(pmap(list(a, b, c, A, B, C), function(a, b, c, A, B, C) {
    a1 <- A * a
    b1 <- a1 * B + b
    c1 <- b1 * C + c
    cbind(a1, b1, c1) %>%
      set_names(c("a1", "b2", "c1"))
  })) %>% 
  unnest_wider(8) %>%
  select(-c(A, B, C))


# A tibble: 10 x 7
       a     b     c type     a1    b2    c1
   <int> <int> <int> <chr> <dbl> <dbl> <dbl>
 1     1    11    21 g         1  12.1  35.5
 2     2    12    22 g         2  14.2  39.0
 3     3    13    23 g         3  16.3  42.6
 4     4    14    24 g         4  18.4  46.1
 5     5    15    25 g         5  20.5  49.6
 6     6    16    26 g         6  22.6  53.1
 7     7    17    27 g         7  24.7  56.6
 8     8    18    28 g         8  26.8  60.2
 9     9    19    29 g         9  28.9  63.7
10    10    20    30 g        10  31    67.2