使用两个data.frame计算R中的累积增长
我举了一个例子,说明我想用最简单的方法实现什么,我一直坚持着 我有两个data.frame,一个带有值,另一个带有百分比:使用两个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",
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