#r #data.table
#r #data.table
Вопрос:
У меня есть data.table, для которого я хотел бы выполнить некоторую обработку. В качестве начального шага я хотел бы установить новый data.table
для столбцов.
Я создаю цикл для интересующих столбцов и пытаюсь назначить NA
/0, который завершается неудачей или имеет проблемы, как описано ниже.
library(data.table)
input_allele <- data.table(FID= paste0("gid",1:10),IID=paste0("IID",11:20),PAT=c(1:10),MAT=c(rep(0,10)),SEX=c(rep(1,10)),PHENOTYPE =c(rep(1,10)),
SNP1=(c(rep(1,5), rep(0,5))),SNP2=(c(rep(1,6),rep(0,3),NA)),SNP3=(c(rep(NA,6),rep(1,4))),SNP4=(c(rep(NA,6),rep(0,4))),SNP5=(c(rep(1,6),rep(0,4))) )
multiplied_value<-input_allele[,c(1:6)]
for(temp_snp in (colnames(input_allele[,.SD,.SDcols=c(7:11)]))){
temp_snpquote<-quote(temp_snp)
multiplied_value[,(temp_snpquote):=0]
}
Я получаю сообщение об ошибке:
Ошибка в
[.data.table
(multiplied_value, ,:=
((temp_snpquote), 0)) : LHS of := должно быть символом или атомарным вектором (имена столбцов или позиции).
Если я использую eval
, я сталкиваюсь со странным поведением: после завершения цикла мне приходится вводить multiplied_value
дважды, прежде чем data.table будет напечатан на консоли. Это поразительно для меня.
for(temp_snp in (colnames(input_allele[,.SD,.SDcols=c(7:11)]))){
temp_snpquote<-quote(temp_snp)
multiplied_value[,eval(temp_snpquote):=0]
}
Я хотел бы понять: 1) как установить новый столбец как NA или 0. 2) почему при использовании eval
я вводил multiplied_value data.table дважды, когда он печатается.
R version 4.0.0 (2020-04-24), data.table_1.13.4
Дистрибутив Unix debian
Комментарии:
1. Я бы использовал
set
для этого, а не:=
. Что-то вроде:for (i in colnames(input_allele[,.SD,.SDcols=c(7:11)])) set(multiplied_value, j = i, value = 0); multiplied_value[]
.2. Но вы также могли бы сделать:
for(temp_snp in (colnames(input_allele[,.SD,.SDcols=c(7:11)]))) multiplied_value[, (temp_snp):= 0]; multiplied_value[]
.3. Я понимаю. Я должен был использовать
[]
, где я должен ввести имя переменной дважды.for(temp_snp in (colnames(input_allele[,.SD,.SDcols=c(7:11)]))) multiplied_value[, (temp_snp):= 0][]
Я не смог понять ваш первый фрагмент кода из-за переменных (j и i). Как то, что там установлено?4. Если вы посмотрите на страницу справки
?set
(где:=
также показано), ближе к концу вы увидите тайминги для разных способов добавления нескольких столбцов в adata.table
.5. Последнее
[]
— печатать после использования любых изменений на месте.
Ответ №1:
Консолидация некоторых комментариев в ответ здесь…
Из ?set
, вы можете обнаружить, что накладные [.data.table
расходы на повторный вызов могут складываться. В этих случаях вы можете попробовать set
вместо этого.
Кроме того, любые set*
функции должны сопровождаться []
выводом на печать.
При этом вот две альтернативы:
copy1 <- copy2 <- copy3 <- input_allele[,c(1:6)]
new <- colnames(input_allele[,.SD,.SDcols=c(7:11)])
## Using `set` :
for (i in new) {
set(copy1, j = i, value = 0)[]
}
head(copy1)
## FID IID PAT MAT SEX PHENOTYPE SNP1 SNP2 SNP3 SNP4 SNP5
## 1: gid1 IID11 1 0 1 1 0 0 0 0 0
## 2: gid2 IID12 2 0 1 1 0 0 0 0 0
## 3: gid3 IID13 3 0 1 1 0 0 0 0 0
## 4: gid4 IID14 4 0 1 1 0 0 0 0 0
## 5: gid5 IID15 5 0 1 1 0 0 0 0 0
## 6: gid6 IID16 6 0 1 1 0 0 0 0 0
## Using `:=` :
for (i in new) {
copy2[, (i) := 0][]
}
head(copy2)
## FID IID PAT MAT SEX PHENOTYPE SNP1 SNP2 SNP3 SNP4 SNP5
## 1: gid1 IID11 1 0 1 1 0 0 0 0 0
## 2: gid2 IID12 2 0 1 1 0 0 0 0 0
## 3: gid3 IID13 3 0 1 1 0 0 0 0 0
## 4: gid4 IID14 4 0 1 1 0 0 0 0 0
## 5: gid5 IID15 5 0 1 1 0 0 0 0 0
## 6: gid6 IID16 6 0 1 1 0 0 0 0 0
Вы также можете избежать цикла:
copy3[, (new) := as.list(rep(0, length(new)))][]
## FID IID PAT MAT SEX PHENOTYPE SNP1 SNP2 SNP3 SNP4 SNP5
## 1: gid1 IID11 1 0 1 1 0 0 0 0 0
## 2: gid2 IID12 2 0 1 1 0 0 0 0 0
## 3: gid3 IID13 3 0 1 1 0 0 0 0 0
## 4: gid4 IID14 4 0 1 1 0 0 0 0 0
## 5: gid5 IID15 5 0 1 1 0 0 0 0 0
## 6: gid6 IID16 6 0 1 1 0 0 0 0 0
## 7: gid7 IID17 7 0 1 1 0 0 0 0 0
## 8: gid8 IID18 8 0 1 1 0 0 0 0 0
## 9: gid9 IID19 9 0 1 1 0 0 0 0 0
## 10: gid10 IID20 10 0 1 1 0 0 0 0 0
Обратите внимание, что quote
и eval
для них не нужны.
Даже при таком небольшом наборе данных разница в производительности между set
циклом и использованием :=
в цикле измерима:
fun1 <- function() { for (i in new) { set(copy1, j = i, value = 0)[] }; copy1 }
fun2 <- function() { for (i in new) { copy2[, (i) := 0][] } ; copy2 }
fun3 <- function() copy3[, (new) := as.list(rep(0, length(new)))][]
bench::mark(fun1(), fun2(), fun3())
## # A tibble: 3 x 13
## expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc
## <bch:expr> <bch:t> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl>
## 1 fun1() 64.9µs 69.63µs 13932. 0B 4.17 6689 2
## 2 fun2() 993µs 1.07ms 910. 377.6KB 4.23 430 2
## 3 fun3() 241.9µs 255.12µs 3793. 16.4KB 4.30 1763 2
## # … with 5 more variables: total_time <bch:tm>, result <list>, memory <list>,
## # time <list>, gc <list>