Точный выбор на основе% в% - PullRequest
6 голосов
/ 31 мая 2019

У меня проблемы с выполнением простой операции.

Я хочу просто выбрать строки, сгруппированные по id, которые имеют все значения (-1, -2, -3, -4), и применить тег на основе этого условия.

   id time
1   1   -4
2   1   -3
3   1   -2
4   1   -1
5   2   -1
6   2   -2
7   3   -1
8   3   -3
9   4   -1
10  4   -2
11  4   -3
12  4   -4

Интуитивно я шел за

rb[rb$time %in% c(-1, -2, -3, -4), ]

Однако, когда я делаю это, все id выбираются. Таким образом, оператор %in% использует оператор OR |.

Итак, я думал, что смогу сделать это тогда, используя оператор AND &

rb[rb$time == -1 & 
 rb$time == -2 & 
 rb$time == -3 & 
 rb$time == -4, ]

Но это не работает.

Любая подсказка, как я могу пометить или поднастроить эти id, например,

   id time tag
1   1   -4   1
2   1   -3   1
3   1   -2   1
4   1   -1   1
5   2   -1   0
6   2   -2   0
7   3   -1   0
8   3   -3   0
9   4   -1   1
10  4   -2   1
11  4   -3   1
12  4   -4   1

Ответы [ 4 ]

7 голосов
/ 31 мая 2019

Одна dplyr возможность может быть:

df %>%
 group_by(id) %>%
 mutate(tag = all(c(-1, -2, -3, -4) %in% time) * 1)

      id  time   tag
   <int> <int> <dbl>
 1     1    -4     1
 2     1    -3     1
 3     1    -2     1
 4     1    -1     1
 5     2    -1     0
 6     2    -2     0
 7     3    -1     0
 8     3    -3     0
 9     4    -1     1
10     4    -2     1
11     4    -3     1
12     4    -4     1

И то же самое с base R может быть:

with(df, ave(time, id, FUN = function(x) all(c(-1, -2, -3, -4) %in% x) * 1))
1 голос
/ 31 мая 2019

Одна из многих опций базового R - использовать aggregate (мы могли бы также переименовать и преобразовать в целое число, чтобы получить 0 или 1, но логические значения лучше подходят для этой цели):

tags <- aggregate(df$time, by = df["id"], FUN = function(el) all(-1:-4 %in% el))
df <- merge(df, tags)

Результат:

df
#    id time     x
# 1   1   -4  TRUE
# 2   1   -3  TRUE
# 3   1   -2  TRUE
# 4   1   -1  TRUE
# 5   2   -1 FALSE
# 6   2   -2 FALSE
# 7   2   -1 FALSE
# 8   2   -3 FALSE
# 9   3   -1  TRUE
# 10  3   -2  TRUE
# 11  3   -3  TRUE
# 12  3   -4  TRUE
0 голосов
/ 31 мая 2019

Вот еще одно базовое решение, использующее vapply и .subset2 (менее читабельное, чем $ или [], но гораздо более эффективное)

rb[['tag']] <- 0L
id_col <- .subset2(rb, 1L)
vapply(unique(rb$id), 
       function (id) {
         index <- id_col == id
         test <- all(sort(.subset2(rb, 2L)[index]) == -4:-1)
         rb[['tag']][index] <<- as.integer(test)
         test
         }, 
       logical(1))
rb
#    id time tag
# 1   1   -4   1
# 2   1   -3   1
# 3   1   -2   1
# 4   1   -1   1
# 5   2   -1   0
# 6   2   -2   0
# 7   3   -1   0
# 8   3   -3   0
# 9   4   -1   1
# 10  4   -2   1
# 11  4   -3   1
# 12  4   -4   1
0 голосов
/ 31 мая 2019

Чтобы добавить больше параметров, вот data.table, который должен иметь значительные преимущества в производительности:

dt <- as.data.table(df)[, tag := all(-1:-4 %in% time), by = id]

Результат:

dt
#     id time   tag
#  1:  1   -4  TRUE
#  2:  1   -3  TRUE
#  3:  1   -2  TRUE
#  4:  1   -1  TRUE
#  5:  2   -1 FALSE
#  6:  2   -2 FALSE
#  7:  2   -1 FALSE
#  8:  2   -3 FALSE
#  9:  3   -1  TRUE
# 10:  3   -2  TRUE
# 11:  3   -3  TRUE
# 12:  3   -4  TRUE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...