r语言 - data.table:在自定义函数中选择条件数据集的一部分



我想编写一个函数,该函数将使用data.table包选择数据集的一部分。函数的声明参数为:

  • 输入数据集 (dset),
  • 变量,数据集将在其上子集 (seg.var),
  • 上面声明的变量的值 (value)。

我能够在基础 R 中编写工作函数:

# Function without data.table
data.select <- function(dset, seg.var, value){
dset.out <- dset[dset[[seg.var]] == value,]
return(dset.out)
}
data.select(iris, "Species", "setosa")

但是,我无法使用data.table包重写它:下面的功能不起作用。

# Function with data.table
data.select.dt <- function(dset, seg.var, value){
dset <- as.data.table(dset)
dset.out <- dset[seg.var == value,]
return(dset.out)
}
data.select.dt(iris, Species, "setosa")

eval(expr, envir, enclos) 中的错误:找不到对象"物种">

data.select.dt(iris, "Species", "setosa")

空数据表(0 行)的 5 列:

萼片长度,萼片宽度,花瓣长度,花瓣宽度,物种

输入数据集采用data.frame格式。重写给定函数的目标是性能改进。任何帮助将不胜感激。

评论有点太长了,所以单独回答:

首先,我提到的get()函数作为对@R.S.回答的评论:

data.select.dt.V1 <- function(dset, seg.var, value){
if(!data.table::is.data.table(dset)) dset <- data.table::as.data.table(dset)  # To convert only if needed
dset[get(seg.var) == value,]
}
data.select.dt.V1(iris, 'Species', 'setosa')

然后是更data.table函数,您可以在其中将第二个参数作为表达式传递(好吧,以data.table的方式),而不是字符串:

data.select.dt.V2 <- function(dset, seg.var, value){
if(!data.table::is.data.table(dset)) dset <- data.table::as.data.table(dset)  # To convert only if needed
sv <- substitute(seg.var)
dset[eval(sv) == value,]
}
data.select.dt.V2(iris, Species, 'setosa')

编辑:功能简化和转换测试(感谢@David Arenburg评论)。

第 2 次编辑:在 515 MBdata.tabledata.frame上对上述两个函数进行了基准测试@David Arenburg 的一个函数(分别带有和不带is.data.table检查、V3V4):

data.select.dt.V3 <- function(dset, seg.var, value) data.table::as.data.table(dset)[.(value), on = seg.var]
data.select.dt.V4 <- function(dset, seg.var, value) {
if(!data.table::is.data.table(dset)) dset <- data.table::as.data.table(dset)  # To convert only if needed
dset[.(value), on = seg.var]
}
expr      min       lq     mean   median       uq      max neval cld
1 res <- data.select.dt.V1(iris_df, "Species", "setosa") 3.804995 4.585763 4.150130 4.688093 5.320362 3.166503    10   c
2 res <- data.select.dt.V2(iris_df, Species, "setosa")   3.713275 3.827180 3.865347 4.544968 4.753045 3.218075    10   c
3 res <- data.select.dt.V3(iris_df, "Species", "setosa") 1.927947 1.942868 2.167127 2.328364 2.595420 2.159664    10  b 
4 res <- data.select.dt.V4(iris_df, "Species", "setosa") 1.987710 2.004497 2.011502 2.280117 2.856847 1.594249    10  b 
5 res <- data.select.dt.V1(iris_dt, "Species", "setosa") 2.771223 2.792428 2.501362 2.805796 3.056144 1.883520    10  b 
6 res <- data.select.dt.V2(iris_dt, Species, "setosa")   2.830161 2.970071 2.593192 3.123812 3.170884 1.752576    10  b 
7 res <- data.select.dt.V3(iris_dt, "Species", "setosa") 1.963530 2.116116 2.059718 2.203265 2.740949 1.768817    10  b 
8 res <- data.select.dt.V4(iris_dt, "Species", "setosa") 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10 a  

显然,如果您同时期待data.framedata.table,那么V4是要去的,如果只有df可能的话,最快的功能将是V3

检查你的代码:data.table 版本中的dset.out <- dset[seg.var == value,]应该是dset.out <- dset[dset[[seg.var]] == value,]这是你原来拥有的。

Species缺少引号,应在调用函数时"Species"引号。这就是错误消息指出工作区中没有对象Species的原因。

这行得通。

data.select.dt <- function(dset, seg.var, value){
dset <- as.data.table(dset)
dset.out <- dset[dset[[seg.var]] == value,]
return(dset.out)
}
data.select.dt(iris, "Species", "setosa")

编辑以添加提示,在函数外部调试,以便您看到出现问题的地方。

这里有一些微妙之处,我的建议是将其分解为几个步骤。先直接编写代码,然后转换为函数:

您的原始代码在函数之外工作:

require(data.table)
dset <- as.data.table(iris)
dset.out <- dset[Species == "setosa",]
dset.out
> dset <- as.data.table(iris)
> dset.out <- dset[Species == "setosa",]
> dset.out
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1:          5.1         3.5          1.4         0.2  setosa
2:          4.9         3.0          1.4         0.2  setosa
...

但是,当您将其包装在函数中时会失败...

> require(data.table)
> data.select.dt <- function(dset, seg.var, value){
+   dset <- as.data.table(dset)
+   dset.out <- dset[ seg.var == eval(value) ]
+   return(dset.out)
+ }
> data.select.dt(iris, Species, "setosa")
Show Traceback
Rerun with Debug
Error in eval(expr, envir, enclos) : object 'Species' not found 

好吧,有趣,为什么它在函数调用中失败?您需要正确引用"物种"变量。这需要您在调用中取消引用:

dset[dset[["Species"]] == "setosa",]
> dset[dset[["Species"]] == "setosa",]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1:          5.1         3.5          1.4         0.2  setosa
2:          4.9         3.0          1.4         0.2  setosa
...

铌。我发现真正有趣的是,调试中的 RStudio 允许函数工作,但在非调试模式下触发错误。

现在你可以把它包装在一个函数中:

data.select.dt <- function(dset, seg.var, value){
dset <- as.data.table(dset)
dset.out <- dset[dset[[seg.var]] == value,]
return(dset.out)
}

请注意,物种用引号括起来"Species"...

data.select.dt(iris, "Species", "setosa")
data.select.dt(iris, "Species", "setosa")
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1:          5.1         3.5          1.4         0.2  setosa
2:          4.9         3.0          1.4         0.2  setosa
3:          4.7         3.2          1.3         0.2  setosa

最新更新