繁体   English   中英

R data.table 列名在函数中不起作用

[英]R data.table column names not working within a function

我正在尝试在函数中使用 data.table,并且我试图了解为什么我的代码失败。 我有一个 data.table 如下:

DT <- data.table(my_name=c("A","B","C","D","E","F"),my_id=c(2,2,3,3,4,4))
> DT
   my_name my_id
1:       A     2
2:       B     2
3:       C     3
4:       D     3
5:       E     4
6:       F     4

我正在尝试使用不同的“my_id”值创建所有对“my_name”,对于 DT,这将是:

Var1 Var2    
A    C
A    D
A    E
A    F
B    C
B    D
B    E
B    F
C    E
C    F
D    E
D    F

我有一个函数可以为给定的“my_id”值对返回所有“my_name”对,它按预期工作。

get_pairs <- function(id1,id2,tdt) {
    return(expand.grid(tdt[my_id==id1,my_name],tdt[my_id==id2,my_name]))
}
> get_pairs(2,3,DT)
Var1 Var2
1    A    C
2    B    C
3    A    D
4    B    D

现在,我想为所有 id 对执行此函数,我尝试通过查找所有 id 对,然后将 mapply 与 get_pairs 函数一起使用来实现。

> combn(unique(DT$my_id),2)
     [,1] [,2] [,3]
[1,]    2    2    3
[2,]    3    4    4
tid1 <- combn(unique(DT$my_id),2)[1,]
tid2 <- combn(unique(DT$my_id),2)[2,]
mapply(get_pairs, tid1, tid2, DT)
Error in expand.grid(tdt[my_id == id1, my_name], tdt[my_id == id2, my_name]) : 
  object 'my_id' not found

同样,如果我尝试在没有 mapply 的情况下做同样的事情,它会起作用。

get_pairs3(tid1[1],tid2[1],DT)
Var1 Var2
1    A    C
2    B    C
3    A    D
4    B    D

为什么此函数仅在 mapply 中使用时才会失败? 我认为这与 data.table 名称的范围有关,但我不确定。

或者,是否有不同/更有效的方法来完成此任务? 我有一个带有第三个 id“样本”的大 data.table,我需要为每个样本获取所有这些对(例如在 DT[sample=="sample_id",] 上操作)。 我是 data.table 包的新手,我可能没有以最有效的方式使用它。

枚举所有可能的对

u_name    <- unique(DT$my_name)
all_pairs <- CJ(u_name,u_name)[V1 < V2]

枚举观察到的对

obs_pairs <- unique(
  DT[,{un <- unique(my_name); CJ(un,un)[V1 < V2]}, by=my_id][, !"my_id"]
)

拿差价

all_pairs[!J(obs_pairs)]

CJexpand.grid类似,除了它创建一个 data.table 并以其所有列作为键。 必须对 data.table X进行键控,联接X X[J(Y)]或非联接X X[!J(Y)] (如最后一行)才能工作。 J是可选的,但更明显地表明我们正在进行连接。


简化。 @CathG 指出,如果每个“id”总是有两个排序的“名称”(如示例数据),则有一种更obs_pairs的构建obs_pairs方法:使用as.list(un)代替CJ(un,un)[V1 < V2]

函数debugonce()在这些场景中非常有用。

debugonce(mapply)
mapply(get_pairs, tid1, tid2, DT)

# Hit enter twice
# from within BROWSER
debugonce(FUN)
# Hit enter twice
# you'll be inside your function, and then type DT
DT
# [1] "A" "B" "C" "D" "E" "F"
Q # (to quit debugging mode)

这是错误的。 基本上, mapply()获取每个输入参数的第一个元素并将其传递给您的函数。 在本例中,您提供了一个data.table ,它也是list 因此,它不是传递整个 data.table,而是传递列表(列)的每个元素。

因此,您可以通过执行以下操作来解决此问题:

mapply(get_pairs, tid1, tid2, list(DT))

但是mapply()默认简化了结果,因此你会得到一个matrix 您必须使用SIMPLIFY = FALSE

mapply(get_pairs, tid1, tid2, list(DT), SIMPLIFY = FALSE)

或者简单地使用Map

Map(get_pairs, tid1, tid2, list(DT))

使用rbindlist()绑定结果。

HTH

为什么此函数仅在 mapply 中使用时才会失败? 我认为这与 data.table 名称的范围有关,但我不确定。

在这种情况下,函数失败的原因与范围界定无关。 mapply对函数进行矢量化,它获取每个参数的每个元素并传递给函数。 所以,在你的情况下, data.table元素是它的列,所以mapply传递列my_name而不是完整的data.table

如果要将完整的data.table传递给mapply ,则应使用MoreArgs参数。 然后您的功能将起作用:

res <- mapply(get_pairs, tid1, tid2, MoreArgs = list(tdt=DT), SIMPLIFY = FALSE)
do.call("rbind", res)
  Var1 Var2
1     A    C
2     B    C
3     A    D
4     B    D
5     A    E
6     B    E
7     A    F
8     B    F
9     C    E
10    D    E
11    C    F
12    D    F

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM