我想确定第一个小于 1 的值,并且此元素后面的所有值也小于 1 且小于或等于该值。
我有一个DT:
stack <- data.table(a = as.numeric(seq(1,10,1)),
b = as.numeric(c(1.54, 1.17, 0.75, 1.65, 0.61, 0.31, 0.90, 0.07, 0.04, 0.01)),
ID = as.numeric(rep(seq(1,2,1),5)))
stack
a b ID
1: 1 1.54 1
2: 2 1.17 2
3: 3 0.75 1
4: 4 1.65 2
5: 5 0.61 1
6: 6 0.31 2
7: 7 0.90 1
8: 8 0.07 2
9: 9 0.04 1
10: 10 0.01 2
我在此示例中查找的值将是第 7 行:
a b ID
7: 7 0.90 1
这是第一个小于 1 的值,其中后面的所有值都小于 1,并且也小于或等于该值。我对从第a
列返回值特别感兴趣。
我已经尝试过stack[,min(which(b < 1))]
但这显然缺少额外的条件要求
另一种方法:
library(data.table)
set.seed(0L)
M <- 1e4
DT <- data.table(a=1:M, b=10*runif(M))
mtd1 <- function() {
DT[which(b < 1 &
sapply(seq_len(.N),
function(i) all(b[min(.N, i + 1):nrow(DT)] <= b[i]))
)[1]]
}
mtd2 <- function() {
DT[order(-b), .SD[b < 1][1L]]
}
identical(mtd1(), mtd2())
#[1] TRUE
library(microbenchmark)
microbenchmark(mtd1(), mtd2(), times=3L)
计时:
Unit: milliseconds
expr min lq mean median uq max neval
mtd1() 737.5113 754.3420 766.047900 771.1728 780.31620 789.4596 3
mtd2() 1.6830 1.7687 3.118033 1.8544 3.83555 5.8167 3
stack[which(b < 1 &
sapply(seq_len(.N),
function(i) all(b[min(.N, i + 1):nrow(stack)] <= b[i]))
)[1]]
如果b[i] < 1
和b[i + x] <= b[i]
我们不需要检查是否b[i + x] < 1
或者通过ID
fun <- function(b){
N <- length(b)
which(b < 1 &
sapply(seq_len(N),
function(i) all(b[min(N, i + 1):N] <= b[i]))
)[1] == seq_len(N)
}
setorder(stack, ID)
stack[stack[, fun(b), by = ID]$V1]
编辑:
我无法删除这篇文章,因为它已被接受,但我意识到这在许多情况下给出了不正确的答案,例如下面的答案。另一个答案是正确的(无论如何要快得多(。
set.seed(0)
DT <- data.table(a=1:10, b=1.1*runif(10))