Изменять новый столбец на основе индекса ближайшего значения TRUE из другого столбца - PullRequest
3 голосов
/ 19 марта 2020

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

  1. Кадр данных сначала будет сгруппирован в соответствии со столбцом x
  2. Получить индекс значений TRUE в b
  3. Новый столбец должен содержать индекс ближайшего значения TRUE, предшествующего значению TRUE в b. Если в a имеется более одного значения TRUE, получите только индекс ближайшего значения TRUE до b.
  4. Полученное значение индекса будет помещено в ту же строку, что и TRUE значение в b.

Вот мои примеры данных:

x = rep(c(1:5), each = 10)

a = c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)

b = c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, 
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE)

df <- data.frame(x ,a, b)

У меня есть этот код, который не дает желаемого результата:

df %>%
  group_by(x) %>%
  mutate(xx = ifelse(b == TRUE, 
                     which(b)[findInterval(which(a), which(b))], 
                     NA))

Мой желаемый результат выглядит следующим образом:

   x     a     b xx
1  1  TRUE FALSE NA
2  1 FALSE FALSE NA
3  1 FALSE FALSE NA
4  1 FALSE  TRUE  1
5  1 FALSE FALSE NA
6  1 FALSE FALSE NA
7  1  TRUE FALSE NA
8  1 FALSE FALSE NA
9  1 FALSE FALSE NA
10 1 FALSE  TRUE  7
11 2 FALSE FALSE NA
12 2 FALSE FALSE NA
13 2 FALSE FALSE NA
14 2 FALSE FALSE NA
15 2 FALSE FALSE NA
16 2 FALSE FALSE NA
17 2 FALSE FALSE NA
18 2 FALSE  TRUE NA
19 2 FALSE FALSE NA
20 2 FALSE FALSE NA
21 3 FALSE FALSE NA
22 3 FALSE FALSE NA
23 3  TRUE FALSE NA
24 3 FALSE FALSE NA
25 3 FALSE FALSE NA
26 3 FALSE FALSE NA
27 3 FALSE FALSE NA
28 3 FALSE FALSE NA
29 3 FALSE FALSE NA
30 3 FALSE FALSE NA
31 4 FALSE FALSE NA
32 4 FALSE FALSE NA
33 4 FALSE FALSE NA
34 4  TRUE FALSE NA
35 4 FALSE FALSE NA
36 4  TRUE FALSE NA
37 4 FALSE FALSE NA
38 4 FALSE FALSE NA
39 4 FALSE  TRUE 36
40 4 FALSE FALSE NA
41 5 FALSE FALSE NA
42 5  TRUE FALSE NA
43 5 FALSE FALSE NA
44 5 FALSE FALSE NA
45 5 FALSE FALSE NA
46 5 FALSE FALSE NA
47 5 FALSE FALSE NA
48 5 FALSE FALSE NA
49 5 FALSE  TRUE 42
50 5 FALSE FALSE NA

Я также думал о преобразовании кадра данных в список и использовании map (), но я не знаю, как действовать дальше. ..

df %>% split(.$x) %>%
  map(~mutate(xx = ifelse(b == TRUE, 
                          which(b)[findInterval(which(a), which(b))], 
                          NA)))

Ответы [ 2 ]

1 голос
/ 19 марта 2020

A dplyr версия с использованием findInterval.

library(dplyr)

df %>%
  mutate(row = row_number(), xx = NA) %>%
  group_by(x) %>%
  mutate(xx = replace(xx, b,
              row[a][findInterval(row[b], row[a])][seq_len(sum(b))])) %>%
  select(-row) %>%
  data.frame()

это возвращает:

