R 根据序列中的位置指定新值
在R工作。 这些数据追踪了大脑活动随时间的变化。“标记”列包含特定处理开始和结束时的信息。例如,第一个条件(标记==1)从第3行开始,到第6行结束。第二个实验条件(mark==2)从第9行开始,到第12行结束。在第15行和第18行之间重复另一批处理R 根据序列中的位置指定新值,r,if-statement,for-loop,conditional-statements,data-manipulation,R,If Statement,For Loop,Conditional Statements,Data Manipulation,在R工作。 这些数据追踪了大脑活动随时间的变化。“标记”列包含特定处理开始和结束时的信息。例如,第一个条件(标记==1)从第3行开始,到第6行结束。第二个实验条件(mark==2)从第9行开始,到第12行结束。在第15行和第18行之间重复另一批处理 ob.id <- c(1:20) mark <- c(0,0,1,0,0,1,0,0,2,0,0,2,0,0,1,0,0,1,0,0) condition<-c(0,0,1,1,1,1,0,0,2,2,2,2,0,0,1, 1,1,
ob.id <- c(1:20)
mark <- c(0,0,1,0,0,1,0,0,2,0,0,2,0,0,1,0,0,1,0,0)
condition<-c(0,0,1,1,1,1,0,0,2,2,2,2,0,0,1, 1,1,1,0,0)
start <- data.frame(ob.id,mark)
result<-data.frame(ob.id,mark,condition)
print (start)
> print (start)
ob.id mark
1 1 0
2 2 0
3 3 1
4 4 0
5 5 0
6 6 1
7 7 0
8 8 0
9 9 2
10 10 0
11 11 0
12 12 2
13 13 0
14 14 0
15 15 1
16 16 0
17 17 0
18 18 1
19 19 0
20 20 0
谢谢你的帮助 以下是我可以想到的一种方法:
# Find where experiments stop and start
ind <- which( result$mark != 0 )
[1] 3 6 9 12 15 18
# Make a matrix of the start and stop indices taking odd and even elements of the vector
idx <- cbind( head(ind , -1)[ 1:length(ind) %% 2 == 1 ] ,tail( ind , -1)[ 1:length(ind) %% 2 == 1 ] )
[,1] [,2]
[1,] 3 6
[2,] 9 12
[3,] 15 18
这是一个有趣的小问题。下面我使用的技巧是首先计算
标记
向量的rle
,这使得问题更简单,因为生成的值
向量始终只有一个0,可能需要或不需要替换(取决于周围的值)
后一种方法可能更灵活。实验总是4行长吗?不,实验条件会有不同的长度:它是呈现特定刺激的毫秒数。+1表示头部和尾部技巧。这也是我的想法。@eddi:t
t
在tail/head
行中的值是多少?谢谢@eddi,你的rle解决方案对我来说更透明、更具教育意义,但我同意后者更灵活(值得@SimonO101称赞!)。这正是我所需要的,而且还演示了我想看到的这类问题的一个示例的条件逻辑。我仍在阅读您的解决方案,但对于步骤2matrix(ind,ncol=2,byrow=T)
+1,这里有一个更简单的选项,这是一个有趣的方法,“但你需要以某种方式解决这个问题,而不仅仅是填补1的空白,”SimonO101说。我最终用eddi的解决方案解决了我的特殊问题,但这给了我一些很好的演示和未来参考资料。谢谢你的时间!
# Find where experiments stop and start
ind <- which( result$mark != 0 )
[1] 3 6 9 12 15 18
# Make a matrix of the start and stop indices taking odd and even elements of the vector
idx <- cbind( head(ind , -1)[ 1:length(ind) %% 2 == 1 ] ,tail( ind , -1)[ 1:length(ind) %% 2 == 1 ] )
[,1] [,2]
[1,] 3 6
[2,] 9 12
[3,] 15 18
idx <- cbind( ind[ 1:length(ind) %% 2 == 1 ] , ind[ 1:length(ind) %% 2 != 1 ] )
# Make vector of row indices to turn to 1's
ones <- as.vector( apply( idx , 1 , function(x) c( x[1]:x[2] ) ) )
# Make your new column and turn appropriate rows to 1
result$condition <- 0
result$condition[ ones ] <- 1
result
# ob.id mark condition
#1 1 0 0
#2 2 0 0
#3 3 1 1
#4 4 1 1
#5 5 1 1
#6 6 1 1
#7 7 0 0
#8 8 0 0
#9 9 1 1
#10 10 1 1
#11 11 1 1
#12 12 1 1
#13 13 0 0
#14 14 0 0
#15 15 1 1
#16 16 1 1
#17 17 1 1
#18 18 1 1
#19 19 0 0
#20 20 0 0
ind <- matrix( which( start$mark != 0 ) , ncol = 2 , byrow = TRUE )
ind <- cbind( ind , start$mark[ ind[ , 1 ] ] )
# [,1] [,2] [,3]
#[1,] 3 6 1
#[2,] 9 12 2
#[3,] 15 18 1
res <- integer( nrow( start ) )
for( i in 1:nrow(ind) ){
res[ ind[i,1]:ind[i,2] ] <- ind[i,3]
}
[1] 0 0 1 1 1 1 0 0 2 2 2 2 0 0 1 1 1 1 0 0
# example vector with some edge cases
v = c(0,0,1,0,0,0,1,2,0,0,2,0,0,1,0,0,0,0,1,2,0,2)
v.rle = rle(v)
v.rle
#Run Length Encoding
# lengths: int [1:14] 2 1 3 1 1 2 1 2 1 4 ...
# values : num [1:14] 0 1 0 1 2 0 2 0 1 0 ...
vals = rle(v)$values
# find the 0's that need to be replaced and replace by the previous value
idx = which(tail(head(vals,-1),-1) == 0 & (head(vals,-2) == tail(vals,-2)))
vals[idx + 1] <- vals[idx]
# finally go back to the original vector
v.rle$values = vals
inverse.rle(v.rle)
# [1] 0 0 1 1 1 1 1 2 2 2 2 0 0 1 1 1 1 1 1 2 2 2
library(data.table)
dt = data.table(start)
dt[, result := mark[1],
by = {tmp = rep(0, length(mark));
tmp[which(mark != 0)[c(F,T)]] = 1;
cumsum(mark != 0) - tmp}]
dt
# ob.id mark result
# 1: 1 0 0
# 2: 2 0 0
# 3: 3 1 1
# 4: 4 0 1
# 5: 5 0 1
# 6: 6 1 1
# 7: 7 0 0
# 8: 8 0 0
# 9: 9 2 2
#10: 10 0 2
#11: 11 0 2
#12: 12 2 2
#13: 13 0 0
#14: 14 0 0
#15: 15 1 1
#16: 16 0 1
#17: 17 0 1
#18: 18 1 1
#19: 19 0 0
#20: 20 0 0