【发布时间】:2019-08-05 00:42:20
【问题描述】:
示例载体(基因转录ID):
a <- c('MSTRG.7176.1', 'MSTRG.7176.2', 'AT2G26340.2', 'AT2G26355.1')
这是一个长向量的子集,如何删除以“MS”开头的项目,然后切断左侧项目的最后 2 位?
【问题讨论】:
示例载体(基因转录ID):
a <- c('MSTRG.7176.1', 'MSTRG.7176.2', 'AT2G26340.2', 'AT2G26355.1')
这是一个长向量的子集,如何删除以“MS”开头的项目,然后切断左侧项目的最后 2 位?
【问题讨论】:
如果我们想像@sindri_baldur 提到的那样完全避免正则表达式,我们可以使用
string <- a[!startsWith(a, "MS")]
substr(string, 1, nchar(string) - 2)
或者grep和substr
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")]这样的正则表达式
startsWith 移到顶部,因为它在 100K 矢量上快两倍。
这里也是stringr 单行代码,
library(stringr)
word(a[!str_detect(a, '^MS')], 1, sep = fixed('.'))
#[1] "AT2G26340" "AT2G26355"
【讨论】:
代码
a <- a[!grepl("^MS", a)]
gsub("\\.[0-9]$", "", a)
# [1] "AT2G26340" "AT2G26355"
说明
regex过滤掉所有以MS开头的元素
regex 替换剩余元素中的点和最后一个数字【讨论】:
由于人类有大约 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~
【讨论】:
将它们视为文件名并删除扩展名:
tools::file_path_sans_ext(a[ !grepl("^MS", a) ])
# [1] "AT2G26340" "AT2G26355"
【讨论】:
我没有看到sub() 和startsWith() 的组合,所以
sub(".{2}$", "", a[!startsWith(a, "MS")])
# [1] "AT2G26340" "AT2G26355"
【讨论】:
你也可以试试:
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)
【讨论】:
提供stringi 的可能性:我更喜欢一个衬里,但也许两行解决方案就足够了。
b<-stringi::stri_replace_all(stringi::stri_sub(a,1,-3),regex="^M.*","")
b[grepl('\\w+',b)]
#[1] "AT2G26340" "AT2G26355"
【讨论】: