2017-02-28 103 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]]')。 –