首页 > 解决方案 > 使用不同的过滤器参数和矢量化 fifelse() 在函数内过滤 data.table

问题描述

任务:data.table在用户定义的函数中有一个大数字(列 1:3 是子集所需的字符)来对数据执行分析。
在函数内进行下游分析之前,我想使用函数的参数传递值以过滤data.table,或者如果没有为给定的列过滤器提供值,则使用所有行。

然而,困难出现了,因为并非所有的列过滤器都会一直使用。

目前,我的方法是使用单独的if else语句块进行过滤,以获取每列的 ID 列表,然后intersect在使用它对data.table. 该示例包括状态 3 列,但实际数据中有更多列,这使得这种方法笨拙且效率低下(尽管它有效)。

查询:是否有data.table直接过滤的方法,因为不知道将使用哪些过滤列?ifelse()或者,有没有办法用or来矢量化这个过程fifelse()
我什至会帮助将它嵌入到一个for循环中,但为了让它工作,我需要动态创建变量名来存储每个 ID 列表。

我想保留使用data.tablebase功能的解决方案。此外,函数的参数名称可以更改为与data.tableif 的列名称相同,这使得编码和可读性更容易。

我感谢提供的任何帮助。

数据:

# Install data.table package if not installed and load
if (!require("data.table")) {
  install.packages("data.table")
  library(data.table)
}

# Data (example)
head(DT, n=2)

#>     ID     info1  info2  name1  name2  name3  name4
#>     <char> <char> <char> <dbl>  <dbl>  <dbl>  <dbl>
#> 1:  A100   StuffA StuffX 0.1460 NA     -0.019 0.2102
#> 2:  A101   StuffA StuffY 0.0987 -1.307 -0.174 NA

当前方法:

# Function (example)
myfunc <- function(ID_filter = "", info1_filter = "", info2_filter = "") {

  # Get IDs to use as filter
  if (ID_filter != "") {
    ID_list <- DT[ID %in% ID_filter][["ID"]]
  } else {
    ID_list <- DT[["ID"]]
  }
  
  if (info1_filter != "") {
    info1_list <- DT[info1 %in% info1_filter][["info1"]]
  } else {
    info1_list <- DT[["info1"]]
  }

  # Get overall filter list
  filters <- Reduce(intersect, list(ID, info1, info2))

  # Subset data.table
  DT <- DT[ID %in% filters]  

}

标签: rif-statementdata.tablevectorization

解决方案


该功能可以简化为

myfunc <- function(DT, ID_filter = "", info1_filter = "", info2_filter = "") {

 lst1 <- Filter(function(x) all(x != ""), 
     dplyr::lst(ID_filter, info1_filter, info2_filter))
 if(length(lst1) > 0 ) {
      pat <- paste(sub("_filter", "", names(lst1)), collapse="|")     
      i1 <- DT[, Reduce(`&`, Map(`%in%`, .SD, lst1)), .SDcols = patterns(pat)]
      DT[i1]
 } else DT
 
 }

-测试

setDT(DT)
myfunc(DT, ID_filter = "A100")
#     ID  info1  info2 name1 name2  name3  name4
#1: A100 StuffA StuffX 0.146    NA -0.019 0.2102
myfunc(DT, ID_filter = "A100", info1 = "StuffA")
#     ID  info1  info2 name1 name2  name3  name4
#1: A100 StuffA StuffX 0.146    NA -0.019 0.2102
myfunc(DT, ID_filter = "A100", info1 = "StuffA", info2 = "StuffX")
#     ID  info1  info2 name1 name2  name3  name4
#1: A100 StuffA StuffX 0.146    NA -0.019 0.2102

myfunc(DT, ID_filter = "A100", info1 = "StuffA", info2 = "StuffY")
#Empty data.table (0 rows and 7 cols): ID,info1,info2,name1,name2,name3...

myfunc(DT) # if all the parameters are "", return the full data
#     ID  info1  info2  name1  name2  name3  name4
#1: A100 StuffA StuffX 0.1460     NA -0.019 0.2102
#2: A101 StuffA StuffY 0.0987 -1.307 -0.174     NA

数据

DT <- structure(list(ID = c("A100", "A101"), info1 = c("StuffA", "StuffA"
), info2 = c("StuffX", "StuffY"), name1 = c(0.146, 0.0987), name2 = c(NA, 
-1.307), name3 = c(-0.019, -0.174), name4 = c(0.2102, NA)), 
 class = "data.frame", row.names = c(NA, 
-2L))

推荐阅读