Я пытаюсь вычислить текущий счетчик (т. Е. Кумулятивную сумму), который зависит от других переменных и может сбрасываться для определенных значений другой переменной. Я работаю в 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
3
itpetersen 24 Окт 2018 в 05:41

2 ответа

Лучший ответ

Мы можем использовать case_when, чтобы присвоить значение, которое нам нужно, в зависимости от наших условий. Затем мы добавляем дополнительное условие group_by, используя cumsum для переключения значений, когда temp столбец 0. На последнем этапе mutate мы временно replace {{X6} } значения в 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
1
Ronak Shah 29 Окт 2018 в 04:46

Вот вариант с использованием 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
3
akrun 24 Окт 2018 в 04:08
52960348