问题
Here is the output that I want from data.table
.
library(data.table)
dt_mtcars <- as.data.table(mtcars)
## desired output ----
dt_mtcars[mpg >20
, .(mean_mpg = mean(mpg)
,median_mpg = median(mpg))
, .(cyl, gear)]
cyl gear mean_mpg median_mpg
1: 6 4 21.000 21.00
2: 4 4 26.925 25.85
3: 6 3 21.400 21.40
4: 4 3 21.500 21.50
5: 4 5 28.200 28.20
I want to get the output by passing arguments to a function.
processFUN <- function(dt, where, select, group){
out <- dt[i=eval(parse(text = where))
,j=eval(parse(text = select))
,by=eval(parse(text = group))]
return(out)
}
report <- processFUN(dt_mtcars
,where= "mpg > 20"
,select= ".(mean_mpg = mean(mpg), median_mpg = median(mpg))"
,group= ".(cyl, gear)")
However, I get an error message.
Error in .(cyl, gear) : could not find function "."
回答1:
Or using eval
with substitute
:
library(data.table) #Win R-3.5.1 x64 data.table_1.12.2
dt_mtcars <- as.data.table(mtcars)
processFUN <- function(dt, where, select, group) {
out <- dt[i=eval(substitute(where)),
j=eval(substitute(select)),
by=eval(substitute(group))]
return(out)
}
processFUN(dt_mtcars, mpg>20, .(mean_mpg=mean(mpg), median_mpg=median(mpg)), .(cyl, gear))
Some of the earliest references that I can find are
- Aggregating sub totals and grand totals with data.table
- Using data.table i and j arguments in functions
The old faq 1.6 contains reference to this: http://datatable.r-forge.r-project.org/datatable-faq.pdf
回答2:
Just to give you an alternative, if you can/want to use table.express, you can also use strings in many situations:
library(data.table)
library(table.express)
processFUN <- function(dt, where, select, group) {
dt %>%
start_expr %>%
group_by(!!!group, .parse = TRUE) %>%
where(!!!where, .parse = TRUE) %>%
transmute(!!!select, .parse = TRUE) %>%
end_expr
}
processFUN(as.data.table(mtcars),
"mpg>20",
c("mean_mpg = mean(mpg)", "median_mpg = median(mpg)"),
c("cyl", "gear"))
cyl gear V1 V2
1: 6 4 21.000 21.00
2: 4 4 26.925 25.85
3: 6 3 21.400 21.40
4: 4 3 21.500 21.50
5: 4 5 28.200 28.20
In the next release, start_expr
and end_expr
will be optional.
回答3:
Do you really want to pass conditions as strings? If so, one way would be to construct the query together using paste
and then use eval(parse...
to evaluate it
library(data.table)
processFUN <- function(dt, where, select, group){
eval(parse(text = paste0(as.character(substitute(dt)), "[", where, ",",
select, ",by = ", group, "]")))
}
processFUN(dt_mtcars
,where= "mpg > 20"
,select= ".(mean_mpg = mean(mpg), median_mpg = median(mpg))"
,group= ".(cyl, gear)")
# cyl gear mean_mpg median_mpg
#1: 6 4 21.000 21.00
#2: 4 4 26.925 25.85
#3: 6 3 21.400 21.40
#4: 4 3 21.500 21.50
#5: 4 5 28.200 28.20
来源:https://stackoverflow.com/questions/57253159/passing-multiple-arguments-to-data-table-inside-a-function