2017-08-31 73 views
2

我正在學習如何編寫使用常見軟件包(如data.table和dplyr)的R函數。R:在用戶定義函數中使用get和data.table

這個功能我寫的計算觀察的特定類別的百分比內的一些其他組(例如:與10-20mpg汽車的份額,被釋放在2015年那個),併產生一個表。這裏沒有它的功能:

library(data.table) 
library(scales) 


#Create test dataframe and cut off points 
test<-data.frame(x=c(0:10), y=c(rep(1,5),rep(2,6)), z=c("A","A","A","B","B","B","C","C","C","C","C")) 
test <- data.table(test) 


#trial non function version (calculating share of row by category z): works 
tmp<-test[,.(N=.N), keyby=.(y,z)] 
tmp[,total:=sum(N), by=y] 
tmp[,percent:=percent(N/total)] 
dcast(tmp,y ~ z, value.var="percent") 

但爲了使它在一個函數內工作,我必須使用get。一旦得到評估,兩個分類變量必須被稱爲「get」和「get.1」的其餘代碼(見下文)。有沒有辦法避免這種情況?

#Two way table function: data.table 

tw_tab<-function(dt,v1,v2){ 

#set up variables as charaters 
v1<-as.character(substitute(v1)) 
v2<-as.character(substitute(v2)) 
dt<-as.character(substitute(dt)) 

#function 
tmp<-get(dt)[,.(N=.N), keyby=.(get(v1),get(v2))] 
tmp[,total:=sum(N), by=get] 
tmp[,percent:=percent(N/total)] 
dcast(tmp,get ~ get.1, value.var="percent") 

} 

#test function 
tw_tab(test, y, z) 

我嘗試了用「得到(V1)」和「得到(V2)」整個代碼,但這不起作用

我看了其他職位上的用戶與數據功能.table(例如,Get a user-defined function work in data.table)但是他們似乎沒有涉及這個問題/遇到它。

我是新來的這一點,所以希望得到更好的方式來做到這一點的人有任何其他反饋/意見。

+0

據透露,'(N = .N)'和'.N'。將做同樣的事情,因爲這是默認名稱。此外,在這個函數中,我猜沒有什麼是由keyby和by獲得的。 – Frank

回答

2

您不必呼籲dtget(根據我的經驗,get是最經常用來指使用弦一柱),你可以提供特徵向量來bykeyby

tw_tab <- function(dt,v1,v2){ 

    #set up variables as charaters 
    v1<-as.character(substitute(v1)) 
    v2<-as.character(substitute(v2)) 

    #function 
    tmp <- dt[,.(N=.N), keyby = c(v1, v2)] 
    tmp[,total:=sum(N), by= c(v1)] 
    tmp[,percent:=percent(N/total)] 
    dcast(tmp, paste(v1, '~', v2), value.var="percent") 
} 

#test function 
tw_tab(test, y, z) 
# y  A  B  C 
# 1: 1 60.0% 40.0% NA 
# 2: 2 NA 16.7% 83.3% 

這裏也是使用xtabsprop.table一個解決方案:

tw_tab <- function(x, v1, v2){ 
    fm <- bquote(~ .(substitute(v1)) + .(substitute(v2))) 
    res <- prop.table(xtabs(formula = fm, data = x), 1) 
    res <- as.data.frame.matrix(res) 
    res[] <- lapply(res, scales::percent) 
    return(res) 
} 

tw_tab(test, y, z) 
#  A  B  C 
# 1 60% 40.0% 0.0% 
# 2 0% 16.7% 83.3% 
1

我會做...

row_pct = function(DT, fm){ 
    all = all.vars(fm) 
    lhs = all.vars(fm[[2]]) 
    rhs = all.vars(fm[[3]]) 

    DT[, .N, by=all][, 
    p := percent(N/sum(N)), by=lhs][, 
    dcast(.SD, eval(fm), value.var = "p", fill = percent(0))] 
} 

例子:

row_pct(test, y ~ z) 

    y A  B  C 
1: 1 60% 40% 0% 
2: 2 0% 16.7% 83.3% 

row_pct(data.table(mtcars), cyl + gear ~ carb) 

    cyl gear 1  2  3  4 6 8 
1: 4 3 100% 0% 0% 0% 0% 0% 
2: 4 4 50% 50% 0% 0% 0% 0% 
3: 4 5 0% 100% 0% 0% 0% 0% 
4: 6 3 100% 0% 0% 0% 0% 0% 
5: 6 4 0% 0% 0% 100% 0% 0% 
6: 6 5 0% 0% 0% 0% 100% 0% 
7: 8 3 0% 33.3% 25.0% 41.7% 0% 0% 
8: 8 5 0% 0% 0% 50% 0% 50% 

如果你想進入ROW和COL某種原因分開瓦爾:

row_pct2 = function(DT, rowvars, colvar){ 
     fm = substitute(`~`(rowvars, colvar)) 
     row_pct(DT, fm) 
} 

# Examples: 
row_pct2(test, y, z) 
row_pct2(data.table(mtcars), cyl + gear, carb)