2017-02-28 53 views
-1

我想编写一个函数,使用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包重写:以下的功能无法正常工作。 5个COLS的对象 '物种' 未找到

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

空data.table(0行)::

# 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)萼片.Length,Sepal.Width,Petal.Length,Petal.Width,Species

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

+3

为什么你要在函数内转换为data.table?您正在创建整个数据集的副本。通过使用'setDT'将其转换为一个''data.table''就更好了。无论哪种方式,我会做一个简单的二进制连接。像'data.select.dt < - 函数(dset,seg.var,value)as.data.table(dset)[。(value),on = seg.var]',然后将其作为data.select运行.dt(iris,“Species”,“setosa”)' –

+0

我想确保其余的代码能够正常工作。由于我使用的数据集大于'iris',因此我想比较“base”子集的性能和'data.table'中实现的性能,而不必强制重写整个代码。 – kaksat

+0

@kaksat,在我的答案中查看'if(!data.table :: is.data.table(dset))',如果'dset'是'data.table',应该节省一些时间和RAM。 –

回答

2

这是一个评论有点太长了,所以一个单独的答案:

首先,我提到为@ R,S注释的get()功能。回答:

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评论)。

第二编辑:基准测试上述两种功能与@大卫Arenburg对515 MB data.tabledata.frame一个(有和没有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 

显然V4是一个至如果你期望data.framedata.table,如果只有df是可能的,最快的功能将是V3

1

这里有一些微妙之处,我的建议是把它分解成几个步骤。直先写代码,然后转换成一个功能:

你原来的代码工作的功能之外:

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 

好的,有趣的是,为什么它在函数调用中失败?您需要正确引用“Species”变量。这需要你在通话中解除引用:

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 
... 

nb。我发现真正有趣的是调试中的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 
+0

R.S.在我之前给出了正确的答案 – Technophobe01

2

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

Species缺少引号,应该是"Species"当您调用该函数时。这就是错误信息在工作区中没有显示对象Species的原因。

This Works。

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

编辑添加一个提示,除功能外调试,所以你看到的东西在打破。

+1

或者你可以使用'dset [get(seg.var)== value]'来保存一些时间和内存(你没有返回'dset [[seg.var]]')。 –