在函数中使用data.table i和j参数 [英] Using data.table i and j arguments in functions
问题描述
我想用 data.table
写一些封装函数来减少代码重复。
I am trying to write some wrapper functions to reduce code duplication with data.table
.
使用 mtcars
的示例。首先,设置一些数据:
Here is an example using mtcars
. First, set up some data:
data(mtcars)
mtcars$car <- factor(gsub("(.*?) .*", "\\1", rownames(mtcars)), ordered=TRUE)
mtcars <- data.table(mtcars)
现在,这里是我通常写的,以获得组的计数摘要。在这种情况下,我按 car
分组:
Now, here is what I would usually write to get a summary of counts by group. In this case I am grouping by car
:
mtcars[, list(Total=length(mpg)), by="car"][order(car)]
car Total
AMC 1
Cadillac 1
Camaro 1
...
Toyota 2
Valiant 1
Volvo 1
复杂性在于,由于 i
和 j
的参数在 data.table
,如果要传入变量,必须使用 eval(...)
:
The complication is that, since the arguments i
and j
are evaluated in the frame of the data.table
, one has to use eval(...)
if you want to pass in variables:
这个工程:
group <- "car"
mtcars[, list(Total=length(mpg)), by=eval(group)]
想要通过相同的分组变量对结果排序。我不能得到以下的任何变体,给我正确的结果。注意我总是得到单行结果,而不是有序集。
But now I want to order the results by the same grouping variable. I can't get any variant of the following to give me correct results. Notice how I always get a single row of results, rather than the ordered set.
mtcars[, list(Total=length(mpg)), by=eval(group)][order(group)]
car Total
Mazda 2
我知道原因:这是因为 group
在 parent.frame
data.table
的框架。
I know why: it's because group
is evaluated in the parent.frame
, not the frame of the data.table
.
如何评估 c
How can I evaluate group
in the context of the data.table
?
更多一般情况下,在 data.table
,我该如何使用这里面的函数?我需要以下函数给我所有的结果,而不只是第一行数据:
More generally, how can I use this inside a function? I need the following function to give me all the results, not just the first row of data:
tableOrder <- function(x, group){
x[, list(Total=length(mpg)), by=eval(group)][order(group)]
}
tableOrder(mtcars, "car")
推荐答案
Gavin和Josh是对的。这个答案只是为了增加更多的背景。这个想法是,不仅可以使用 quote()
将可变列名称传递到这样的函数中,而是的列名称。 / p>
Gavin and Josh are right. This answer is only to add more background. The idea is that not only can you pass variable column names into a function like that, but expressions of column names, using quote()
.
group = quote(car)
mtcars[, list(Total=length(mpg)), by=group][order(group)]
group Total
AMC 1
Cadillac 1
...
Toyota 2
Valiant 1
Volvo 1
虽然,开始更难,但可以更灵活。这是想法,反正。内部函数需要 substitute()
,如下所示:
Although, admitedly more difficult to start with, it can be more flexible. That's the idea, anyway. Inside functions you need substitute()
, like this :
tableOrder = function(x,.expr) {
.expr = substitute(.expr)
ans = x[,list(Total=length(mpg)),by=.expr]
setkeyv(ans, head(names(ans),-1)) # see below re feature request #1780
ans
}
tableOrder(mtcars, car)
.expr Total
AMC 1
Cadillac 1
Camaro 1
...
Toyota 2
Valiant 1
Volvo 1
tableOrder(mtcars, substring(car,1,1)) # an expression, not just a column name
.expr Total
[1,] A 1
[2,] C 3
[3,] D 3
...
[8,] P 2
[9,] T 2
[10,] V 2
tableOrder(mtcars, list(cyl,gear%%2)) # by two expressions, so head(,-1) above
cyl gear Total
[1,] 4 0 8
[2,] 4 1 3
[3,] 6 0 4
[4,] 6 1 3
[5,] 8 1 14
在v1.8.0中添加了一个新的参数 keyby
2012)让它更简单:
A new argument keyby
was added in v1.8.0 (July 2012) making it simpler :
tableOrder = function(x,.expr) {
.expr = substitute(.expr)
x[,list(Total=length(mpg)),keyby=.expr]
}
i
, j
和区域的意见和反馈by
变量表达式是最受欢迎的。你可以做的另一件事是有一个表,其中列包含表达式,然后查找放在 i
, j
或由该表中的
。
Comments and feedback in the area of i
,j
and by
variable expressions are most welcome. The other thing you can do is have a table where a column contains expressions and then look up which expression to put in i
, j
or by
from that table.
这篇关于在函数中使用data.table i和j参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!