R数据表的删除行操作

3
我有一个data.table:
> dat
     Mutant       F1       F2       F3       F4       F5       F6       F7
  1:  A115D  6.53193  7.19020  8.45634  8.49147  9.28304 16.83618 10.70517
  2:  A115F  0.90377  4.33477  5.71287  6.63125  5.86933  9.41705 14.59203
  3:  A115G  3.26668  4.46146  5.42433  7.80924  8.52429 10.92138 11.27432
  4:  A115H  2.91278  5.09545  6.01828  8.18154  8.11368 11.98551 11.33009
  5:  A115I  9.35627  9.29640  9.78475 10.76222 12.80510 16.13456 16.51090
 ---                                                                      
313:   Y80R -1.19326 -2.05579 -1.16474  1.74387  4.79593  5.59487 11.35956
314:   Y80S -0.77282 -1.51611 -0.07168  3.16070  3.16795  7.73116 11.60527
315:   Y80T -0.16135 -0.05859  2.02493  3.28120  6.10268 11.71562 12.45665
316:   Y80V -0.24050 -0.59869  0.36746  3.07046  3.75905  9.17579 11.83179
317:   Y80W  0.77770 -0.10166  2.27790  6.11470  6.01080  9.47050 13.95344

我希望删除所有F1-F7列中任意一个值大于10的行。

阅读文档,我已经了解到:

> dat[, .SD > 10, .SDcols=2:7]

虽然我不确定我在这里做的事情是否有意义。无论如何,这样做可以得到类似以下的结果:

> dat[, .SD>10, .SDcols=2:7]
        F1    F2    F3    F4    F5    F6   F7
[1,] FALSE FALSE FALSE FALSE FALSE  TRUE TRUE
[2,] FALSE FALSE FALSE FALSE FALSE FALSE TRUE
[3,] FALSE FALSE FALSE FALSE FALSE  TRUE TRUE
[4,] FALSE FALSE FALSE FALSE FALSE  TRUE TRUE
[5,] FALSE FALSE FALSE  TRUE  TRUE  TRUE TRUE
[6,] FALSE FALSE FALSE FALSE  TRUE  TRUE TRUE

现在,我想过滤掉所有包含TRUE的行。


1
如果您正在处理数据并进行此类操作,则可能需要使用矩阵而不是data.table。 - Frank
1
从您上一个观点开始,尝试使用 dat[rowSums(dat[, .SD>10, .SDcols=2:7])==0]。或者,对于更符合惯用法的 data.table,请尝试 dat[!(Reduce("|",dat[,lapply(.SD,function(x) x>10),.SDcols=2:7]))] - nicola
那么在你的样本数据中将不会保留任何行,是一个空的数据表? - Rich Scriven
@RichardScriven 还有更多的值,而且 10 不是实际使用的过滤器值。 - TMOTTM
如果一个人不知道 Reduce,那该怎么做呢? - TMOTTM
3个回答

2

我们可以尝试

i1 <- setDT(dat)[, Reduce(`+`,lapply(.SD, ">", 10)), .SDcols=2:7]
i1
#[1] 1 0 1 1 3 0 0 1 0 0
dat[i1==0]

注意:刚刚注意到在评论中@nicola发布了类似的方法。在编辑之前,我只看到了他最初的评论。


或者使用

dat[-dat[ , .I[max(unlist(.SD))>10] ,by = 1:nrow(dat) , .SDcols= 2:7]$V1]
 #  Mutant       F1       F2       F3      F4      F5      F6       F7
 #1:  A115F  0.90377  4.33477  5.71287 6.63125 5.86933 9.41705 14.59203
 #2:   Y80R -1.19326 -2.05579 -1.16474 1.74387 4.79593 5.59487 11.35956
 #3:   Y80S -0.77282 -1.51611 -0.07168 3.16070 3.16795 7.73116 11.60527
 #4:   Y80V -0.24050 -0.59869  0.36746 3.07046 3.75905 9.17579 11.83179
 #5:   Y80W  0.77770 -0.10166  2.27790 6.11470 6.01080 9.47050 13.95344

