Использование dplyr для маркировки и подсчета пробелов между значениями - PullRequest
0 голосов
/ 31 октября 2018

У меня есть этот фрейм данных:

    df<-structure(list(Name = c("sub1", "sub1", "sub1", "sub1", "sub1", 
                            "sub1", "sub1", "sub1", "sub1", "sub1", "sub1", "sub1", "sub1", 
                            "sub1", "sub1", "sub1", "sub1", "sub1", "sub1", "sub1", "sub1", 
                            "sub1", "sub1", "sub2", "sub2", "sub2", "sub2", "sub2", "sub2"
), StimulusName = c("Alpha11", "Alpha11", "Alpha11", "Alpha11", 
                    "Alpha11", "Alpha11", "Alpha11", "Alpha11", "Alpha11", "Alpha11", 
                    "Alpha11", "Alpha11", "Alpha11", "Alpha11", "Alpha11", "Alpha11", 
                    "Alpha11", "Alpha11", "Alpha12", "Alpha12", "Alpha12", "Alpha12", 
                    "Alpha12", "Alpha11", "Alpha11", "Alpha11", "Alpha11", "Alpha11", 
                    "Alpha11"), FixationSeq = c(2L, 2L, 2L, 2L, NA, NA, NA, NA, 3L, 
                                                3L, 3L, 3L, 3L, NA, NA, NA, NA, NA, 1L, NA, NA, 2L, NA, NA, NA, 
                                                NA, NA, 2L, 2L)), row.names = c(NA, -29L), class = c("tbl_df", 
                                                                                                     "tbl", "data.frame"), spec = structure(list(cols = list(Name = structure(list(), class = c("collector_character", 
                                                                                                                                                                                                "collector")), StimulusName = structure(list(), class = c("collector_character", 
                                                                                                                                                                                                                                                          "collector")), FixationSeq = structure(list(), class = c("collector_integer", 
                                                                                                                                                                                                                                                                                                                   "collector"))), default = structure(list(), class = c("collector_guess", 
                                                                                                                                                                                                                                                                                                                                                                         "collector"))), class = "col_spec"))

В столбце FixationSeq есть уникальные числа (в моем примере 2 и 3 для Name = sub1 и StimulusName = Alpha11). Между этими числами есть сегменты, заполненные NA. Есть также сегмент после 3, заполненный NA.

Я хотел бы иметь возможность создать новый столбец SaccadeCount и добавить увеличивающуюся цифровую метку к каждому экземпляру NA сегмента (в целом, то есть, возможно, нескольких строк) к соответствующему строки в SaccadeCount.

Кроме того, я хотел бы иметь еще один столбец с именем SaccadeDuration и общее количество строк, в которых появляются уникальные сегменты NA. Таким образом, в примере df строки, соответствующие сегменту NA между 2 и 3, будут заполнены символом «3», поскольку это общее количество строк между 2 и 3.

Я хотел бы сделать это с помощью dplyr и сгруппировать операцию по столбцам Name и StimulusName.

Вывод может выглядеть примерно так:

    Name    StimulusName    FixationSeq SaccadeCount    SaccadeDuration
   sub1     Alpha11             2       
   sub1     Alpha11             2       
   sub1     Alpha11             2       
   sub1     Alpha11             2       
   sub1     Alpha11             NA            1              3
   sub1     Alpha11             NA            1              3
   sub1     Alpha11             NA            1              3
   sub1     Alpha11             3       
   sub1     Alpha11             3       
   sub1     Alpha11             3       
   sub1     Alpha11             3       
   sub1     Alpha11             3       
   sub1     Alpha11             3       
   sub1     Alpha11             NA            2              5
   sub1     Alpha11             NA            2              5
   sub1     Alpha11             NA            2              5
   sub1     Alpha11             NA            2              5
   sub1     Alpha11             NA            2              5
   sub1     Alpha12             1       
   sub1     Alpha12             NA            1              2      
   sub1     Alpha12             NA            1              2
   sub1     Alpha12             2
   sub1     Alpha12             NA            2              1  
   sub2     Alpha11             NA            1              4
   sub2     Alpha11             NA            1              4
   sub2     Alpha11             NA            1              4
   sub2     Alpha11             NA            1              4
   sub2     Alpha11             2                  
   sub2     Alpha11             2 

Большое спасибо за ваше время и помощь.

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

Использование data.table

код:

library(data.table)
fun1 <- function(x) {
    na.ind = is.na(x$FixationSeq)
    na.vals= rleidv(rleidv(na.ind)[na.ind])
    x$SaccadeCount = NA
    x$SaccadeCount[na.ind] = na.vals

    na.rle = rle(na.vals)
    x$SaccadeDuration = NA
    x$SaccadeDuration[na.ind] = rep(na.rle$lengths, na.rle$lengths)

    return(x)
    }

setDT(df)[, fun1(.SD) ,by = .(Name, StimulusName)]

Вы можете использовать fun1 в режиме dplyr:

ans<-
df %>% group_by(Name, StimulusName) %>% dplyr::do(.data = ., fun1(.))

результат:

 #   Name StimulusName FixationSeq SaccadeCount SaccadeDuration
 #1: sub1      Alpha11           2           NA              NA
 #2: sub1      Alpha11           2           NA              NA
 #3: sub1      Alpha11           2           NA              NA
 #4: sub1      Alpha11           2           NA              NA
 #5: sub1      Alpha11           2           NA              NA
 #6: sub1      Alpha11           2           NA              NA
 #7: sub1      Alpha11           2           NA              NA
 #8: sub1      Alpha11           2           NA              NA
 #9: sub1      Alpha11           2           NA              NA
