![](/img/trans.png)
[英]How to use R data.table column names with cube(..., j = ,...) within a function?
[英]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)]
CJ
與expand.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.