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 行を使用して、上記の 3 つの最速のレプリケーションを 10 回試みましたが、その場合でも gt が最速であり、そのスケールでは diff が 2 位に上昇しました。
> 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: 2 番目のソリューションを追加しました。
更新 3: パフォーマンス比較を追加しました (手元のデータに限定)。
更新 4: 3 番目の方法を追加しました。