2017-08-31 38 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)