簡體   English   中英

一種使用正則表達式 grep 在 R 中接收數據幀或列表的方法

[英]A way to grep using regular expresion to receive a dataframe or a list in R

我在數據框中有一列,如下所示:

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 完全陌生,並且無法找到將 grep 放入數據幀的方法。

我想出的最接近的事情是這樣的:

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."

首先,它只為每個肽返回一個字符串,而我希望它返回與括號對一樣多的字符串。 其次,我知道我的正則表達式不正確——我沒有省略數字和括號,而且我願意。

編輯:我編輯了輸出,因為其中有一個錯字,我刪除了對另一個問題的提及,我在這里收到答案之前沒有時間問!

歡迎任何建議!

我的第一個想法是使用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=忽略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 。)

您可以使用一個函數,該函數將為每組括號創建一個左側和右側(因此您將獲得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

首先將sep定義為任何未出現在peptide字符。 我們在下面使用了一個空格。

然后創建兩個變量,其中數字字段已被刪除,並且它們周圍的括號也已被刪除。 p0正是因為雖然ps類似於p0但每個非數字字段的最后一個字符被替換為sep (以便我們以后可以找到它)。

使用上述變量計算pos ,它是一個數字矩陣,其第 i 列包含p0第 i 個字段末尾的字符位置。 為此,我們使用gregexprps查找sep的位置,然后將其處理為數字矩陣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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM