Способ grep с использованием регулярного выражения для получения кадра данных или списка в R - PullRequest
0 голосов
/ 20 мая 2018

У меня есть столбец в кадре данных, который выглядит следующим образом:

peptide <- c("aaa(0.011)bbb(0.989)ccc","aaa(1)bbbccc","aaabbb(0.15)ccc(0.85)ddd",
             "aaabbb(0.75)cc(0.24)ddd(0.01)")

Я хотел бы извлечь текст, обрамляющий каждую из скобок.Иногда в каждой строке может быть до 7 наборов скобок (в моем примере это максимум 3).При извлечении текста я хотел бы избавиться от скобок и цифр вместе и просто сохранить буквы.Допустим, я хочу извлечь до пяти букв на каждой стороне каждой пары скобок.Если бы я достиг этого, мой вывод выглядел бы так:

col1          col2        col3
aaabbbcc      aabbbccc    NA
aaabbbcc      NA          NA
aabbbcccdd   bbcccddd    NA
aabbbccddd   bbbccddd    ccddd

Где каждый ряд соответствует строкам, извлеченным из одного пептида.

Я совершенно новичок в R и совершенно новичок в grep / sub, и не могу найти способ войти в фрейм данных.

Самое близкое, что я придумал, этоthis:

before<- sub(".*([[:print:]][[:print:]][[:print:]][[:print:]][[:print:]])\\(.*","\\1", peptide)
after<- sub(".*\\)([[:print:]][[:print:]][[:print:]][[:print:]][[:print:]]).*","\\1", peptide)
final <- paste(before,after,sep="")

Это не возвращает то, что я хочу.

> final
[1] "1)bbbbbb(0"        "aaa(1)bbbcccbbbcc" "5)cccccc(0"        "75)cccc(0."

Во-первых, он просто возвращает одну строку на пептид, тогда как я хотел бы, чтобы он возвращал столько строк, сколько естьпары скобок.Во-вторых, я знаю, что мои регулярные выражения неверны - я не опускаю цифры и скобки, и я хотел бы.

РЕДАКТИРОВАТЬ: я отредактировал вывод, потому что в нем была опечатка, и я удалилупоминание другого вопроса, который я не успел задать, прежде чем получить ответы здесь!

Любые предложения приветствуются!

Ответы [ 3 ]

0 голосов
/ 20 мая 2018

Вы можете использовать функцию, которая создаст левую и правую стороны для каждого набора скобок (таким образом, вы получите n - 1 строки для n скобок) и свернете все влево и вправо запятой.Затем введите не более 5 символов с каждой стороны запятой.

peptide <- c("aaa(0.011)bbb(0.989)ccc","aaa(1)bbbccc","aaabbb(0.15)ccc(0.85)ddd",
             "aaabbb(0.75)cc(0.24)ddd(0.01)")


f <- function(x) {
  l <- lapply(seq_along(x), function(ii) {
    x <- rbind(trimws(x), replace(gsub('.', '', x), ii, ','))
    paste(x, collapse = '')
  })

  sapply(l[-length(l)], function(x)
    gsub('([a-z]{1,5}),([a-z]{1,5})?|.', '\\1\\2', x))
}


sp <- strsplit(gsub('\\([0-9.]+\\)', ', ', peptide), ',')

## for example
f(sp[[4L]])
# [1] "aabbbccddd" "bbbccddd"   "ccddd"     

## apply to everything and return as a data frame
l <- lapply(sp, f)
l <- lapply(l, function(x) {
  ml <- max(lengths(l))
  setNames(`length<-`(x, ml), paste0('col', seq.int(ml)))
})
data.frame(do.call('rbind', l))

#         col1     col2  col3
# 1   aaabbbcc aabbbccc  <NA>
# 2   aaabbbcc     <NA>  <NA>
# 3 aabbbcccdd bbcccddd  <NA>
# 4 aabbbccddd bbbccddd ccddd
0 голосов
/ 20 мая 2018

Сначала определите sep как любой символ, который не появляется в peptide.Мы использовали пробел ниже.

Затем создайте две переменные, в которых были удалены числовые поля и удалены круглые скобки вокруг них.p0 означает, что хотя ps похоже на p0, но последний символ каждого из нечисловых полей заменяется на sep (чтобы мы могли позже найти его).

ИспользованиеПеречисленные выше переменные вычисляют pos, который представляет собой числовую матрицу, в которой i-й столбец содержит позиции символов конца i-го поля в p0.Для этого мы используем gregexpr, чтобы найти местоположения sep в ps, а затем манипулируем этим в числовой матрице pos.

Затем для каждого элемента pos определяем положения символовначала и конца соответствующей выходной строки и используйте substring для извлечения этих подстрок из p0 с изменением размеров до тех же размеров, что и pos.

