【问题标题】:How to remove certain items from a vector?如何从向量中删除某些项目?
【发布时间】:2019-08-05 00:42:20
【问题描述】:

示例载体(基因转录ID):

a <- c('MSTRG.7176.1', 'MSTRG.7176.2', 'AT2G26340.2', 'AT2G26355.1')

这是一个长向量的子集,如何删除以“MS”开头的项目,然后切断左侧项目的最后 2 位?

【问题讨论】:

标签: r regex vector


【解决方案1】:

如果我们想像@sindri_baldur 提到的那样完全避免正则表达式,我们可以使用

string <- a[!startsWith(a, "MS")]
substr(string, 1, nchar(string) - 2)

或者grepsubstr

string <- grep('^MS',a, invert = TRUE, value = TRUE)
substr(string, 1, nchar(string) - 2)
#[1] "AT2G26340" "AT2G26355"

因为我们有很多新的答案添加了基准,包括所有这些都具有长度为 400k 的向量。

a <- c('MSTRG.7176.1', 'MSTRG.7176.2', 'AT2G26340.2', 'AT2G26355.1')
a <- rep(a, 100000)

library(microbenchmark)

microbenchmark(
ronak1 = {string <- a[!startsWith(a, "MS")];substr(string, 1, nchar(string) - 2)}, 
ronak2 = {string <- grep('^MS',a, invert = TRUE, value = TRUE);substr(string, 1, nchar(string) - 2)}, 
sotos = {word(a[!str_detect(a, '^MS')], 1, sep = fixed('.'))}, 
thothal = {b1 <- a[!grepl("^MS", a)];gsub("\\.[0-9]$", "", b1)}, 
zx8754 = tools::file_path_sans_ext(a[ !grepl("^MS", a) ]), 
tmfmnk = dirname(chartr(".", "/", a[!grepl("^MS", a)])), 
NelSonGon = {b<-stringi::stri_replace_all(stringi::stri_sub(a,1,-3),regex="^M.*","");b[grepl('\\w+',b)]}
)


#Unit: milliseconds
#      expr        min         lq       mean     median         uq       max neval
#    ronak1   34.75928   38.58217   45.63393   40.32845   44.24355  225.2581   100
#    ronak2   94.10687   96.72758  110.83819   99.26914  105.98822  938.2969   100
#     sotos 1926.21112 2500.27209 2852.43240 2861.61699 3173.10420 4478.7890   100
#   thothal  155.95328  160.62800  169.02275  164.46494  169.32770  218.5033   100
#    zx8754  172.96970  179.03618  186.12374  183.96887  188.06251  234.1895   100
#    tmfmnk  189.29085  195.14593  208.89245  199.47172  204.40604  547.7497   100
# NelSonGon  186.54426  198.29856  226.19221  206.54542  217.92970  948.2535   100

【讨论】:

  • 你的第二步避免使用正则表达式,你可以完全避免使用像a[!startsWith(a, "MS")]这样的正则表达式
  • @sindri_baldur 对。最好有一个非正则表达式选项。
  • 我会把你的第二个答案startsWith 移到顶部,因为它在 100K 矢量上快两倍。
  • @zx8754 完成。知道这很有趣。你认为使用正则表达式会变慢吗?
  • 不知道,帮助页面说它比substringgrepl快,所以决定测试一下,速度很快。但会消耗两倍的内存,请参阅下面的基准。
【解决方案2】:

这里也是stringr 单行代码,

library(stringr)

word(a[!str_detect(a, '^MS')], 1, sep = fixed('.'))
#[1] "AT2G26340" "AT2G26355"

