Условный счетчик хода (накопленная сумма) со сбросом в R (dplyr) - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь вычислить текущий счет (т. Е. Кумулятивную сумму), который зависит от других переменных и может сбрасываться для определенных значений в другой переменной.Я работаю в R и предпочел бы решение на основе dplyr, если это возможно.

Я хотел бы создать переменную для счетчика прогонов cumulative на основе следующего алгоритма:

  • Рассчитать счетчик хода (cumulative) в комбинациях id и age
  • Увеличить счетчик хода (cumulative) на 1 для каждого последующего trial, гдеaccuracy = 0, block = 2 и condition = 1
  • Сброс счетчика хода (cumulative) до 0 для каждого trial, где accuracy = 1, block = 2 и condition = 1, и следующегоприращение возобновляется с 1 (не предыдущее число)
  • Для каждого trial, где block != 2 или condition != 1, оставьте текущий счет (cumulative) как NA

Вот минимальный рабочий пример:

mydata <- data.frame(id = c(1,1,1,1,1,1,1,1,1,1,1),
                 age = c(1,1,1,1,1,1,1,1,1,1,2),
                 block = c(1,1,2,2,2,2,2,2,2,2,2),
                 trial = c(1,2,1,2,3,4,5,6,7,8,1),
                 condition = c(1,1,1,1,1,2,1,1,1,1,1),
                 accuracy = c(0,0,0,0,0,0,0,1,0,0,0)
)

id  age block   trial   condition   accuracy
1   1   1       1       1           0
1   1   1       2       1           0
1   1   2       1       1           0
1   1   2       2       1           0
1   1   2       3       1           0
1   1   2       4       2           0
1   1   2       5       1           0
1   1   2       6       1           1
1   1   2       7       1           0
1   1   2       8       1           0
1   2   2       1       1           0

Ожидаемый результат:

id  age block   trial   condition   accuracy    cumulative
1   1   1       1       1           0           NA
1   1   1       2       1           0           NA
1   1   2       1       1           0           1
1   1   2       2       1           0           2
1   1   2       3       1           0           3
1   1   2       4       2           0           NA
1   1   2       5       1           0           4
1   1   2       6       1           1           0
1   1   2       7       1           0           1
1   1   2       8       1           0           2
1   2   2       1       1           0           1

Ответы [ 2 ]

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

Вот опция, использующая data.table.Создайте двоичный столбец на основе match значений paste d «точность», «блок», «условие» и значений пользовательских значений, сгруппированных по идентификатору длины строки двоичного столбца («ind»)), 'id' и 'age', получите совокупную сумму 'ind' и присвойте (:=) ее новому столбцу ("Cumulative")

library(data.table)
setDT(mydata)[, ind := match(do.call(paste0, .SD), c("121", "021")) - 1,
    .SDcols = c("accuracy", "block", "condition")
     ][, Cumulative := cumsum(ind), .(rleid(ind), id, age)
      ][, ind := NULL][]
#    id age block trial condition accuracy Cumulative
# 1:  1   1     1     1         1        0         NA
# 2:  1   1     1     2         1        0         NA
# 3:  1   1     2     1         1        0          1
# 4:  1   1     2     2         1        0          2
# 5:  1   1     2     3         1        0          3
# 6:  1   1     2     4         2        0         NA
# 7:  1   1     2     5         1        1          0
# 8:  1   1     2     6         1        0          1
# 9:  1   1     2     7         1        0          2
#10:  1   2     2     1         1        0          1
0 голосов
/ 24 октября 2018

Мы можем использовать case_when, чтобы назначить необходимое нам значение в зависимости от наших условий.Затем мы добавляем дополнительное условие group_by, используя cumsum для переключения значений, когда temp столбец 0. На последнем шаге mutate мы временно replace NA значения в temp до 0, а затем принимаем cumsum поверх него и снова верните значения NA в его место, чтобы получить окончательный результат.

library(dplyr)

mydata %>%
    group_by(id, age) %>%
    mutate(temp = case_when(accuracy == 0 & block == 2 & condition == 1 ~ 1, 
                            accuracy == 1 & block == 2 & condition == 1 ~ 0, 
                            TRUE ~ NA_real_)) %>%
    ungroup() %>%
    group_by(id, age, group = cumsum(replace(temp == 0, is.na(temp), 0))) %>%
    mutate(cumulative = replace(cumsum(replace(temp, is.na(temp), 0)),
                          is.na(temp), NA)) %>%
    select(-temp, -group)


#    group    id   age block trial condition accuracy cumulative
#   <dbl> <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>      <dbl>
# 1     0     1     1     1     1         1        0         NA
# 2     0     1     1     1     2         1        0         NA
# 3     0     1     1     2     1         1        0          1
# 4     0     1     1     2     2         1        0          2
# 5     0     1     1     2     3         1        0          3
# 6     0     1     1     2     4         2        0         NA
# 7     0     1     1     2     5         1        0          4
# 8     1     1     1     2     6         1        1          0
# 9     1     1     1     2     7         1        0          1
#10     1     1     1     2     8         1        0          2
#11     1     1     2     2     1         1        0          1
...