【问题标题】:Find minimum value of conditional statement where condition is also met for all values after找到条件语句的最小值,其中条件也满足之后的所有值
【发布时间】:2018-05-14 09:22:19
【问题描述】:

我想确定第一个小于 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 &lt; 1))],但这显然缺少额外的条件要求

【问题讨论】:

  • @bouncyball,谢谢你的收获。你是对的。编辑了我的问题。

标签: r data.table


【解决方案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

【讨论】:

  • 并不总是有效。例如,identical(mtd1(), mtd2()) 在运行DT[a == 3, b := .99] 之后是FALSE
  • 对不起,我的意思是如果你按照问题中的定义使用stack 执行DT &lt;- stack,然后运行DT[a == 3, b := .99] 然后identical(mtd1(), mtd2())FALSE
  • 在这种情况下,答案不应该是 a==3,因为 b 在第 4 行中大于 1。
  • 啊好吧。让我修复 b
  • 用 e.g. 测试可能更好。 b=10*runif(M),否则一切都小于 1,从而使 b &lt; 1 条件无关紧要。
【解决方案2】:
stack[which(b < 1 &
            sapply(seq_len(.N), 
                   function(i) all(b[min(.N, i + 1):nrow(stack)] <= b[i]))
            )[1]]

如果b[i] &lt; 1b[i + x] &lt;= b[i] 我们不需要检查b[i + x] &lt; 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))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    相关资源
    最近更新 更多