【讨论】:

    【解决方案3】:

    代码

    a <- a[!grepl("^MS", a)]
    gsub("\\.[0-9]$", "", a)
    # [1] "AT2G26340" "AT2G26355"
    

    说明

    1. 使用regex过滤掉所有以MS开头的元素
    2. 再次使用regex 替换剩余元素中的点和最后一个数字

    【讨论】:

      【解决方案4】:

      由于人类有大约 200K 转录本,这里是基准:

      a <- c('MSTRG.7176.1', 'MSTRG.7176.2', 'AT2G26340.2', 'AT2G26355.1')
      a <- rep(a, 25000)
      
      library(stringr)
      
      bench::mark(
        x1 = {
          string <- grep('^MS',a, invert = TRUE, value = TRUE)
          substr(string, 1, nchar(string) - 2) },
        x2 = {
          string <- a[!startsWith(a, "MS")]
          substr(string, 1, nchar(string) - 2)},
        x3 = {
          word(a[!str_detect(a, '^MS')], 1, sep = fixed('.'))  
        },
        x4 = {
          gsub("\\.[0-9]$", "", a[ !grepl("^MS", a) ])},
        x5 = {
          tools::file_path_sans_ext(a[ !grepl("^MS", a) ])  
        }
        )
      
      # A tibble: 5 x 14
      # expression      min     mean  median     max `itr/sec` mem_alloc  n_gc n_itr total_time result memory  time  gc   
      # <chr>      <bch:tm> <bch:tm> <bch:t> <bch:t>     <dbl> <bch:byt> <dbl> <int>   <bch:tm> <list> <list>  <lis> <lis>
      # x1           20.3ms   21.3ms    21ms  28.1ms     46.9     1.91MB     1    24      512ms <chr ~ <Rprof~ <bch~ <tib~
      # x2           11.7ms   12.6ms  12.3ms  17.8ms     79.3     2.86MB     3    40      505ms <chr ~ <Rprof~ <bch~ <tib~
      # x3          668.5ms  668.5ms 668.5ms 668.5ms      1.50   10.54MB     9     1      668ms <chr ~ <Rprof~ <bch~ <tib~
      # x4           23.8ms   24.6ms  24.1ms  32.2ms     40.7      2.1MB     1    21      516ms <chr ~ <Rprof~ <bch~ <tib~
      # x5           33.8ms   35.2ms  34.7ms  40.9ms     28.4      2.1MB     1    15      528ms <chr ~ <Rprof~ <bch~ <tib~
      

      【讨论】:

        【解决方案5】:

        将它们视为文件名并删除扩展名:

        tools::file_path_sans_ext(a[ !grepl("^MS", a) ])
        # [1] "AT2G26340" "AT2G26355"
        

        【讨论】:

          【解决方案6】:

          我没有看到sub()startsWith() 的组合,所以

          sub(".{2}$", "", a[!startsWith(a, "MS")])
          # [1] "AT2G26340" "AT2G26355"
          

          【讨论】:

            【解决方案7】:

            你也可以试试:

            dirname(chartr(".", "/", a[!grepl("^MS", a)]))
            
            [1] "AT2G26340" "AT2G26355"
            

            首先,grepl() 标识以MS 开头的案例。其次,它使用chartr(). 替换为/。最后,dirname() 将字符串的一部分返回到最后一个/

            考虑到可能有元素不是以MS开头但包含两个或多个小数,您可以使用:

            chartr("/", ".", dirname(chartr(".", "/", a[!grepl("^MS", a)])))
            

            与第一种可能性相同,但它将剩余的/ 替换回.

            或者将chartr()替换为gsub()的第二种可能性:

            gsub("/", ".", dirname(gsub(".", "/", a[!grepl("^MS", a)], fixed = TRUE)), 
                 fixed = TRUE)
            

            【讨论】:

              【解决方案8】:

              提供stringi 的可能性:我更喜欢一个衬里,但也许两行解决方案就足够了。

               b<-stringi::stri_replace_all(stringi::stri_sub(a,1,-3),regex="^M.*","")
              b[grepl('\\w+',b)]
              #[1] "AT2G26340" "AT2G26355"
              

              【讨论】:

                猜你喜欢
                • 2010-12-08
                • 1970-01-01
                • 1970-01-01
                • 2012-11-03
                • 1970-01-01
                • 1970-01-01
                • 2020-12-03
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多