R: изменить переменную, обусловленную данными из нескольких предыдущих строк - PullRequest
0 голосов
/ 13 июня 2018

Привет, я был бы очень признателен за помощь, я действительно не мог найти решение в предыдущих вопросах.

У меня есть тиббл в длинном формате (строки сгруппированы по идентификатору и упорядочены по времени).Я хочу создать переменную "eleg" на основе "varx".Условием будет то, что «eleg» = 1, если «varx» в предыдущих 3 строках == 0 и в текущей строке varx == 1, если не = 0, для каждого идентификатора.Если возможно, используя dplyr.

id <- c(1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3)
time <- c(1,2,3,4,5,6,7,1,2,3,4,5,6,1,2,3,4)
varx <- c(0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1)
eleg <- c(0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1)
table <- data.frame(id, time, varx, eleg)

В моем реальном наборе данных условие «в предыдущих 24 строках», и один и тот же идентификатор может иметь Eleg == 1 более одного раза, если это соответствует условию.

Спасибо.

Ответы [ 4 ]

0 голосов
/ 13 июня 2018

Вы запросили решение dplyr, предпочтительно.
Ниже приведено базовое решение R, с функцией, которую можно адаптировать к "в предыдущих 24 строках" , просто передайтеn = 24 к функции.

fun <- function(DF, crit = "varx", new = "eleg", n = 3){
  DF[[new]] <- 0
  for(i in seq_len(nrow(DF))[-seq_len(n)]){
    if(all(DF[[crit]][(i - n):(i - 1)] == 0) && DF[[crit]][i] == 1)
      DF[[new]][i] <- 1
  }
  DF
}


sp <- split(table[-4], table[-4]$id)
new_df <- do.call(rbind, lapply(sp, fun))
row.names(new_df) <- NULL
identical(table, new_df)
#[1] TRUE

Обратите внимание, что если вы создаете новый столбец, eleg, вам, вероятно, не нужно будет разбивать table[-4], просто table, так как 4-й столбец будетеще не существует.
Вы можете сделать do.call(rbind, lapply(sp, fun, n = 24)), а остальное будет таким же.

0 голосов
/ 13 июня 2018

Один из подходов может быть

library(dplyr)

m <- 3     #number of times previous rows are looked back

df %>%
  group_by(id) %>%
  mutate(eleg = ifelse(rowSums(sapply(1:m, function(k) lag(varx, n = k, order_by = id, default = 1) == 0)) == m & varx == 1, 
                       1, 
                       0)) %>%
  data.frame()

, который дает

   id time varx eleg
1   1    1    0    0
2   1    2    0    0
3   1    3    0    0
4   1    4    0    0
5   1    5    1    1
6   1    6    1    0
7   1    7    0    0
8   2    1    0    0
9   2    2    1    0
10  2    3    1    0
11  2    4    1    0
12  2    5    1    0
13  2    6    1    0
14  3    1    0    0
15  3    2    0    0
16  3    3    0    0
17  3    4    1    1


Пример данных:

df <- structure(list(id = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
3, 3, 3, 3), time = c(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 
1, 2, 3, 4), varx = c(0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 
0, 0, 0, 1)), .Names = c("id", "time", "varx"), row.names = c(NA, 
-17L), class = "data.frame")
0 голосов
/ 13 июня 2018

Вот еще один подход, использующий dplyr и zoo:

library(dplyr)
library(zoo)

df %>% 
  group_by(id) %>% 
  mutate(elegnew = as.integer(varx == 1 & 
                      rollsum(varx == 1, k = 4, align = "right", fill = 0) == 1))

# # A tibble: 17 x 5
# # Groups:   id [3]
# id  time  varx  eleg elegnew
# <dbl> <dbl> <dbl> <dbl>   <int>
#   1    1.    1.    0.    0.       0
# 2    1.    2.    0.    0.       0
# 3    1.    3.    0.    0.       0
# 4    1.    4.    0.    0.       0
# 5    1.    5.    1.    1.       1
# 6    1.    6.    1.    0.       0
# 7    1.    7.    0.    0.       0
# 8    2.    1.    0.    0.       0
# 9    2.    2.    1.    0.       0
# 10    2.    3.    1.    0.       0
# 11    2.    4.    1.    0.       0
# 12    2.    5.    1.    0.       0
# 13    2.    6.    1.    0.       0
# 14    3.    1.    0.    0.       0
# 15    3.    2.    0.    0.       0
# 16    3.    3.    0.    0.       0
# 17    3.    4.    1.    1.       1

Идея состоит в том, чтобы сгруппировать по идентификатору и затем проверить a), равно ли varx 1 и b) равна ли сумма varx =1 событие в предыдущих 3 плюс текущая строка (k = 4) равно 1 (что означает, что все предыдущие 3 должны быть 0).Я предполагаю, что varx либо 0, либо 1.

0 голосов
/ 13 июня 2018
library(data.table)
df %>% 
mutate(elegnew = ifelse(Reduce("+", shift(df$varx, 1:3)) == 0 & df$varx == 1, 1, 0))

   id time varx eleg elegnew
1   1    1    0    0       0
2   1    2    0    0       0
3   1    3    0    0       0
4   1    4    0    0       0
5   1    5    1    1       1
6   1    6    1    0       0
7   1    7    0    0       0
8   2    1    0    0       0
9   2    2    1    0       0
10  2    3    1    0       0
11  2    4    1    0       0
12  2    5    1    0       0
13  2    6    1    0       0
14  3    1    0    0       0
15  3    2    0    0       0
16  3    3    0    0       0
17  3    4    1    1       1
...