![](/img/trans.png)
[英]Filter the values in a variable in a dataframe which match a regular expression using grep in 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 個字段末尾的字符位置。 為此,我們使用gregexpr
在ps
查找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.