Home > Net >  Summarise durations of string duplicates in the presence of `NA`
Summarise durations of string duplicates in the presence of `NA`

Time:12-29

I have gaze-direction data in columns A_aoi and B_aoi as well as the respective gaze durations in columns A_dur and B_dur:

df <- data.frame(
  id = 1:4,
  A_aoi = c("C*BB*B", "C*BCCC", "B**", "C*B"),
  A_dur = c("234,312,222,3456,1112,77", "12,13,14,15,11,1654", "896,45222,55", "5554,322,142"),
  B_aoi = c("**ACC", "AC*", "AAA", "C*A*"),
  B_dur =c("12,13,15,100,100", "1,2,3", "88,99,100", "1,2,3,4")
)

In some cases there are two or more immediatly adjacent duplicates (i.e., measurements of the same type); for example, the first A_aoi value contains the string BB, the second value contains CCC.

I need to summarise the durations of these duplicates. With the help of this code from a previous question Summarize values in strings in one variable based on positions of related values in another variable, I'm able to do this task:

library(data.table)

calculate <- function(p, q) {
  mapply(function(x, y) toString(tapply(as.numeric(x), rleid(y), sum)), 
         strsplit(p, ','), strsplit(q, ''))
}

aoi_cols <- grep('aoi', names(df))
dur_cols <- grep('dur', names(df))
df[dur_cols] <- Map(calculate, df[dur_cols], df[aoi_cols])
df
  id  A_aoi                    A_dur B_aoi       B_dur
1  1 C*BB*B 234, 312, 3678, 1112, 77 **ACC 25, 15, 200
2  2 C*BCCC         12, 13, 14, 1680   AC*     1, 2, 3
3  3    B**               896, 45277   AAA         287
4  4    C*B           5554, 322, 142  C*A*  1, 2, 3, 4

BUT: in my actual data, there are NA values. For example, in this slightly modified df, where I've added a single NA value in column B_dur, the code throws an error:

df <- data.frame(
  id = 1:4,
  A_aoi = c("C*BB*B", "C*BCCC", "B**", "C*B"),
  A_dur = c("234,312,222,3456,1112,77", "12,13,14,15,11,1654", "896,45222,55", "5554,322,142"),
  B_aoi = c("**ACC", "AC*", "AAA", "C*A*"),
  B_dur =c("12,13,15,100,100", NA, "88,99,100", "1,2,3,4")
)

How can the task be accomplished even in the presence of NA, so that the result looks like this:

df
  id  A_aoi                    A_dur B_aoi       B_dur
1  1 C*BB*B 234, 312, 3678, 1112, 77 **ACC 25, 15, 200
2  2 C*BCCC         12, 13, 14, 1680   AC*        <NA>
3  3    B**               896, 45277   AAA         287
4  4    C*B           5554, 322, 142  C*A*  1, 2, 3, 4

CodePudding user response:

You can modify the calculate function to check for NA values.

library(data.table)

calculate <- function(p, q) {
  mapply(function(x, y) {
    if(any(is.na(x))) NA 
    else toString(tapply(as.numeric(x), rleid(y), sum))
    }, strsplit(p, ','), strsplit(q, ''))
}

df[dur_cols] <- Map(calculate, df[dur_cols], df[aoi_cols])
df

#  id  A_aoi                    A_dur B_aoi       B_dur
#1  1 C*BB*B 234, 312, 3678, 1112, 77 **ACC 25, 15, 200
#2  2 C*BCCC         12, 13, 14, 1680   AC*        <NA>
#3  3    B**               896, 45277   AAA         287
#4  4    C*B           5554, 322, 142  C*A*  1, 2, 3, 4
  • Related