sep <- " "
pat <- "(.)\\(.*?\\)"
ps <- gsub(pat, sep, peptide)
p0 <- gsub(pat, "\\1", peptide)

g <- gregexpr(sep, ps, fixed = TRUE)
pos <- t(unname(do.call("cbind", lapply(g, ts))))

replace(pos, TRUE, substring(p0, pos-5+1, pos+5))

, давая:

     [,1]         [,2]       [,3]   
[1,] "aaabbbcc"   "aabbbccc" NA     
[2,] "aaabbbcc"   NA         NA     
[3,] "aabbbcccdd" "bbcccddd" NA     
[4,] "aabbbccddd" "bbbccddd" "ccddd"
0 голосов
/ 20 мая 2018

Моя первая мысль - использовать strsplit с использованием чисел / паренов в качестве разделителей:

str(
  strsplit(peptide, '[().[:digit:]]+')
)
# List of 4
#  $ : chr [1:3] "aaa" "bbb" "ccc"
#  $ : chr [1:2] "aaa" "bbbccc"
#  $ : chr [1:3] "aaabbb" "ccc" "ddd"
#  $ : chr [1:3] "aaabbb" "cc" "ddd"

Пока это выглядит хорошо, так что теперь мы можем перебирать каждый разрыв и захватывать конкатенации до / после,(Пока игнорируйте параметр removeqmark=, я его сейчас опишу.)

surrounding <- function(vec, k=5, removeqmark=TRUE) {
  l <- length(vec)
  out <- sapply(seq_len(l-1), function(i) {
    bef <- paste(vec[1:i], collapse="")
    aft <- paste(vec[(i+1):l], collapse="")
    paste0(substr(bef, max(1, nchar(bef)-k+1), nchar(bef)),
           substr(aft, 1, min(k, nchar(aft))))
  })
  if (removeqmark) out <- gsub("\\?", "", out)
  out
}

Теперь мы можем перебирать векторы разделенной строки, используя эту функцию:

str(
  lapply(strsplit(peptide, '[().[:digit:]]+'), surrounding)
)
# List of 4
#  $ : chr [1:2] "aaabbbcc" "aabbbccc"
#  $ : chr "aaabbbcc"
#  $ : chr [1:2] "aabbbcccdd" "bbcccddd"
#  $ : chr [1:2] "aabbbccddd" "bbbccddd"

К сожалению, выпадает треть последнего вектора.Это не удивительно для меня, поскольку окончание на разделителе не обязательно возвращает пустую строку.Таким образом, мы можем добавить что-то к каждой строке IFF, которую мы заканчиваем на разделителе:

( peptide2 <- gsub("([().[:digit:]])$", "\\1?", peptide) )
# [1] "aaa(0.011)bbb(0.989)ccc"        "aaa(1)bbbccc"                   "aaabbb(0.15)ccc(0.85)ddd"      
# [4] "aaabbb(0.75)cc(0.24)ddd(0.01)?"
str(
  strsplit(peptide2, '[().[:digit:]]+')
)
# List of 4
#  $ : chr [1:3] "aaa" "bbb" "ccc"
#  $ : chr [1:2] "aaa" "bbbccc"
#  $ : chr [1:3] "aaabbb" "ccc" "ddd"
#  $ : chr [1:4] "aaabbb" "cc" "ddd" "?"
str(
  lapply(strsplit(peptide2, '[().[:digit:]]+'), surrounding)
)
# List of 4
#  $ : chr [1:2] "aaabbbcc" "aabbbccc"
#  $ : chr "aaabbbcc"
#  $ : chr [1:2] "aabbbcccdd" "bbcccddd"
#  $ : chr [1:3] "aabbbccddd" "bbbccddd" "ccddd"

, где по умолчанию мы удаляем знак вопроса из результирующего окружения.Чтобы использовать окружающее число, отличное от 5, просто выполните:

lapply(strsplit(peptide2, '[().[:digit:]]+'), surrounding, k=2)

Чтобы объединить это в data.frame, вам нужно проделать дополнительную работу, поскольку у вас есть строки различной длины.

rows <- lapply(strsplit(peptide2, '[().[:digit:]]+'), surrounding)
( maxrows <- max(lengths(rows)) )
# [1] 3
rows <- lapply(rows, function(r) c(r, rep(NA_character_, maxrows - length(r))))
do.call(rbind, rows)
#      [,1]         [,2]       [,3]   
# [1,] "aaabbbcc"   "aabbbccc" NA     
# [2,] "aaabbbcc"   NA         NA     
# [3,] "aabbbcccdd" "bbcccddd" NA     
# [4,] "aabbbccddd" "bbbccddd" "ccddd"

(Это генерирует сэндвич matrix ... в as.data.frame, если вам нужен кадр.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...