R data.table:在自定义函数中根据条件选择数据集的一部分

R data.table:在自定义函数中根据条件选择数据集的一部分,r,function,data.table,subset,R,Function,Data.table,Subset,我想编写一个函数,使用data.table包选择数据集的一部分。函数的声明参数为: 输入数据集数据集, 变量,数据集将在其上子集seg.var, 上面声明的变量值的值。 我能够在base R中编写工作函数: # Function without data.table data.select <- function(dset, seg.var, value){ dset.out <- dset[dset[[seg.var]] == value,] return(dset.ou

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

输入数据集数据集, 变量,数据集将在其上子集seg.var, 上面声明的变量值的值。 我能够在base 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")
evalexpr、envir、enclose中出错:未找到对象“物种”

空数据。表0 5列:萼片。长度,萼片。宽度,花瓣。长度,花瓣。宽度,种类


输入数据集为data.frame格式。重写上述给定函数的目的是提高性能。任何帮助都将不胜感激。

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

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

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
...
data.select.dt <- function(dset, seg.var, value){
  dset <- as.data.table(dset)
  dset.out <- dset[dset[[seg.var]] == value,]
  return(dset.out)
}
注意。我发现真正有趣的是,调试中的RStudio允许函数工作,但在非调试模式下会触发错误

现在,您可以将其包装到函数中:

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
...
data.select.dt <- function(dset, seg.var, value){
  dset <- as.data.table(dset)
  dset.out <- dset[dset[[seg.var]] == value,]
  return(dset.out)
}

检查您的代码:dset.out对于注释来说有点太长,因此需要单独回答:

首先,我提到的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')
编辑:由于@David Arenburg注释,功能简化和转换测试

第二次编辑:在515 MB data.table和data.frame上分别使用@David Arenburg的带和不带is.data.table检查、V3和V4功能对上述两个功能进行了基准测试:


显然,如果您同时需要data.frame和data.table,那么V4就是最好的选择,如果只需要df,那么最快的函数就是V3。

为什么要在函数中转换为data.table?您正在创建整个数据集的副本。最好使用setDT将data.table转换为一个就地的data.table。无论如何,我都要做一个简单的二进制连接。类似data.select.dt的内容我希望确保代码的其余部分能够正常工作。因为我使用的数据集比iris大,所以我想比较基本子集设置和data.table中实现的子集设置的性能,而不必重写整个代码。@kaksat,请参见if!data.table::is.data.tabledset在我的回答中,如果dset是data.table,应该可以节省一些时间和RAM。如果您关心性能,最好测试它,而不是通过自定义函数进行混淆。@m-dz,感谢您的优化。尽管如此,我确信我的数据集将是一个data.frame@弗兰克,说到底,我可能不得不做这个调整,所以用转换测试性能似乎是合理的。在我之前给出了正确的答案,或者您可以使用dset[getseg.var==value,]来节省一些时间和内存,您不会返回dset[[seg.var]]。
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")

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
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")
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.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')
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