我有一个事件日期的数据集(日期格式),每个事件都属于一个(未知的)剧集。我想将事件分类为剧集,以便剧集第一天后 180 天内的所有事件都被视为同一集的一部分,并且剧集的第一天分配给该集的所有事件部分。例如,给定事件日期的向量
event_dates <- c(34, 102, 190, 202, 245, 460, 500, 517)
我希望得到剧集 ID 的向量
c(1, 1, 1, 1, 2, 3, 3, 3)
和剧集开始天数的载体
c(34, 34, 34, 34, 245, 460, 460, 460)
第5个条目开始新剧集,因为它比第一集的第一个日期晚了180多天;第6个条目开始新一集,因为它比第二集的第一个日期晚了180多天,依此类推。
我确实对数百万单独的患者进行了此操作,因此理想情况下,我更喜欢可以在data.table
或分组tibble
中与by
一起使用的矢量化解决方案,即使它有点不透明而不是可读但缓慢的解决方案,我目前拥有。谢谢!
使用末尾注释中的event_dates(从问题中复制),这里有两种方法。
1) 减少循环事件Reduce
的使用:
f <- function(base, x) if (x > base + 180) x else base
st <- Reduce(f, init = -Inf, event_dates, acc = TRUE)[-1]; st
## [1] 34 34 34 34 245 460 460 460
as.numeric(factor(st))
## [1] 1 1 1 1 2 3 3 3
2) for 循环 循环访问值,维护一个变量base
,即最新的 baes 值。
base <- -Inf
st <- event_dates
for(i in seq_along(event_dates)) {
if (st[i] > base + 180) base <- st[i]
st[i] <- base
}
st
## [1] 34 34 34 34 245 460 460 460
as.numeric(factor(out))
## [1] 1 1 1 1 2 3 3 3
3) C++
在当前目录中创建一个名为 event_dates.cpp 的文件,其中包含:
// To build & load: library(Rcpp); source("event_dates.cpp")
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector grouper(NumericVector x) {
NumericVector y(clone(x));
int n = y.size();
double base = y[0] - 200;
for(int i = 0; i < n; i++) {
if (y[i] > base + 180.0) base = y[i];
y[i] = base;
}
return y;
}
然后运行这个。
library(Rcpp)
sourceCpp("event_dates.cpp")
st <- grouper(event_dates); st
## [1] 34 34 34 34 245 460 460 460
as.numeric(factor(st))
## [1] 1 1 1 1 2 3 3 3
注意
event_dates <- c(34, 102, 190, 202, 245, 460, 500, 517)
使用while
循环
event_grp <- event_dates
tmp <- event_dates
index <- rep(1, length(event_dates))
i <- 1
while(TRUE) {
to_compare <- event_dates[i]
i1 <- which((tmp - to_compare) > 180)[1] -1
if(is.na(i1)) i1 <- length(event_dates)
event_grp[i:i1] <- to_compare
if(i > 1) index[i:i1] <- index[i-1] + 1
tmp[i:i1] <- NA
if(i1 == length(event_dates)) break
i <- i1+1
}
-输出
> event_grp
[1] 34 34 34 34 245 460 460 460
> index
[1] 1 1 1 1 2 3 3 3