2
你可以使用 which 命令。
dat[-which(rowSums(dat[,2:8]>10)>0),]

或者正如TTMOTT指出的那样。
dat[-(rowSums(dat[,2:8]>10)>0),]

略微更快的方式

dat[-which(max(dat[,2:8])>10),]基本上是计算行数,其中存在一个true值

希望我没有犯错,我的玩具示例是:

 lines ="Mutant,F1,F2,F3,F4,F5,F6,F7
A115D,6.53193,7.19020,8.45634,8.49147,9.28304,16.83618,10.70517
A115F,0.90377,4.33477,5.71287,6.63125,5.86933,9.41705,14.59203
A115G,3.26668,4.46146,5.42433,7.80924,8.52429,10.92138,11.27432
A115H,2.91278,5.09545,6.01828,8.18154,8.11368,11.98551,11.33009
A115I,9.35627,9.29640,9.78475,10.76222,12.80510,16.13456,16.51090"

con <- textConnection(lines)
dat <- read.csv(con)
dat

dat[rowSums(dat[,2:7]>10)>0,]

阅读了data.table的vignette之后,我仍然不明白.SD > 10是如何工作的。它是否会检查所有列(除了.SDcols)的每个元素是否大于10? - TMOTTM
是的,这就是想法。它将.SD>10应用于您列出为SDcols的每个列。这可以加快操作。我猜你可以像我指定的那样做 dat[which(rowSums(dat[, 2:7])>0),] - CAFEBABE
你原来的陈述存在一些问题,建议使用我上一条评论中提供的非常简单的陈述。 - CAFEBABE
事实上,“which”可能并不需要,是吗?但仍然是一个好的解决方案。 - TMOTTM

0

简单点怎么样?

dat[-which(dat$F1>10 | dat$F2>10 | dat$F3>10 | dat$F4>10 | dat$F5>10 | dat$F6>10 | dat$F7>10)]

4个提议解决方案的基准测试

dat <- data.frame("xxxxx", F1=runif(10000, 1,20),
                  F2=runif(10000, 1,20),
                  F3=runif(10000, 1,20),
                  F4=runif(10000, 1,20),
                  F5=runif(10000, 1,20),
                  F6=runif(10000, 1,20),
                  F7=runif(10000, 1,20))

benchmark(replications = 100, dat[-which(dat$F1>10 | dat$F2>10 | dat$F3>10 | 
                                      dat$F4>10 | dat$F5>10 | dat$F6> 10 | 
                                      dat$F7>10),],columns = c('elapsed'))
  elapsed
1    0.26

  benchmark(replications = 100, dat[(rowSums(dat[,2:8]>10)==0),],columns = c('elapsed'))

  elapsed
1    0.17

dat <- as.data.table(dat)

benchmark(replications = 100, dat[!(Reduce("|",dat[,lapply(.SD,function(x) x>10),.SDcols=2:8]))],
          columns = c('elapsed'))

  elapsed
1    0.32

benchmark(replications = 100, dat[-dat[ , .I[max(unlist(.SD))>10] ,by = 1:nrow(dat) , .SDcols= 2:8]$V1],
          columns = c('elapsed'))
  elapsed
1    6.05

在我的编辑中,基于10000个随机数的两种解决方案进行了一些基准测试。 - andrnev
你在你的版本和我的版本中都犯了一个错误。你的版本无法运行,在我的情况下会产生非常大的差异。我猜你是用不同的代码库进行基准测试的。 - CAFEBABE
应该使用dat[(rowSums(dat[,2:8]>10)>0),]而不是dat[(rowSums(dat[,2:7]>10)>0),],对吧? - andrnev
抱歉。OP要求删除列大于10的行。这次我已经更新了所有4个解决方案的基准测试。 - andrnev
正确且最快的解决方案是 dat[(rowSums(dat[,2:8]>10)==0),]。 - andrnev
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接