




Код
a <- a[!grepl("^MS", a)]
gsub("\\.[0-9]$", "", a)
# [1] "AT2G26340" "AT2G26355"
Объяснение
regex, чтобы отфильтровать все элементы, начинающиеся с MS.regex снова, чтобы заменить точку и последнюю цифру из оставшихся элементовЕсли мы хотим полностью избежать регулярных выражений, как упоминает @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"
Поскольку у нас есть довольно много новых ответов, мы добавляем тест, включая все из них с вектором длиной 400 КБ.
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 готово. Это довольно интересно знать. Как вы думаете, использование регулярных выражений делает его медленнее?
Понятия не имею, на странице справки написано, что это быстрее, чем подстрока и грепл, поэтому решил проверить, и это быстро. Но ест в два раза больше памяти, смотрите бенчмарки ниже.
Вот еще одна строчка stringr,
library(stringr)
word(a[!str_detect(a, '^MS')], 1, sep = fixed('.'))
#[1] "AT2G26340" "AT2G26355"
Думайте о них как об именах файлов и отбрасывайте расширение:
tools::file_path_sans_ext(a[ !grepl("^MS", a) ])
# [1] "AT2G26340" "AT2G26355"
Поскольку у человека около 200 тысяч транскриптов, вот эталон:
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~
Вы также можете попробовать:
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"
Я не вижу сочетания sub() и startsWith(), поэтому
sub(".{2}$", "", a[!startsWith(a, "MS")])
# [1] "AT2G26340" "AT2G26355"
Связанный пост: Удалить часть строки после «.»