在列中传播更改

时间:2016-09-16 22:56:01

标签: r

我想使用dplyr逐行遍历数据帧,如果A == 0,则将B设置为前一行中B的值,否则请保留不变。但是,我希望“前一行中B的值”在计算过程中引用前一行,而不是在计算开始之前,因为值可能已经改变 - 换句话说,我想要变化向下传播。例如,使用以下数据:

dat <- data.frame(A=c(1,0,0,0,1),B=c(0,1,1,1,1))

A B
1 0
0 1
0 1
0 1
1 1

我希望计算结果为:

result <- data.frame(A=c(1,0,0,0,1),B=c(0,0,0,0,1))

A B
1 0
0 0
0 0
0 0
1 1

如果我使用类似result <- dat %>% mutate(B = ifelse(A==0,lag(B),B)的内容,则更改不会向下传播:结果$ B将等于c(0,0,1,1,1),而不是c(0,0,0, 0,1)。

更一般地说,如何使用dplyr :: mutate创建依赖于自身的列(因为它在计算期间更新,而不是之前的更新)?

3 个答案:

答案 0 :(得分:6)

好像你想要进行最后一次观察&#34;做法。最常见的R实现是zoo::na.locf,它使用最后一个观察值填充NA值。在这种情况下我们需要做的就是首先将NA设置为我们要填写的所有B值:

mutate(dat, 
       B = ifelse(A == 0, NA, B),
       B = zoo::na.locf(B))
# A B
# 1 1 0
# 2 0 0
# 3 0 0
# 4 0 0
# 5 1 1

至于我的评论,请注意mutate唯一能做的就是将列添加到数据框中。我们也可以在没有变异的情况下做到这一点:

result = dat
result$B = with(result, ifelse(A == 0, NA, B))
result$B = zoo::na.locf(result$B)

使用mutate[$或任何其他方法访问/添加列与问题相关。

答案 1 :(得分:2)

我们可以在更改&#39; B&#39;后fill使用tidyr。在&#39; A&#39;

中对应于NA的值
library(dplyr)
library(tidyr)
dat %>%
     mutate(B = NA^(!A)*B) %>%
     fill(B)
#  A B
#1 1 0
#2 0 0
#3 0 0
#4 0 0
#5 1 1

注意:默认情况下,.directionfill中的参数)为&#34; down&#34;,但它也可以采用&#34; up&#34;即fill(B, .direction="up")

答案 2 :(得分:2)

以下是使用分组的解决方案,以及来自rleid的{​​{1}}(行程编码ID)。我认为它应该比data.table解决方案更快,因为动物园依赖于多次转动和一个cumsum。并且zoo非常快速

基本上,我们只想要前一组的最后一个值,因此我们根据rleid的diff矢量创建一个分组变量,并将其添加到rleid if rleid。然后我们对A == 1

的每个案例进行分组并获取该组的第一个B值
A == 0

编辑:这是一个包含较长数据集的示例,因此我们可以真正看到行为:(另外,如果所有library(dplyr) library(data.table) dat <- data.frame(A=c(1,0,0,0,1),B=c(0,1,1,1,1)) dat <- dat %>% mutate(grp = data.table::rleid(A), grp = ifelse(A == 1, grp + c(diff(grp),0),grp)) %>% group_by(grp) %>% mutate(B = ifelse(A == 0, B[1],B)) # EDIT: Always carry forward B on A == 0 dat Source: local data frame [5 x 3] Groups: grp [2] A B grp <dbl> <dbl> <dbl> 1 1 0 2 2 0 0 2 3 0 0 2 4 0 0 2 5 1 1 3 都不是全部A != 1那么应该是切换的

A == 1

结果:

set.seed(30)
dat <- data.frame(A=sample(0:1,15,replace = TRUE),
                  B=sample(0:1,15,replace = TRUE))

> dat
   A B
1  0 1
2  0 0
3  0 1
4  0 1
5  0 0
6  0 0
7  1 1
8  0 0
9  1 0
10 0 0
11 0 0
12 0 0
13 1 0
14 1 1
15 0 0