使用不同的过滤器参数和向量化的 fifelse() 在函数内部过滤 data.table
Filter data.table inside function with varying filter arguments and vectorised fifelse()
任务: 我在用户定义函数中有一个大数字 data.table
(列 1:3 是子集化所需的字符),用于对数据。
在函数内进行下游分析之前,我想使用函数的参数传递值以过滤 data.table
,或者如果没有为给定的列过滤器提供值,则使用所有行。
然而,困难出现了,因为并不是所有的列过滤器都会一直被使用。
目前,我的方法是使用单独的 if
else
语句块进行过滤以获得每列的 ID 列表,然后我 intersect
在使用之前这是 data.table
的子集。该示例包括状态 3 列,但实际数据中有更多列,这使得这种方法笨拙且效率低下(尽管它有效)。
查询: 如果不知道将使用哪些过滤列,是否有直接过滤 data.table
的方法?或者,有没有办法用 ifelse()
或 fifelse()
来矢量化过程?
我什至会寻求帮助将其嵌入 for
循环中,但要使其正常工作,我需要动态创建变量名来存储每个 ID 列表。
我想保留使用 data.table
和 base
函数的解决方案。此外,函数的参数名称可以更改为与 data.table
的列名称相同,如果这样可以使编码和可读性更容易。
感谢您提供的任何帮助。
数据:
# 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]
}
函数可以简化为
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))
任务: 我在用户定义函数中有一个大数字 data.table
(列 1:3 是子集化所需的字符),用于对数据。
在函数内进行下游分析之前,我想使用函数的参数传递值以过滤 data.table
,或者如果没有为给定的列过滤器提供值,则使用所有行。
然而,困难出现了,因为并不是所有的列过滤器都会一直被使用。
目前,我的方法是使用单独的 if
else
语句块进行过滤以获得每列的 ID 列表,然后我 intersect
在使用之前这是 data.table
的子集。该示例包括状态 3 列,但实际数据中有更多列,这使得这种方法笨拙且效率低下(尽管它有效)。
查询: 如果不知道将使用哪些过滤列,是否有直接过滤 data.table
的方法?或者,有没有办法用 ifelse()
或 fifelse()
来矢量化过程?
我什至会寻求帮助将其嵌入 for
循环中,但要使其正常工作,我需要动态创建变量名来存储每个 ID 列表。
我想保留使用 data.table
和 base
函数的解决方案。此外,函数的参数名称可以更改为与 data.table
的列名称相同,如果这样可以使编码和可读性更容易。
感谢您提供的任何帮助。
数据:
# 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]
}
函数可以简化为
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))