1)正则表达式 我们将每列的元素粘贴在一起,然后在结果字符串中搜索所有内容,包括最后一次出现的01
. 然后返回此匹配的长度(即匹配不仅包括 01,还包括所有内容):
f <- function(x) attr(regexpr(".*01", paste(x, collapse = "")), "match.length")
apply(df, 2, f)
[1] 3 5 8
请注意,如果 01 没有出现在列中,那么它将为该列返回 -1。
2) rollapply 在这个解决方案中,我们将宽度为 2 的每个滚动部分与 0:1 进行比较,并返回最后一个的索引:
tmp <- rbind(1L, coredata(df), 0L)
max.col(t(rollapply(tmp, 2, identical, c(0,1))), "last")
[1] 3 5 8
如果列中没有匹配项,它会nrow(df)+1
为该列返回。
3) gt在这个解决方案中,我们使用大于比较(或小于比较取决于哪个项是第一个)将每个元素与下一个元素进行比较。
> cdf <- coredata(df)
> max.col(cbind(TRUE, t(cdf[-nrow(df),] < cdf[-1,])), "last")
[1] 3 5 8
如果一列不应该匹配,它会为该列返回 1(如果存在匹配,这不是可能的返回值)。
这是速度比较。输出是 100 次复制的经过时间。输出按升序排列,表示 100 次复制的秒数,因此最快的 (gt) 排在第一位。
> library(xts)
> library(rbenchmark)
> benchmark(order = "elapsed",
+ gt = { cdf <- coredata(df); max.col(cbind(TRUE, t(cdf[-nrow(df),] < cdf[-1,])), "last") },
+ regexpr = apply(df, 2, f),
+ rollapply = { tmp <- rbind(1L, coredata(df), 0L)
+ max.col(t(rollapply(tmp, 2, identical, c(0,1))), "last") },
+ diff = { df.diff = t(diff(df)[-1])
+ max.col(df.diff, "last") + 1 + (rowSums(df.diff > 0) == 0) },
+ intersect = { n <- nrow(df); cols <- 1:ncol(df)
+ lastdays <- sapply(cols,function(j){max(intersect(which(df[2:n,j]==1),which(df[1:(n-1),j]==0)))+1})
+ data.frame(cols,lastdays) })
test replications elapsed relative user.self sys.self user.child sys.child
1 gt 100 0.02 1.0 0.02 0 NA NA
2 regexpr 100 0.05 2.5 0.04 0 NA NA
4 diff 100 0.09 4.5 0.10 0 NA NA
5 intersect 100 0.26 13.0 0.27 0 NA NA
3 rollapply 100 0.84 42.0 0.85 0 NA NA
>
我还使用 100,000 行从上面尝试了 10 次最快的三个复制,在这种情况下, gt 仍然是最快的,并且在该比例下,diff 已经上升到第二位。
> df <- xts(coredata(df)[rep(1:10, each = 10000), ], Sys.Date() + 1:100000)
> dim(df)
[1] 100000 3
> library(rbenchmark)
> benchmark(order = "elapsed", replications = 10,
+ gt = { cdf <- coredata(df); max.col(cbind(TRUE, t(cdf[-nrow(df),] < cdf[-1,])), "last") },
+ regexpr = apply(df, 2, f),
+ diff = { df.diff = t(diff(df)[-1])
+ max.col(df.diff, "last") + 1 + (rowSums(df.diff > 0) == 0) })
test replications elapsed relative user.self sys.self user.child sys.child
1 gt 10 0.32 1.000 0.31 0.00 NA NA
3 diff 10 6.04 18.875 5.91 0.12 NA NA
2 regexpr 10 8.31 25.969 8.01 0.31 NA NA
更新 1:已修复,因此需要最后而不是第一个。它现在也适用于有问题的 dput 输出,而不是数据框。也简化了。
更新 2:添加了第二个解决方案。
更新 3:添加了性能比较(仅限于手头的数据)。
更新 4:添加了第三种方法。