Мои данные выглядят так:
year month flag group
1: 1992 6 1 8
2: 1992 7 0 8
3: 1992 8 0 8
4: 1992 9 0 8
5: 1992 10 0 8
6: 1992 11 0 8
7: 1992 12 0 8
8: 1995 6 0 10
9: 1995 7 0 11
10: 1995 8 0 11
11: 1995 9 1 11
12: 1995 10 0 11
13: 1995 11 0 11
14: 1995 12 0 11
15: 1998 6 0 13
16: 1998 7 0 13
17: 1998 8 0 13
18: 1998 9 0 13
19: 1998 10 0 13
20: 1998 11 0 13
21: 1998 12 0 13
Что мне нужно сделать, так это присвоить значение 1 всем строкам, которые следуют за первым наблюдением 1 в столбце flag
, однако это также должно быть сделано group
.
В качестве конкретного примера я хочу этого:
year month flag group
1: 1992 6 1 8
2: 1992 7 1 8
3: 1992 8 1 8
4: 1992 9 1 8
5: 1992 10 1 8
6: 1992 11 1 8
7: 1992 12 1 8
8: 1995 6 0 10
9: 1995 7 0 11
10: 1995 8 0 11
11: 1995 9 1 11
12: 1995 10 1 11
13: 1995 11 1 11
14: 1995 12 1 11
15: 1998 6 0 13
16: 1998 7 0 13
17: 1998 8 0 13
18: 1998 9 0 13
19: 1998 10 0 13
20: 1998 11 0 13
21: 1998 12 0 13
Обратите внимание, что строки 1:7 теперь равны 1, а также строки 11:14, а также обратите внимание, что в строках 15:21 не было никаких изменений, поскольку изначально не было 1.
Большинство моих идей вращались вокруг использования which
, чтобы узнать индекс первого 1 по группе, но я столкнулся с некоторыми проблемами.
Если у кого-то есть какие-либо решения на основе data.table()
, это было бы здорово.
Я ценю любую помощь!
Вот dput()
моих базовых данных, если это будет полезно:
library(data.table)
DT = setDT(structure(list(year = c(1992, 1992, 1992, 1992, 1992, 1992, 1992,
1992, 1992, 1992, 1992, 1992, 1995, 1995, 1995, 1995, 1995, 1995,
1995, 1995, 1995, 1995, 1995, 1995, 1998, 1998, 1998, 1998, 1998,
1998, 1998, 1998, 1998, 1998, 1998, 1998), month = c(1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), flag = c(0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), group = c(8L, 8L, 8L,
8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 10L, 10L, 10L, 10L, 10L,
10L, 11L, 11L, 11L, 11L, 11L, 11L, 13L, 13L, 13L, 13L, 13L, 13L,
13L, 13L, 13L, 13L, 13L, 13L)), row.names = c(NA, -36L),
class = c("data.table", "data.frame")))
Вы можете использовать dplyr
и cumsum
:
library(dplyr)
df %>%
group_by(group) %>%
mutate(flag = ifelse(cumsum(flag) > 1, 1, 0))
Другой способ может заключаться в использовании lag
:
df %>%
group_by(group) %>%
mutate(flag = ifelse(flag != 1 & row_number() > 1, lag(flag, 1), flag))
Или в data.table
как:
df[, flag := ifelse(cumsum(flag) > 1, 1, 0), by=group]
Мы возвращаем 1 для строк из первого вхождения, где flag = 1
и в группе есть хотя бы один flag = 1
library(data.table)
dt[,flag := +(seq_len(.N)>= which.max(flag == 1) & any(flag == 1)),by = group]
dt
# year month flag group
# 1: 1992 6 1 8
# 2: 1992 7 1 8
# 3: 1992 8 1 8
# 4: 1992 9 1 8
# 5: 1992 10 1 8
# 6: 1992 11 1 8
# 7: 1992 12 1 8
# 8: 1995 6 0 10
# 9: 1995 7 0 11
#10: 1995 8 0 11
#11: 1995 9 1 11
#12: 1995 10 1 11
#13: 1995 11 1 11
#14: 1995 12 1 11
#15: 1998 6 0 13
#16: 1998 7 0 13
#17: 1998 8 0 13
#18: 1998 9 0 13
#19: 1998 10 0 13
#20: 1998 11 0 13
#21: 1998 12 0 13
# year month flag group
Что в dplyr
было бы
library(dplyr)
dt %>%
group_by(group) %>%
mutate(flag = +(row_number() >= which.max(flag == 1) & any(flag == 1)))
а в базе R использование ave
будет
dt$flag <- with(dt, +(ave(flag == 1, group, FUN = function(x)
seq_along(x) >= which.max(x) & any(x))))
данные
dt <- structure(list(year = c(1992, 1992, 1992, 1992, 1992, 1992, 1992,
1992, 1992, 1992, 1992, 1992, 1995, 1995, 1995, 1995, 1995, 1995,
1995, 1995, 1995, 1995, 1995, 1995, 1998, 1998, 1998, 1998, 1998,
1998, 1998, 1998, 1998, 1998, 1998, 1998), month = c(1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), flag = c(0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), group = c(8L, 8L, 8L,
8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 10L, 10L, 10L, 10L, 10L,
10L, 11L, 11L, 11L, 11L, 11L, 11L, 13L, 13L, 13L, 13L, 13L, 13L,
13L, 13L, 13L, 13L, 13L, 13L)), row.names = c(NA, -36L), class =
c("data.table","data.frame"))
При использовании вашего ответа data.table()
я получаю следующую ошибку: Error in
[.data.table(stack_dat, ,
:=(flag, as.integer(seq_len(.N) >= : Type of RHS ('integer') must match LHS ('double'). To check and coerce would impact performance too much for the fastest cases. Either change the type of the target column, or coerce the RHS of := yourself (e.g. by using 1L instead of 1)
Кроме того, похоже, что вы сгруппировали по столбцу year
, а не по столбцу group
. Или я неправильно понял ваш код?
@Gin_Salmon да, я сначала сгруппировал по year
. Я изменил группу на group
сейчас, хотя вывод не меняется, и я не получаю ошибку в примерах данных, которые я использовал. Похоже, есть несоответствие типов, попробуйте использовать as.numeric
вместо +
, попробуйте dt[,flag := as.numeric(seq_len(.N)>= which.max(flag == 1) & any(flag == 1)),by=group]
Спасибо за это. У меня есть пара вопросов по коду: зачем нужен any()
и что за ошибка, о которой я изначально говорил, и в чем разница между +
и as.numeric
?
@Gin_Salmon which.max
вычисляет первое максимальное значение в переданном векторе. flag == 1
возвращает вектор значений TRUE
/FALSE
в зависимости от того, равно ли flag
1 или нет, когда мы делаем which.max(flag == 1)
, он возвращает индекс первого максимального значения. Таким образом, в случае, если есть какое-либо значение TRUE
, он вернет индекс первого TRUE
или, если все значения равны FALSE
, тогда максимум будет FALSE
, и он вернет 1. Таким образом, в этом случае он даст 1 всему group
, чтобы избегайте использования any
и проверьте, есть ли flag
со значением 1 в group
.
Что касается +
и as.numeric
, +
преобразует значения TRUE/FALSE
в целые числа, тогда как в вашем столбце были числовые значения, поэтому было несоответствие типов, и, следовательно, вместо +
мы используем as.numeric
, чтобы тип соответствовал исходным столбцам.
Используйте na.locf()
из пакета zoo
Шаг 1: Отфильтруйте группы, содержащие хотя бы одну «1», и замените в них «0» на NA.
Шаг 2: Используйте na.locf()
, чтобы перетащить самое последнее значение, не относящееся к NA, на все, что ниже.
library(zoo)
library(data.table)
temp[group %in% temp[,max(flag),.(group)][V1==1]$group & flag == 0,flag:= NA][,flag:=na.locf(flag,na.rm = FALSE)]
Входная таблица (темп)
structure(list(year = c(1992, 1992, 1992, 1992, 1992, 1992, 1992,
1995, 1995, 1995, 1995, 1995, 1995, 1995, 1998, 1998, 1998, 1998,
1998, 1998, 1998), month = c(6, 7, 8, 9, 10, 11, 12, 6, 7, 8,
9, 10, 11, 12, 6, 7, 8, 9, 10, 11, 12), flag = c(1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), group = c(8L,
8L, 8L, 8L, 8L, 8L, 8L, 10L, 11L, 11L, 11L, 11L, 11L, 11L, 13L,
13L, 13L, 13L, 13L, 13L, 13L)), row.names = c(NA, -21L), class = c("data.table",
"data.frame"))
Выходная таблица
structure(list(year = c(1992, 1992, 1992, 1992, 1992, 1992, 1992,
1995, 1995, 1995, 1995, 1995, 1995, 1995, 1998, 1998, 1998, 1998,
1998, 1998, 1998), month = c(6, 7, 8, 9, 10, 11, 12, 6, 7, 8,
9, 10, 11, 12, 6, 7, 8, 9, 10, 11, 12), flag = c(1, 1, 1, 1,
1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0), group = c(8L,
8L, 8L, 8L, 8L, 8L, 8L, 10L, 11L, 11L, 11L, 11L, 11L, 11L, 13L,
13L, 13L, 13L, 13L, 13L, 13L)), row.names = c(NA, -21L), class = c("data.table",
"data.frame"))
Вы можете выполнить неэквивалентное соединение с первым месяцем для каждой группы:
DT[unique(DT[flag==1], by = "group"), on=.(group, month >= month), flag := 1]
Это результат с выводом из OP:
year month flag group
1: 1992 1 0 8
2: 1992 2 0 8
3: 1992 3 0 8
4: 1992 4 0 8
5: 1992 5 0 8
6: 1992 6 1 8
7: 1992 7 1 8
8: 1992 8 1 8
9: 1992 9 1 8
10: 1992 10 1 8
11: 1992 11 1 8
12: 1992 12 1 8
13: 1995 1 0 10
14: 1995 2 0 10
15: 1995 3 0 10
16: 1995 4 0 10
17: 1995 5 0 10
18: 1995 6 0 10
19: 1995 7 0 11
20: 1995 8 0 11
21: 1995 9 1 11
22: 1995 10 1 11
23: 1995 11 1 11
24: 1995 12 1 11
25: 1998 1 0 13
26: 1998 2 0 13
27: 1998 3 0 13
28: 1998 4 0 13
29: 1998 5 0 13
30: 1998 6 0 13
31: 1998 7 0 13
32: 1998 8 0 13
33: 1998 9 0 13
34: 1998 10 0 13
35: 1998 11 0 13
36: 1998 12 0 13
year month flag group
Ваше
data.table
решение мне не подходит. Он просто присваивает каждому значению 0. Любые предложения?