R data.table列名在函数

时间:2015-06-25 13:34:24

标签: r data.table mapply

我正在尝试在函数中使用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“sample”的大型data.table,我需要为每个样本获取所有这些对(例如在DT上运行[sample ==“sample_id”,])。我是data.table包的新手,我可能没有以最有效的方式使用它。

3 个答案:

答案 0 :(得分:4)

枚举所有可能的对

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", with=FALSE]
)

取得差异

all_pairs[!J(obs_pairs)]

CJexpand.grid类似,不同之处在于它创建了一个以其所有列为关键字的data.table。必须为加入X或非加入X[J(Y)](如最后一行)键入data.table X[!J(Y)]才能生效。 J是可选的,但更明显的是我们正在进行加入。

简化。 @CathG指出,如果你总是有两个排序的&#34;名称,那么有一种更简洁的构建obs_pairs的方法。为每个&#34; id&#34; (如示例数据中所示):使用as.list(un)代替CJ(un,un)[V1 < V2]

答案 1 :(得分:3)

  

为什么此功能仅在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

答案 2 :(得分:3)

函数// define reference variable `interval` , set to `0` var interval = 0; var wait = function(data) { // set `interval` as reference to `setInterval` interval = setInterval(function() { console.log(data) }, 1000) } $.post("my.php", {send:"123"}, function(resp) { // pass `resp` to `wait`, call `setInterval` , wait(resp); }); 在这些场景中非常有用。

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) 获取每个输入参数的第一个元素并将其传递给您的函数。在这种情况下,您提供了 data.table ,它也是 list 。因此,它不是传递整个data.table,而是传递列表的每个元素(列)。

所以,你可以通过这样做来解决这个问题:

mapply()

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)) 绑定结果。

HTH