![](/img/trans.png)
[英]R: Subsetting a data.table with repeated column names with numerical positions
[英]R data.table subsetting by column value
我想知道在data.table
,根据某些列值的出现选择行的最有效或最干净的方法是什么? 例如,在一个7列的数据表中,每个值都是1或0,我希望所有的行都精确地有2个值1和5个值0(1表示“存在”而0表示“不存在”)。
到目前为止,这是我在做的,假设下面的data.table
(更大,这只是其中的一个示例)
name D2A1.var D2B3.var D3A1.var D4A3.var D5B3.var H2A3.var H4A4.var MA_ancestor.var
Chrom_1;10000034;G;A Chrom_1;10000034;G;A 1 1 1 1 1 1 1 1
Chrom_1;10000035;G;A Chrom_1;10000035;G;A 1 1 1 1 1 1 1 1
Chrom_1;10000042;C;A Chrom_1;10000042;C;A 1 1 1 1 1 1 1 1
Chrom_1;10000051;A;G Chrom_1;10000051;A;G 1 1 1 1 1 1 1 1
Chrom_1;10000070;G;A Chrom_1;10000070;G;A 1 1 1 1 1 1 1 1
Chrom_1;10000084;C;T Chrom_1;10000084;C;T 1 1 1 1 1 1 1 1
Chrom_6;9997224;AT;A Chrom_6;9997224;AT;A 0 0 0 0 0 1 0 1
Chrom_6;9998654;GTGTGTGTT;G Chrom_6;9998654;GTGTGTGTT;G 0 0 0 0 0 0 0 1
Chrom_6;9999553;TTTC;T Chrom_6;9999553;TTTC;T 0 0 0 0 0 0 0 1
如果我要所有行中有7 1的行,并且假设D2A1.var和D3A1.var中只有1,则执行以下操作
ALL = DT[DT$MA_ancestor.var == 1 & DT$D2A1.var == 1 &DT$D2B3.var == 1 & DT$D3A1.var == 1 & DT$D4A3.var == 1 &DT$D5B3.var == 1 & DT$H2A3.var == 1 & DT$H4A4.var == 1,]
TWO = DT[DT$MA_ancestor.var == 0 & DT$D2A1.var == 1 &DT$D2B3.var == 0 & DT$D3A1.var == 1 & DT$D4A3.var == 0 &DT$D5B3.var == 0 & DT$H2A3.var == 0 & DT$H4A4.var == 0,]
DFlist=list(TWO, ALL)
DFlong = rbindlist(DFlist, use.names = TRUE, idcol = FALSE)
这将返回预期结果并且足够快。 但是,在具有多个条件的情况下,需要进行大量的键入和大量的data.table
创建。 是否有更快,更清洁和更紧凑的方式来实现这一目标?
我们可以通过指定感兴趣的列来使用.SDcols
。 遍历Data.table的子集( .SD
),创建逻辑vector
list
,并使用&
Reduce
其.SD
为单个逻辑vector
ALL <- DT[, Reduce(`&`, lapply(.SD, `==`, 1), .SDcols = nm1]
TWO <- DT[, Reduce(`&`, lapply(.SD, `==`, 0), .SDcols = nm1]
哪里
nm1 <- names(DT)[-1] #or change the names accordingly
是否有更快,更清洁和更紧凑的方式来实现这一目标?
像您一样进行单独的查询和重新绑定可能是最简单的。
您可以使用replace
和join语法简化每个查询:
# make a list of columns initially set to value 0
vec0 = lapply(DT[, .SD, .SDcols=D2A1.var:MA_ancestor.var], function(x) 0)
# helper function for semi join
subit = function(x, d = DT) d[x, on=names(x), nomatch=0]
rbind(
subit(replace(vec0, names(vec0), 1)),
subit(replace(vec0, c("D2A1.var", "D3A1.var"), 1))
)
(此代码未经测试,因为OP的数据不易复制。)
您可能可以进一步简化...
subitall = function(..., d = DT, v0 = vec0)
rbindlist(lapply(..., function(x) subit( replace(v0, names(v0), 1), d = d )))
subitall( names(vec0), c("D2A1.var", "D3A1.var") )
关于功能subit
的子集/半连接,你可以修改它的基础上的答案,满足您的需求进行有data.table半联接
编辑:哦,对了,按照@chinsoon的回答,您也可以先rbind:
subit(rbindlist(list(
replace(vec0, names(vec0), 1),
replace(vec0, c("D2A1.var", "D3A1.var"), 1)
)))
这意味着只加入一次,这更简单。
使用setkey
另一个选项:
setkeyv(DT, names(DT))
#create desired filtering conditions as lists
cond1 <- setNames(as.list(rep(1, ncol(DT))), names(DT))
cond2 <- list(MA_ancestor.var=0, D2A1.var=1, D2B3.var=0, D3A1.var=1, D4A3.var=0, D5B3.var=0, H2A3.var=0, H4A4.var=0)
#get list of conditions so that one does not have to type it one by one
scond <- grep("^cond", ls(), value=TRUE)
DT[rbindlist(mget(scond, envir=.GlobalEnv), use.names=TRUE)]
如果您担心使用cond
开头的虚假变量,则可以使用list2env
将它们分配给环境,然后将list2env
传递给mget
。
数据:
DT <- fread("D2A1.var D2B3.var D3A1.var D4A3.var D5B3.var H2A3.var H4A4.var MA_ancestor.var
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 0 0 0 0 1 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.