R данные.имена столбцов таблицы, не работающие в функции
Я пытаюсь использовать данные.таблицу внутри функции, и я пытаюсь понять, почему мой код не работает. У меня есть данные.таблица ниже:
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_name "с разными значениями" my_id", которые для 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_name "для данной пары значений" my_id", которая работает так, как ожидалось.
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
теперь я хочу выполнить эту функцию для всех пар идентификаторов, которые я пытаюсь сделать, найдя все пары идентификаторов, а затем используя 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? Я думаю, что это как-то связано с областью данных.имена таблиц, но я не уверен.
альтернативно, есть ли другой / более эффективный способ выполнить эту задачу? У меня большие данные.таблица с третьим идентификатором "sample", и мне нужно получить все эти пары для каждого образца (например, работая на DT[sample==" sample_id",]). Я новичок в данных.пакет таблицы, и я не могу использовать его самым эффективным способом.
3 ответов
почему эта функция терпит неудачу только при использовании внутри mapply? Я думаю это как-то связано с объемом данных.имена таблиц, но я не уверенный.
почему функция не имеет ничего общего с областью действия в этом случае. mapply
векторизирует функцию, принимает каждый элемент каждого параметра и переходит к функции. Итак, в вашем случае data.table
элементы ее столбцов, так mapply
передает столбец my_name
вместо полное data.table
.
если вы хотите пройти полное data.table
to mapply
, вы должны использовать . Тогда ваша функция будет работать:
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
перечислить все возможные пары
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)]
CJ
как expand.grid
за исключением того, что он создает данных.таблицу со всеми столбцами в качестве ключа. Данные.таблица X
должен быть настроен для соединения X[J(Y)]
или нет-присоединитесь X[!J(Y)]
(как последняя строка) для работы. The J
является необязательным, но делает более очевидным, что мы делаем присоединяться.
упрощений. @CathG указал, что есть более чистый способ построения obs_pairs
если у вас всегда есть два отсортированных " имени "для каждого" id " (как в примере данных): используйте 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()
принимает первый элемент каждого входного аргумента и передает его вашей функции. В этом случае вы предоставили данные.таблица, который также список. Итак, вместо того, чтобы передавать все данные.таблица, она передает каждый элемент списка (столбцов).
таким образом, вы можете обойти это путем делать:
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