我正在尝试使用dplyr
的{{1}}函数来创建新变量,这些新变量取决于后续新变量的前一行值。
我已经用不同的术语搜索了SO,以查看是否有点击的声音,而最接近的答案是this。这是我所用的mutate()
的粗略结构:
tib
我想使用library(dplyr)
library(magrittr)
tib <- tribble(
~ID,
"A1",
"A2",
"A3",
"A4",
"A5",
"A1",
"B1",
"B2",
"B3"
)
来生成列mutate()
,x
和y
:
z
例如,对于上面显示的值,我希望输出为:
tib %<>%
mutate(
x = if_else(ID == "A1", 2, lag(y) + lag(z)),
y = if_else(ID == "A1", 3, x + lag(z)),
z = if_else(ID == "A1", 7, lag(z))
)
此方法的问题是| ID | x | y | z |
--------------------------------
| A1 | 2 | 3 | 7 |
| A2 | 10 | 17 | 7 |
| A3 | 24 | 31 | 7 |
| A4 | 38 | 45 | 7 |
| A5 | 52 | 59 | 7 |
| A1 | 2 | 3 | 7 |
| B1 | 10 | 17 | 7 |
| B2 | 24 | 31 | 7 |
| B3 | 38 | 45 | 7 |
--------------------------------
返回错误:
mutate()
我了解在启动Error in lag(y) : object 'y' not found
和y
之前先参考它们。如果z
是一个仅依赖于自身的事物(如上面的链接问题所示),我可以按照建议的那样多次通过,但是我认为这不可能。
如我的问题注释中所建议,如果我尝试初始化这些值(以便知道x
和y
),如下所示,
z
我收到的小词如下:
tib %<>%
mutate(
x = if_else(ID == "A1", 2, 0),
y = if_else(ID == "A1", 3, 0),
z = if_else(ID == "A1", 7, 0)
)
tib %<>%
mutate(
x = if_else(ID == "A1", 2, lag(y) + lag(z)),
y = if_else(ID == "A1", 3, x + lag(z)),
z = if_else(ID == "A1", 7, lag(z))
)
这与我预期的结果有所不同(也许是因为# A tibble: 9 x 4
ID x y z
<chr> <dbl> <dbl> <dbl>
1 A1 2 3 7
2 A2 10 17 7
3 A3 0 0 0
4 A4 0 0 0
5 A5 0 0 0
6 A1 2 3 7
7 B1 10 17 7
8 B2 0 0 0
9 B3 0 0 0
按列计算所有变量,所以mutate()
和y
是z
)?
希望更明确地说,我希望能够根据所述列的前几行中存在的值来为每个新列计算值-它们总是会有一些行会获得初始值,但是如何使它流到较低的行?
如果有帮助,请在Excel中使用this is how I would want it to work(我刚刚开始学习R)。
我想继续使用0
来保持代码的一致性。
答案 0 :(得分:2)
mutate()
不适用于Excel等迭代公式。它按列进行操作,因此在每一行迭代之间进行通信并不容易。在这种情况下,您的函数具有简单的非递归定义。这是包装非迭代版本的包装器函数
my_mutate <- function(data, x0, y0, z0) {
mutate(data,
n = 1:n(),
x = if_else(n==1, x0, y0 + z0*(n-1)),
y = if_else(n==1, y0, y0 + z0*2*(n-1)),
z = z0,
n = NULL
)
}
然后我们可以使用
执行组内转换tib %>% group_by(grp=cumsum(ID=="A1")) %>%
my_mutate(x0=2, y0=3, z0=7) %>%
ungroup %>% select(-grp)
# ID x y z
# <chr> <dbl> <dbl> <dbl>
# 1 A1 2 3 7
# 2 A2 10 17 7
# 3 A3 17 31 7
# 4 A4 24 45 7
# 5 A5 31 59 7
# 6 A1 2 3 7
# 7 B1 10 17 7
# 8 B2 17 31 7
# 9 B3 24 45 7
使用非迭代定义时要容易得多。