#10: sub1      Alpha11           2           NA              NA
#11: sub1      Alpha11           2           NA              NA
#12: sub1      Alpha11           2           NA              NA
#13: sub1      Alpha11           2           NA              NA
#14: sub1      Alpha11           2           NA              NA
#15: sub1      Alpha11           2           NA              NA
#16: sub1      Alpha11           2           NA              NA
#17: sub1      Alpha11           2           NA              NA
#18: sub1      Alpha11           2           NA              NA
#19: sub1      Alpha11           2           NA              NA
#20: sub1      Alpha11           2           NA              NA
#21: sub1      Alpha11           2           NA              NA
#22: sub1      Alpha11          NA            1               5
#23: sub1      Alpha11          NA            1               5
#24: sub1      Alpha11          NA            1               5
#25: sub1      Alpha11          NA            1               5
#26: sub1      Alpha11          NA            1               5
#27: sub1       Alpha1           9           NA              NA
#28: sub1       Alpha1           9           NA              NA
#29: sub1       Alpha1           9           NA              NA
#30: sub1       Alpha1           9           NA              NA
#31: sub1       Alpha1           9           NA              NA
#32: sub1       Alpha1           9           NA              NA
#33: sub1       Alpha1           9           NA              NA
#    Name StimulusName FixationSeq SaccadeCount SaccadeDuration

  • Мой подход использует предопределенную функцию fun1, которая выполняет работу для каждой группы.
  • Похоже, группы определены мои Name и StimulusName
  • Я использую очень важные функции, о которых вы должны узнать ?rle, ?rleidv
  • Я предварительно заполняю новый столбец всеми NA -значениями, затем добавляю новые значения, где это необходимо.
0 голосов
/ 31 октября 2018

Использование dplyr:

df %>%
  group_by(Name, StimulusName) %>%
  mutate(x = is.na(FixationSeq),
         count = cumsum(c(TRUE, diff(x) != 0L) & x) * x,
         dur = NA_integer_) %>%
  group_by(Name, StimulusName, count) %>%
  mutate(dur = replace(dur, as.logical(count), n()))

Соответствующий (более лаконичный) data.table версия:

library(data.table)
setDT(df)

df[ , count := ({
  x <- is.na(FixationSeq)
  .(cumsum(c(TRUE, diff(x) != 0L) & x) * x)}), by = .(Name, StimulusName)]

df[as.logical(count), dur := .N, by = .(Name, StimulusName, count)]
    Name StimulusName FixationSeq count dur
1:  sub1      Alpha11           2     0  NA
2:  sub1      Alpha11           2     0  NA
3:  sub1      Alpha11           2     0  NA
4:  sub1      Alpha11           2     0  NA
5:  sub1      Alpha11          NA     1   4
6:  sub1      Alpha11          NA     1   4
7:  sub1      Alpha11          NA     1   4
8:  sub1      Alpha11          NA     1   4
9:  sub1      Alpha11           3     0  NA
10: sub1      Alpha11           3     0  NA
11: sub1      Alpha11           3     0  NA
12: sub1      Alpha11           3     0  NA
13: sub1      Alpha11           3     0  NA
14: sub1      Alpha11          NA     2   5
15: sub1      Alpha11          NA     2   5
16: sub1      Alpha11          NA     2   5
17: sub1      Alpha11          NA     2   5
18: sub1      Alpha11          NA     2   5
19: sub1      Alpha12           1     0  NA
20: sub1      Alpha12          NA     1   2
21: sub1      Alpha12          NA     1   2
22: sub1      Alpha12           2     0  NA
23: sub1      Alpha12          NA     2   1
24: sub2      Alpha11          NA     1   4
25: sub2      Alpha11          NA     1   4
26: sub2      Alpha11          NA     1   4
27: sub2      Alpha11          NA     1   4
28: sub2      Alpha11           2     0  NA
29: sub2      Alpha11           2     0  NA
    Name StimulusName FixationSeq count dur

При желании изменить count == 0 на NA:

df[count == 0, count := NA]

Я бы не стал менять его на «пусто» (""), как показано в вопросе, потому что это привело бы столбец к character и сделал бы числа бесполезными для дальнейшего анализа.


Шаг за шагом cumsum(c(TRUE, diff(x) != 0L) & x) * x:

v <- c(1, 1, NA, NA, 1, NA, NA, NA)
x <- is.na(v)
x
# [1] FALSE FALSE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE

diff(x)
# [1]  0  1  0 -1  1  0  0

diff(x) != 0L
# [1] FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE

c(TRUE, diff(x) != 0L) & x
# [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE

cumsum(c(TRUE, diff(x) != 0L) & x)
# [1] 0 0 1 1 1 2 2 2

cumsum(c(TRUE, diff(x) != 0L) & x) * x
# [1] 0 0 1 1 0 2 2 2

Остальное, надеюсь, довольно просто.

0 голосов
/ 31 октября 2018

Это должно сделать это. Может быть, есть более простой способ, хотя. Первый mutate указывает начало сегмента NA . group_by и второй mutate считают NA s для каждого сегмента.

library(dplyr)
df %>% mutate(SaccadeCount = cumsum(ifelse(is.na(FixationSeq) & 
              !is.na(lag(FixationSeq)), 1,0)) * is.na(FixationSeq)) %>%
    group_by(SaccadeCount) %>%
    mutate(SaccadeDuration = n()) %>%
    ungroup() %>%
    mutate(SaccadeDuration = SaccadeDuration * is.na(FixationSeq))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...