В data.table
ниже для каждой групповой переменной id
базовое значение для столбца event
равно 1 или -1. Иногда генерируется новое событие, которое заменяет эти базовые значения. Новые значения событий могут быть любыми числовыми значениями, кроме 1 или -1. Я хочу распространять значение события для каждой группы до тех пор, пока не произойдет следующее новое событие.
temp_dt = structure(list(date = structure(c(18263L, 18264L, 18267L, 18268L,
18269L, 18270L, 18271L, 18274L, 18275L, 18276L, 18277L, 18278L,
18282L, 18283L, 18284L, 18285L, 18288L, 18289L, 18290L, 18291L,
18292L, 18295L, 18296L, 18297L, 18298L, 18299L, 18302L, 18303L,
18304L, 18305L, 18306L, 18310L, 18311L, 18312L, 18313L, 18316L,
18317L, 18318L, 18319L, 18320L, 18323L, 18324L, 18325L, 18326L,
18327L, 18330L, 18331L, 18332L, 18333L, 18334L, 18337L, 18338L,
18339L, 18340L, 18341L, 18344L, 18345L, 18346L, 18347L, 18348L
), class = c("IDate", "Date")), id = c(43L, 43L, 43L, 43L, 43L,
43L, 43L, 43L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L,
44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L, 44L,
44L, 44L, 44L, 44L, 44L, 44L, 45L, 45L, 45L, 45L, 45L, 45L, 45L,
45L, 45L, 45L, 45L, 45L, 45L, 45L, 45L, 45L, 45L, 45L, 45L, 45L,
45L, 45L, 45L), event = c(-1, -1, -1, -1, -1, -1, -1, -1, 1,
1, 1, 1, 1, 1, -4, 1, 1, 1, 1, 1, 1, -2, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1)), row.names = c(NA,
-60L), class = c("data.table", "data.frame"))
> head(temp_dt, 20)
date id event
1: 2020-01-02 43 -1
2: 2020-01-03 43 -1
3: 2020-01-06 43 -1
4: 2020-01-07 43 -1
5: 2020-01-08 43 -1
6: 2020-01-09 43 -1
7: 2020-01-10 43 -1
8: 2020-01-13 43 -1
9: 2020-01-14 44 1
10: 2020-01-15 44 1
11: 2020-01-16 44 1
12: 2020-01-17 44 1
13: 2020-01-21 44 1
14: 2020-01-22 44 1
15: 2020-01-23 44 -4
16: 2020-01-24 44 1
17: 2020-01-27 44 1
18: 2020-01-28 44 1
19: 2020-01-29 44 1
20: 2020-01-30 44 1
Вот желаемый результат, а ожидаемый результат указан в столбце signal
date id event signal
1: 2020-01-02 43 -1 -1
2: 2020-01-03 43 -1 -1
3: 2020-01-06 43 -1 -1
4: 2020-01-07 43 -1 -1
5: 2020-01-08 43 -1 -1
6: 2020-01-09 43 -1 -1
7: 2020-01-10 43 -1 -1
8: 2020-01-13 43 -1 -1
9: 2020-01-14 44 1 1
10: 2020-01-15 44 1 1
11: 2020-01-16 44 1 1
12: 2020-01-17 44 1 1
13: 2020-01-21 44 1 1
14: 2020-01-22 44 1 1
15: 2020-01-23 44 -4 -4
16: 2020-01-24 44 1 -4
17: 2020-01-27 44 1 -4
18: 2020-01-28 44 1 -4
19: 2020-01-29 44 1 -4
20: 2020-01-30 44 1 -4
21: 2020-01-31 44 1 -4
22: 2020-02-03 44 -2 -2
23: 2020-02-04 44 1 -2
24: 2020-02-05 44 1 -2
25: 2020-02-06 44 1 -2
26: 2020-02-07 44 1 -2
27: 2020-02-10 44 1 -2
28: 2020-02-11 44 1 -2
29: 2020-02-12 44 1 -2
30: 2020-02-13 44 1 -2
31: 2020-02-14 44 1 -2
32: 2020-02-18 44 1 -2
33: 2020-02-19 44 1 -2
34: 2020-02-20 44 1 -2
35: 2020-02-21 44 1 -2
36: 2020-02-24 44 1 -2
37: 2020-02-25 44 1 -2
38: 2020-02-26 45 -1 -1
39: 2020-02-27 45 -2 -2
40: 2020-02-28 45 -1 -2
41: 2020-03-02 45 -1 -2
42: 2020-03-03 45 -1 -2
43: 2020-03-04 45 -1 -2
44: 2020-03-05 45 -1 -2
45: 2020-03-06 45 -1 -2
46: 2020-03-09 45 -1 -2
47: 2020-03-10 45 -1 -2
48: 2020-03-11 45 -1 -2
49: 2020-03-12 45 -1 -2
50: 2020-03-13 45 -1 -2
51: 2020-03-16 45 -1 -2
52: 2020-03-17 45 -1 -2
53: 2020-03-18 45 4 4
54: 2020-03-19 45 -1 4
55: 2020-03-20 45 -1 4
56: 2020-03-23 45 -1 4
57: 2020-03-24 45 -1 4
58: 2020-03-25 45 -1 4
59: 2020-03-26 45 -1 4
60: 2020-03-27 45 -1 4
date id event signal
Мое решение этой проблемы почему-то работает не так, как ожидалось. Может ли кто-нибудь указать, что я делаю неправильно?
temp_dt[, signal:= ifelse(abs(event) == 1 & shift(abs(event)) != 1, shift(event), event) , by = id]
date id event signal
1: 2020-01-02 43 -1 NA
2: 2020-01-03 43 -1 -1
3: 2020-01-06 43 -1 -1
4: 2020-01-07 43 -1 -1
5: 2020-01-08 43 -1 -1
6: 2020-01-09 43 -1 -1
7: 2020-01-10 43 -1 -1
8: 2020-01-13 43 -1 -1
9: 2020-01-14 44 1 NA
10: 2020-01-15 44 1 1
11: 2020-01-16 44 1 1
12: 2020-01-17 44 1 1
13: 2020-01-21 44 1 1
14: 2020-01-22 44 1 1
15: 2020-01-23 44 -4 -4
16: 2020-01-24 44 1 -4
17: 2020-01-27 44 1 1
18: 2020-01-28 44 1 1
Вот еще одна попытка
temp_dt[, signal := {
rn <- 1:.N
i2 <- which(abs(event) != 1)
fcase(
rn %inrange% .(i2 + 1, i2 + 3), event,
rn %in% i2, event
)}, by = id]
Вот еще одна попытка, но у нее тоже есть проблемы -
temp_dt[, signal := cummax(abs(event)), by = id]
В противном случае будет оценено простое data.table
решение без использования joins
.
Вот способ сделать это БЕЗ data.table в базе R. Надеюсь, кто-то скоро даст вам эффективное решение для соединения data.table!
# split by group
L <- split(temp_dt, temp_dt[,id])
for(i in 1:length(L)){
# ensure date is ordered oldest to newest
L[[i]] <- L[[i]][order(date)]
# prepare to loop through all rows except the last one
n <- nrow(L[[i]])-1
for(j in 1:n){
# if current row is not default and next row is default
if (abs(L[[i]][j, event]) != 1 & abs(L[[i]][j + 1, event]) == 1){
# carry not default forward
L[[i]][j + 1, "event"] = L[[i]][j, event]
}
}
}
# turns lists of data.tables into one data.table
new_signal <- rbindlist(L)
# rename the event column to "signal"
colnames(new_signal) <- c("date","id","signal")
# merge them together for your answer
temp_dt <- merge(temp_dt, new_signal)
Подход с использованием data.table
.
library(data.table)
setDT(emp_dt)[, signal := fifelse(event != shift(event), event, NA_real_), by = id]
emp_dt[, signal := fifelse(abs(event) != 1, signal, NA_real_), by = id]
emp_dt[, signal := fifelse(rowidv(event) == 1, event, signal), by = id]
setnafill(emp_dt, cols = "signal", type = "locf")
emp_dt
#> date id event signal
#> 1: 2020-01-02 43 -1 -1
#> 2: 2020-01-03 43 -1 -1
#> 3: 2020-01-06 43 -1 -1
#> 4: 2020-01-07 43 -1 -1
#> 5: 2020-01-08 43 -1 -1
#> 6: 2020-01-09 43 -1 -1
#> 7: 2020-01-10 43 -1 -1
#> 8: 2020-01-13 43 -1 -1
#> 9: 2020-01-14 44 1 1
#> 10: 2020-01-15 44 1 1
#> 11: 2020-01-16 44 1 1
#> 12: 2020-01-17 44 1 1
#> 13: 2020-01-21 44 1 1
#> 14: 2020-01-22 44 1 1
#> 15: 2020-01-23 44 -4 -4
#> 16: 2020-01-24 44 1 -4
#> 17: 2020-01-27 44 1 -4
#> 18: 2020-01-28 44 1 -4
#> 19: 2020-01-29 44 1 -4
#> 20: 2020-01-30 44 1 -4
#> 21: 2020-01-31 44 1 -4
#> 22: 2020-02-03 44 -2 -2
#> 23: 2020-02-04 44 1 -2
#> 24: 2020-02-05 44 1 -2
#> 25: 2020-02-06 44 1 -2
#> 26: 2020-02-07 44 1 -2
#> 27: 2020-02-10 44 1 -2
#> 28: 2020-02-11 44 1 -2
#> 29: 2020-02-12 44 1 -2
#> 30: 2020-02-13 44 1 -2
#> 31: 2020-02-14 44 1 -2
#> 32: 2020-02-18 44 1 -2
#> 33: 2020-02-19 44 1 -2
#> 34: 2020-02-20 44 1 -2
#> 35: 2020-02-21 44 1 -2
#> 36: 2020-02-24 44 1 -2
#> 37: 2020-02-25 44 1 -2
#> 38: 2020-02-26 45 -1 -1
#> 39: 2020-02-27 45 -2 -2
#> 40: 2020-02-28 45 -1 -2
#> 41: 2020-03-02 45 -1 -2
#> 42: 2020-03-03 45 -1 -2
#> 43: 2020-03-04 45 -1 -2
#> 44: 2020-03-05 45 -1 -2
#> 45: 2020-03-06 45 -1 -2
#> 46: 2020-03-09 45 -1 -2
#> 47: 2020-03-10 45 -1 -2
#> 48: 2020-03-11 45 -1 -2
#> 49: 2020-03-12 45 -1 -2
#> 50: 2020-03-13 45 -1 -2
#> 51: 2020-03-16 45 -1 -2
#> 52: 2020-03-17 45 -1 -2
#> 53: 2020-03-18 45 4 4
#> 54: 2020-03-19 45 -1 4
#> 55: 2020-03-20 45 -1 4
#> 56: 2020-03-23 45 -1 4
#> 57: 2020-03-24 45 -1 4
#> 58: 2020-03-25 45 -1 4
#> 59: 2020-03-26 45 -1 4
#> 60: 2020-03-27 45 -1 4
#> date id event signal
Created on 2023-04-10 with reprex v2.0.2
Добавьте кумулятивную сумму того, равно ли event
-1 или 1, к группе и возьмите первый элемент event
для каждой группы:
temp_dt[, signal := event[1], .(id, grp = cumsum(!(event %in% c(-1, 1))))]
Альтернативно,
temp_dt[, signal := event[1], .(id, grp = cumsum(abs(event) - 1))]
Спасибо, ДжейБлад. Это самое простое однострочное решение.
Вау, это действительно простое решение. Спасибо, НикХр.