#   x     a     b xx
#1  1  TRUE FALSE NA
#2  1 FALSE FALSE NA
#3  1 FALSE FALSE NA
#4  1 FALSE  TRUE  1
#5  1 FALSE FALSE NA
#6  1 FALSE FALSE NA
#7  1  TRUE FALSE NA
#8  1 FALSE FALSE NA
#9  1 FALSE FALSE NA
#10 1 FALSE  TRUE  7
#11 2 FALSE FALSE NA
#12 2 FALSE FALSE NA
#13 2 FALSE FALSE NA
#14 2 FALSE FALSE NA
#15 2 FALSE FALSE NA
#16 2 FALSE FALSE NA
#17 2 FALSE FALSE NA
#18 2 FALSE  TRUE NA
#19 2 FALSE FALSE NA
#20 2 FALSE FALSE NA
#21 3 FALSE FALSE NA
#22 3 FALSE FALSE NA
#23 3  TRUE FALSE NA
#24 3 FALSE FALSE NA
#25 3 FALSE FALSE NA
#26 3 FALSE FALSE NA
#27 3 FALSE FALSE NA
#28 3 FALSE FALSE NA
#29 3 FALSE FALSE NA
#30 3 FALSE FALSE NA
#31 4 FALSE FALSE NA
#32 4 FALSE FALSE NA
#33 4 FALSE FALSE NA
#34 4  TRUE FALSE NA
#35 4 FALSE FALSE NA
#36 4  TRUE FALSE NA
#37 4 FALSE FALSE NA
#38 4 FALSE FALSE NA
#39 4 FALSE  TRUE 36
#40 4 FALSE FALSE NA
#41 5 FALSE FALSE NA
#42 5  TRUE FALSE NA
#43 5 FALSE FALSE NA
#44 5 FALSE FALSE NA
#45 5 FALSE FALSE NA
#46 5 FALSE FALSE NA
#47 5 FALSE FALSE NA
#48 5 FALSE FALSE NA
#49 5 FALSE  TRUE 42
#50 5 FALSE FALSE NA

Основной лог c находится в строке mutate, где мы replace значения NA в позиции b по индексу (номеру строки) ближайшего значения a.

1 голос
/ 19 марта 2020

Не dplyr, но этот by подход работает (хотя и не очень элегантно). by внутренне разбивает данные на x -группы, сохраняет в w, который b равен TRUE, и возвращает вектор value-else- NA, где value это тот, где cumsum из a == TRUE соответствует значению w.

df$xx <- as.numeric(unlist(by(df, df$x, function(s) {
  o <- rep(NA, nrow(s))
  if (!(any(s$a) & any(s$b))) o
  else {
    w <- which(s$b)
    y <- cumsum(s$a)[w]
    mapply(function(z, v) o[v] <<- rownames(s)[el(which(cumsum(s$a) == z))], y, w)
    return(o)
  }
})))

Результат

df
#    x     a     b xx
# 1  1  TRUE FALSE NA
# 2  1 FALSE FALSE NA
# 3  1 FALSE FALSE NA
# 4  1 FALSE  TRUE  1
# 5  1 FALSE FALSE NA
# 6  1 FALSE FALSE NA
# 7  1  TRUE FALSE NA
# 8  1 FALSE FALSE NA
# 9  1 FALSE FALSE NA
# 10 1 FALSE  TRUE  7
# 11 2 FALSE FALSE NA
# 12 2 FALSE FALSE NA
# 13 2 FALSE FALSE NA
# 14 2 FALSE FALSE NA
# 15 2 FALSE FALSE NA
# 16 2 FALSE FALSE NA
# 17 2 FALSE FALSE NA
# 18 2 FALSE  TRUE NA
# 19 2 FALSE FALSE NA
# 20 2 FALSE FALSE NA
# 21 3 FALSE FALSE NA
# 22 3 FALSE FALSE NA
# 23 3  TRUE FALSE NA
# 24 3 FALSE FALSE NA
# 25 3 FALSE FALSE NA
# 26 3 FALSE FALSE NA
# 27 3 FALSE FALSE NA
# 28 3 FALSE FALSE NA
# 29 3 FALSE FALSE NA
# 30 3 FALSE FALSE NA
# 31 4 FALSE FALSE NA
# 32 4 FALSE FALSE NA
# 33 4 FALSE FALSE NA
# 34 4  TRUE FALSE NA
# 35 4 FALSE FALSE NA
# 36 4  TRUE FALSE NA
# 37 4 FALSE FALSE NA
# 38 4 FALSE FALSE NA
# 39 4 FALSE  TRUE 36
# 40 4 FALSE FALSE NA
# 41 5 FALSE FALSE NA
# 42 5  TRUE FALSE NA
# 43 5 FALSE FALSE NA
# 44 5 FALSE FALSE NA
# 45 5 FALSE FALSE NA
# 46 5 FALSE FALSE NA
# 47 5 FALSE FALSE NA
# 48 5 FALSE FALSE NA
# 49 5 FALSE  TRUE 42
# 50 5 FALSE FALSE NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...