我有以下数据集:
df <- data.frame(subject = c(1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3),
time = c(1,2,3,4,5,6,7,8,9,10,11,12,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,11),
performance = c(1,0,-1,-1,0,1,1,-1,0,0,0,1,1,1,-1,0,1,1,-1,0,0,1,-1,1,1,0,1,1,-1,0,-1,-1,0))
我想要做的是更改性能变量中的一些条目。更具体地说,如果“-1”条目前面有“1”,我想将“-1”改为“0”。
然而,这应该仅在受试者内进行,而不是在受试者之间进行(所有受试者都有不同数量的会话)。
所以,这就是我最终想要的:
df2 =data.frame(subject = c(1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3),
time = c(1,2,3,4,5,6,7,8,9,10,11,12,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,11),
performance = c(1,0,-1,-1,0,1,1,0,0,0,0,1,1,1,0,0,1,1,0,0,0,1,-1,1,1,0,1,1,-1,0,-1,-1,0))
有谁知道如何做到这一点?
提前致谢! S上。
答案 0 :(得分:2)
使用dplyr
,
df %>%
group_by(subject) %>%
mutate(performance = replace(performance, which(performance + lag(performance)==0 & performance == -1), 0))
答案 1 :(得分:1)
这是一个data.table方法,我首先创建一个flag
列,然后用于对数据进行子集化并通过引用更新performance
列。
library(data.table)
dt <- as.data.table(df) # or setDT(df)
dt[, flag := performance == -1 & shift(performance, 1L) == 1, by = subject]
dt[(flag), performance := 0][, flag := NULL]
我选择使用中间标志列来完成它,因为我希望它能够很好地处理大型数据集。如果您不关心效果,则可以使用ifelse
或replace
代替。
答案 2 :(得分:0)
这很难看,但应该有效:
dftest <- df
for (i in 2:nrow(dftest)) {
if(
dftest$performance[i] == -1 && dftest$performance[i - 1] == 1
){
if(
dftest$subject[i] == dftest$subject[i - 1]
) {
dftest$performance[i] <- 0
}
}
}
all.equal(df2, dftest) # ONE ERROR
这在第29行给出了错误 - 你能在这里检查你的示例df2是否正确吗?如果我理解正确的问题df2$performance[29]
应为0
?
答案 3 :(得分:0)
使用by
和sapply
的基础R解决方案:
gr <- do.call(c, by(df, df$subject, function(x) {
c(FALSE, unlist(sapply(1:length(x$performance),
function(y) (x$performance[y] == -1) & (x$performance[y-1] == 1))))
}))
df[gr, 3] <- 0
cbind(df, df2)