Chris Ruehlemann
Chris Ruehlemann

Reputation: 21400

Detect blinks in pupillary data

I have pupillary data, with Diam_av recording averaged pupil diameter, like so:

df <- data.frame(
  Diam_av = c(12.3,13,15.5,0,0,0,0,13.7,0,0,9.98,4,0,8.76)
)

Sometimes Diam_avis 0. I assume there to be a blink (i.e., eyes closed) where there are at least 4 consecutive 0 values. I'm trying to flag these Blinks, thus:

library(dplyr)
df %>%
  mutate(Blinks = ifelse(Diam_av == 0 & lag(Diam_av) == 0 & lag(Diam_av, 2) == 0 & lag(Diam_av, 3) == 0, 
                         "yes", "no"),
         Blinks = ifelse(lead(Blinks) == "yes"|lead(Blinks,2) == "yes"|lead(Blinks,3) == "yes", 
                         "yes", Blinks))
1    12.30     no
2    13.00     no
3    15.50     no
4     0.00    yes
5     0.00    yes
6     0.00    yes
7     0.00    yes
8    13.70     no
9     0.00     no
10    0.00     no
11    9.98     no
12    4.00   <NA>
13    0.00   <NA>
14    8.76   <NA>

While the result is acceptable in terms of Blinks detection, there are two issues with the code: (i) it seems bulky and repetitive and (ii) some Blinks get changed to NA whereas they should be no. How can the code be mended?

Upvotes: 1

Views: 51

Answers (2)

akrun
akrun

Reputation: 887251

Using data.table

library(data.table)
setDT(df)[, Blinks := c('no', 'yes')[1 + (.N >= 4)],rleid(Diam_av == 0)]
df
    Diam_av Blinks
 1:   12.30     no
 2:   13.00     no
 3:   15.50     no
 4:    0.00    yes
 5:    0.00    yes
 6:    0.00    yes
 7:    0.00    yes
 8:   13.70     no
 9:    0.00     no
10:    0.00     no
11:    9.98     no
12:    4.00     no
13:    0.00     no
14:    8.76     no

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 389055

You may use rle and change 4 consecutive 0 values to 'yes' and rest of them as 'no'.

library(dplyr)
df %>%
  mutate(Blinks = ifelse(with(rle(Diam_av == 0), 
                        rep(values & lengths >= 4, lengths)), 'yes', 'no'))

#   Diam_av Blinks
#1    12.30     no
#2    13.00     no
#3    15.50     no
#4     0.00    yes
#5     0.00    yes
#6     0.00    yes
#7     0.00    yes
#8    13.70     no
#9     0.00     no
#10    0.00     no
#11    9.98     no
#12    4.00     no
#13    0.00     no
#14    8.76     no

Upvotes: 2

Related Questions