簡體   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