Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select row N based on values from row N-1 across list of data frames

Tags:

list

r

I've searched through previous answered questions and haven't been able to construct a functioning solution yet. Here's my situation with demo data:

Say I have subjects complete a computer task where they give a response on each trial. I end up with data from each trial regarding whether they gave the accurate response and what their reaction time was:

sub1 <- data.frame(acc = round(rnorm(10, mean=.65, sd=.25), 0), RT = round(rnorm(10, mean=270, sd=30), 0))
sub2 <- data.frame(acc = round(rnorm(10, mean=.65, sd=.25), 0), RT = round(rnorm(10, mean=270, sd=30), 0))
sub3 <- data.frame(acc = round(rnorm(10, mean=.65, sd=.25), 0), RT = round(rnorm(10, mean=270, sd=30), 0))

sub.list <- list(sub1, sub2, sub3)

I've created a list where each element is a subject's data.

> sub.list
[[1]]
   acc  RT
1    1 259
2    0 187
3    1 256
4    1 288
5    1 304
6    1 265
7    1 312
8    1 196
9    1 335
10   0 276

[[2]]
   acc  RT
1    1 215
2    0 325
3    1 290
4    0 297
5    0 281
6    1 294
7    0 289
8    1 252
9    0 364
10   0 241

[[3]]
   acc  RT
1    0 292
2    0 267
3    0 240
4    1 321
5    1 292
6    0 269
7    1 241
8    1 206
9    1 250
10   1 283

Now comes my issue. I want to create another column for each subject that only has the RTs for accurate trials that were also preceded by an accurate response. Here's a non-working for-loop and an example of what I'm trying to end up with.

for(i in 1:length(sub.list)){
  for(j in 2:nrow(sub.list[[i]])){
    if(sub.list[[i]][(j-1), "acc"]==1 & sub.list[[i]][j, "acc"]==1){
      sub.list[[i]][j,]$correct.RT <- sub.list[[i]][j, "RT"]
    } else {
      sub.list[[i]][j,]$correct.RT <- NA
    }
  }
}

> sub.list
[[1]]
   acc  RT correctRT
1    1 259        NA
2    0 187        NA
3    1 256        NA
4    1 288       288
5    1 304       304
6    1 265       265
7    1 312       312
8    1 196       196
9    1 335       335
10   0 276        NA

[[2]]
   acc  RT correctRT
1    1 215        NA
2    0 325        NA
3    1 290        NA
4    0 297        NA
5    0 281        NA
6    1 294        NA
7    0 289        NA
8    1 252        NA
9    0 364        NA
10   0 241        NA

[[3]]
   acc  RT correctRT
1    0 292        NA
2    0 267        NA
3    0 240        NA
4    1 321        NA
5    1 292       292
6    0 269        NA
7    1 241        NA
8    1 206       206
9    1 250       250
10   1 283       283

My reason for doing this is so that I can perform functions on these trials alone. For example:

> sapply(sub.list, function(x) mean(x$correctRT, na.rm=TRUE))
[1] 283.3333      NaN 257.7500

I know there must be a way to accomplish this with mapply or one of the other apply functions rather than a clumsy, slow for loop, but my hang up is how to reference sequential rows.

Any help is much appreciated!

like image 368
YTD Avatar asked Feb 17 '23 08:02

YTD


1 Answers

sub.list <- lapply(sub.list, transform,
                   correctRT = ifelse(acc & c(0, head(acc, -1)), RT, NA))

But given your final goal, I would rather create a flag (TRUE/FALSE) variable:

sub.list <- lapply(sub.list, transform,
                   is.valid = acc & c(0, head(acc, -1)))

Then to compute the means for example:

sapply(sub.list, with, mean(RT[is.valid]))
like image 139
flodel Avatar answered Apr 07 '23 09:04

flodel