我正在尝试根据排名创建一个新列,每个月都在变化。以下是样本输入数据。
df <- data.frame(id=c(1,1,1,1,1,1,1,2,2,2,3,3,4),
rank=c(3,1,1,1,1,1,2,2,3,1,1,2,3),
dates=c('2019-06-15','2019-07-15','2019-08-15','2019-09-15','2019-10-15','2019-11-15','2019-12-15',
'2019-10-15','2019-11-15','2019-12-15',
'2019-11-15','2019-12-15','2019-12-15'))
这是预期的输出,我希望从最近的日期开始行。
id rank dates new_col
1 2 2019-12-15 0
2 1 2019-12-15 0
3 2 2019-12-15 1
4 3 2019-12-15 0
new_col
是否表示从6个月的回顾起rank
会增加?例如,如果从12月起的一行是2
,但在10月的一行中是1
,则在十二月行中,我们可以将new_col
= 1。
我们必须将回溯日期限制为6个月。
假设您愿意使用data.table。首先在时间变量之后对数据进行排序。使用shift获取最后2个可用值(在您的情况下为6个),并取最大值。我认为,需要确保每个ID都有完整的时间序列,否则,它将采用最后可用的值。通过比较rank和rank_max,可以确定排名是否已更改。
library(data.table)
df <- data.table(id=c(1,1,1,2,2,2,3,3,3) %>% as.character,
rank=c(1,3,2,2,3,1,1,2,3),
time=rep(1:3,3))
setorder(df, time)
df[, rank_max := do.call(pmax, shift(rank, 1:2, type = "lag")), by=id]
id rank time rank_max
1: 1 1 1 NA
2: 2 2 1 NA
3: 3 1 1 NA
4: 1 3 2 NA
5: 2 3 2 NA
6: 3 2 2 NA
7: 1 2 3 3
8: 2 1 3 3
9: 3 3 3 2
这里是在data.table
中使用非等价联接的选项:
#convert into IDate and get dates from 6m ago
DT[, dates := as.IDate(dates, format="%Y-%m-%d")][, c("start", "end") :=
.(as.IDate(sapply(dates, function(x) seq(x, by="-6 months", length.out=2L)[2L])), dates)]
#extract latest rows for each id
latest <- DT[DT[, .I[.N], id]$V1]
#non-equi join and for each latest date of each id, check if the current rank is the highest over last 6m
DT[latest, on=.(id, dates>=start, dates<end),
by=.EACHI, {
a <- +all(i.rank > x.rank)
.(new_col=replace(a, is.na(a), 0L))
}]
输出:
id dates dates new_col
1: 1 2019-06-15 2019-12-15 0
2: 2 2019-06-15 2019-12-15 0
3: 3 2019-06-15 2019-12-15 1
4: 4 2019-06-15 2019-12-15 0
数据:
library(data.table)
DT <- data.table(id=c(1,1,1,1,1,1,1,2,2,2,3,3,4),
rank=c(3,1,1,1,1,1,2,2,3,1,1,2,3),
dates=c('2019-06-15','2019-07-15','2019-08-15','2019-09-15','2019-10-15','2019-11-15','2019-12-15',
'2019-10-15','2019-11-15','2019-12-15',
'2019-11-15','2019-12-15','2019-12-15'))