gpt4 book ai didi

r - 如何使用by将所有列暴露给data.table的子集并将其暴露给该函数?

转载 作者:行者123 更新时间:2023-12-04 10:06:52 28 4
gpt4 key购买 nike

当按组对data.table进行切片时,用于切片数据的变量不在函数执行过程中的子集中。我使用debugonce演示了这一点。

library(data.table)
x <- data.table(a = rep(letters[1:4], each = 3), b = rep(c("a", "b"), each = 6), c = rnorm(12))

myfun <- function(y) paste(y$a, y$b, y$c, collapse = "")

> debugonce(myfun)
> x[, myfun(.SD), by = .(b, a)]
debugging in: myfun(.SD)
debug: paste(y$a, y$b, y$c, collapse = "")
Browse[2]> y
c
1: -1.2662416
2: 0.9818497
3: -0.5395385

我所追求的是拆分应用范式的功能,其中我将根据因素对data.frame进行切片并将该函数应用于所有列,也就是说,还包括已用于切片的变量它(如下所示)。
> debugonce(myfun)

> sapply(split(x, f = list(x$b, x$a)), FUN = myfun)
debugging in: FUN(X[[i]], ...)
debug: paste(y$a, y$b, y$c, collapse = "")
Browse[2]> y
a b c
1: a a -1.2662416
2: a a 0.9818497
3: a a -0.5395385

最佳答案

OP具有将列表作为参数的功能,该功能应包含data.table的所有列,包括by中用于分组的列。
根据help(".SD"):

.SD is a data.table containing the Subset of x's Data for each group, excluding any columns used in by (or keyby).


(强调我的)

.BY is a list containing a length 1 vector for each item in by. This can be useful when by is not known in advance.


因此, .BY.SD相互补充以访问data.table的所有列。
而不是在函数调用中明确重复 by
x[, myfun(c(list(b, a), .SD)), by = .(b, a)]
我们可以用
x[, myfun(c(.BY, .SD)), by = .(b, a)]
   b a                                                                 V1
1: a a a a -1.02091215130492a a -0.295107569536843a a 0.77776326093429
2: a b b a -0.369037832486311b a -0.716211663822323b a -0.264799143319049
3: b c c b -1.39603530693486c b 1.4707902839894c b 0.721925347069227
4: b d d b -1.15220308230505d b -0.736782242593426d b 0.420986999145651

OP已使用 debugonce()来显示传递给 myfun()的参数:
> debugonce(myfun)
> x[, myfun(c(.BY, .SD)), by = .(b, a)]
debugging in: myfun(c(.BY, .SD))
debug at #1: paste(y$a, y$b, y$c, collapse = "")
Browse[2]> y
$b
[1] "a"

$a
[1] "a"

$c
[1] -1.0209122 -0.2951076 0.7777633

另一个例子
使用另一个示例数据集和函数,可能更容易举例说明问题的核心:
x <- data.table(a = rep(letters[3:6], each = 3), b = rep(c("x", "y"), each = 6), c = 1:12)
myfun <- function(y) paste(y$a, y$b, y$c, sep = "/", collapse = "-")

x[, myfun(.SD), by = .(b, a)]
   b a             V1
1: x c //1-//2-//3
2: x d //4-//5-//6
3: y e //7-//8-//9
4: y f //10-//11-//12

因此,列 ba确实会在输出中显示为分组变量,但不会通过 .SD传递给函数。
现在,用 .BY补充 .SD
x[, myfun(c(.BY, .SD)), by = .(b, a)]
   b a                   V1
1: x c c/x/1-c/x/2-c/x/3
2: x d d/x/4-d/x/5-d/x/6
3: y e e/y/7-e/y/8-e/y/9
4: y f f/y/10-f/y/11-f/y/12

data.table的所有列都传递给该函数。
函数调用中的单独参数
Roland has suggested.BY.SD作为单独的参数传递给函数。实际上, .BY是一个列表对象, .SD是一个data.table对象(本质上也是一个允许我们使用 c(.BY, .SD)的列表)。在某些情况下,差异可能很重要。
为了进行验证,我们可以定义一个将 str()打印为副作用的函数。仅针对第一组( .GRP == 1L)调用该函数。
myfun1 <- function(y) str(y)
x[, if (.GRP == 1L) myfun1(.SD), by = .(b, a)]
Classes ‘data.table’ and 'data.frame':    3 obs. of  1 variable:
$ c: int 1 2 3
- attr(*, ".internal.selfref")=<externalptr>
- attr(*, ".data.table.locked")= logi TRUE
Empty data.table (0 rows) of 2 cols: b,a
x[, if (.GRP == 1L) myfun1(.BY), by = .(b, a)]
List of 2
$ b: chr "x"
$ a: chr "c"
Empty data.table (0 rows) of 2 cols: b,a
x[, if (.GRP == 1L) myfun1(c(.BY, .SD)), by = .(b, a)]
List of 3
$ b: chr "x"
$ a: chr "c"
$ c: int [1:3] 1 2 3
Empty data.table (0 rows) of 2 cols: b,a

其他连结
除了 help(".SD")之外,对以下SO问题的评论和答案可能很有用:
  • What does .SD stand for in data.table in R
  • Use of lapply .SD in data.table R
  • 关于r - 如何使用by将所有列暴露给data.table的子集并将其暴露给该函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45295639/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com