【问题标题】:Drop rows of R data.table删除 R data.table 的行
【发布时间】:2016-04-06 21:05:02
【问题描述】:

我有一个 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 的所有行。

【问题讨论】:

  • 如果您正在处理数据,您可能需要一个矩阵,而不是 data.table。
  • 从你的最后一点开始,试试dat[rowSums(dat[, .SD>10, .SDcols=2:7])==0]。或者,对于更惯用的data.table,请尝试dat[!(Reduce("|",dat[,lapply(.SD,function(x) x>10),.SDcols=2:7]))]
  • 所以在您的示例数据中不会保留任何行,一个空数据表?
  • @RichardScriven 值比较多,10 并不是实际使用的过滤值。
  • 不知道Reduce怎么办?

标签: r data.table


【解决方案1】:

你可以使用下面的命令

dat[-which(rowSums(dat[,2:8]>10)>0),]

或者正如 TTMOTT 指出的那样

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

稍微快一点 dat[-which(max(dat[,2:8])>10),]

它基本上计算存在真值的行

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

 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 小插图之后,我不明白 .SD &gt; 10 是如何工作的。它是否根据&gt; 10 检查所有列的每个元素(减去.SDcols)?
  • 是的,就是这个想法。它为您列为 SDcols 的每一列应用 .SD>10。这样可以加快操作。我想你可以像我用 dat[which(rowSums(dat[, 2:7])>0),] 指定的那样做
  • 您的原始陈述使用我上次评论中非常简单的陈述出现了一些问题
  • 事实上,which 可能不需要,是吗?仍然是一个很好的解决方案。
【解决方案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 在 cmets 中发布了类似的方法。我在编辑前只看到了他的原始评论。


或者使用

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

【讨论】:

    【解决方案3】:

    简单点怎么样?

    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 个随机数的基准测试。
    • 您的版本和我的版本都犯了错误。你的没有运行,在我的情况下,它让他的拥抱变得非常不同。我猜你用不同的代码库进行了基准测试。
    • 应该是 dat[(rowSums(dat[,2:8]>10)>0),] 而不是 dat[(rowSums(dat[,2:7]>10)>0 ),] 没有?
    • 是的。现在看起来不错。在最初的问题中是 2:7。结果看起来很有趣。
    猜你喜欢
    • 2014-05-04
    • 2016-04-22
    • 2018-01-08
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多