【问题标题】:Subset using i statement dynamically created from another data.table's variables使用从另一个 data.table 的变量动态创建的 i 语句的子集
【发布时间】:2017-11-28 17:40:46
【问题描述】:

我有类似以下的数据:

set.seed(1)
dt <- data.table(ID=1:10, Status=c(rep("OUT",2),rep("IN",2),"ON",rep("OUT",2),rep("IN",2),"ON"), 
                 t1=round(rnorm(10),1), t2=round(rnorm(10),1), t3=round(rnorm(10),1), 
                 t4=round(rnorm(10),1), t5=round(rnorm(10),1), t6=round(rnorm(10),1),
                 t7=round(rnorm(10),1),t8=round(rnorm(10),1))

    ID Status   t1   t2   t3   t4   t5   t6   t7   t8
 1:  1    OUT -0.6  1.5  0.9  1.4 -0.2  0.4  2.4  0.5
 2:  2    OUT  0.2  0.4  0.8 -0.1 -0.3 -0.6  0.0 -0.7
 3:  3     IN -0.8 -0.6  0.1  0.4  0.7  0.3  0.7  0.6
 4:  4     IN  1.6 -2.2 -2.0 -0.1  0.6 -1.1  0.0 -0.9
 5:  5     ON  0.3  1.1  0.6 -1.4 -0.7  1.4 -0.7 -1.3
 6:  6    OUT -0.8  0.0 -0.1 -0.4 -0.7  2.0  0.2  0.3
 7:  7    OUT  0.5  0.0 -0.2 -0.4  0.4 -0.4 -1.8 -0.4
 8:  8     IN  0.7  0.9 -1.5 -0.1  0.8 -1.0  1.5  0.0
 9:  9     IN  0.6  0.8 -0.5  1.1 -0.1  0.6  0.2  0.1
10: 10     ON -0.3  0.6  0.4  0.8  0.9 -0.1  2.2 -0.6

我需要将约束应用于dt,类似于以下内容(使用 fread 从 csv 读取):

dt_constraints <- data.table(columns=c("t1","t3","t7","t8"), operator=c(rep(">=",2),rep("<=",2)), 
                         values=c(-.6,-.5,2.4,.5))

    columns operator    values
1   t1       >=         -0.6
2   t3       >=         -0.5
3   t7       <=          2.4
4   t8       <=          0.5

我可以通过在i 语句中输入各种约束来轻松子集dt

dt_sub <- dt[t1>=-.6 & t3 >=-.5 & t7<=2.4 & t8<=.5,] 

    ID  Status  t1  t2  t3   t4  t5   t6    t7   t8
1   1   OUT   -0.6  1.5 0.9  1.4 -0.2  0.4  2.4  0.5
2   2   OUT    0.2  0.4 0.8 -0.1 -0.3 -0.6  0   -0.7
3   5   ON     0.3  1.1 0.6 -1.4 -0.7  1.4 -0.7 -1.3
4   7   OUT    0.5  0  -0.2 -0.4  0.4 -0.4 -1.8 -0.4
5   9   IN     0.6  0.8-0.5  1.1 -0.1  0.6  0.2  0.1
6   10  ON    -0.3  0.6 0.4  0.8  0.9 -0.1  2.2 -0.6

但是,由于约束不断变化(每次都会读取一个新的约束 csv),我正在寻找一种有效的方法来以编程方式将约束直接从 dt_constraints 应用到子集 dt。实际数据非常大,约束的数量也很大,因此效率是关键。

非常感谢。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    还有一种替代方法,它使用 non-equi 连接 进行子集化:

    thresholds <- dt_constraints[, values]
    cond <- dt_constraints[, paste0(columns, operator, "V", .I)]
    dt[dt[as.list(thresholds), on = cond, which = TRUE]]
    
       ID Status   t1  t2   t3   t4   t5   t6   t7   t8
    1:  1    OUT -0.6 1.5  0.9  1.4 -0.2  0.4  2.4  0.5
    2:  2    OUT  0.2 0.4  0.8 -0.1 -0.3 -0.6  0.0 -0.7
    3:  5     ON  0.3 1.1  0.6 -1.4 -0.7  1.4 -0.7 -1.3
    4:  7    OUT  0.5 0.0 -0.2 -0.4  0.4 -0.4 -1.8 -0.4
    5:  9     IN  0.6 0.8 -0.5  1.1 -0.1  0.6  0.2  0.1
    6: 10     ON -0.3 0.6  0.4  0.8  0.9 -0.1  2.2 -0.6
    

    【讨论】:

      【解决方案2】:

      我们可以将paste作为单个字符串,然后执行eval

      dt[eval(parse(text=do.call(paste, c(dt_constraints, collapse= ' & '))))]
      #   ID Status   t1  t2   t3   t4   t5   t6   t7   t8
      #1:  1    OUT -0.6 1.5  0.9  1.4 -0.2  0.4  2.4  0.5
      #2:  2    OUT  0.2 0.4  0.8 -0.1 -0.3 -0.6  0.0 -0.7
      #3:  5     ON  0.3 1.1  0.6 -1.4 -0.7  1.4 -0.7 -1.3
      #4:  7    OUT  0.5 0.0 -0.2 -0.4  0.4 -0.4 -1.8 -0.4
      #5:  9     IN  0.6 0.8 -0.5  1.1 -0.1  0.6  0.2  0.1
      #6: 10     ON -0.3 0.6  0.4  0.8  0.9 -0.1  2.2 -0.6
      

      如果我们使用tidyverse,那么

      library(dplyr)
      dt %>% 
         filter(!!rlang::parse_expr(do.call(paste, c(dt_constraints, collapse= ' & '))))
      #  ID Status   t1  t2   t3   t4   t5   t6   t7   t8
      #1  1    OUT -0.6 1.5  0.9  1.4 -0.2  0.4  2.4  0.5
      #2  2    OUT  0.2 0.4  0.8 -0.1 -0.3 -0.6  0.0 -0.7
      #3  5     ON  0.3 1.1  0.6 -1.4 -0.7  1.4 -0.7 -1.3
      #4  7    OUT  0.5 0.0 -0.2 -0.4  0.4 -0.4 -1.8 -0.4
      #5  9     IN  0.6 0.8 -0.5  1.1 -0.1  0.6  0.2  0.1
      #6 10     ON -0.3 0.6  0.4  0.8  0.9 -0.1  2.2 -0.6
      

      【讨论】:

      • data.table 解决方案完美运行。我知道最好使用列名,但如果列号列在约束表中而不是列名中,您将如何执行相同的任务,即 dt_constraints &lt;- data.table(columns=c(3,5,9,10), operator=c(rep("&gt;=",2),rep("&lt;=",2)), values=c(-.6,-.5,2.4,.5)) 。谢谢
      • @FG7 在这种情况下dt_constraints[, columns := names(dt)[columns]] 然后像上面那样做paste
      • 非常感谢您的帮助。我需要一点额外的信息:通过每个约束和未通过每个约束的观察数。理想情况下,我可以得到一个类似于dt_constraints 表的输出表,但有两个额外的列,一个是通过的观察数,一个是失败的观察数。有什么想法吗?
      • @FG7 抱歉,我没有收到您的评论。您能否将其作为一个新问题发布?
      • 谢谢@akrun。根据要求,我发布了新问题here。感谢您的所有帮助。
      猜你喜欢
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2014-01-08
      • 2014-04-11
      • 1970-01-01
      • 1970-01-01
      • 2013-09-14
      • 1970-01-01
      相关资源
      最近更新 更多