2

我有一个向量 v ,其中每个条目是一个或多个字符串(或可能是字符(0)),用分号分隔:

ABC

DEF;ABC;QWE

TRF

character(0)

ABC;GFD

在“;”上拆分后,我需要找到包含“ABC”(1、2、5 或逻辑向量 T、T、F、F、T)的向量的索引

我目前正在使用如下循环:

toSelect=integer(0)
for(i in c(1:length(v))){
if(length(v[i])==0) next
words=strsplit(v[i],";")[[1]] 
if(!is.na(match("ABC",words))) toSelect=c(toSelect,i)
}

不幸的是,我的向量有 450k 条目,所以这需要很长时间。我宁愿通过做类似的事情来创建一个逻辑向量

toSelect=(!is.na(match("ABC",strsplit(v,";")))

但是由于 strsplit 返回一个列表,我找不到将 strsplit(v,";") 正确格式化为向量的方法(unlist 不会这样做,因为它会破坏索引)。有人对如何加速此代码有任何想法吗?

谢谢!

4

3 回答 3

4

使用正则表达式:

v = list("ABC", "DEF;ABC;QWE", "TRF", character(0), "ABC;GFD")
grep("(^|;)ABC($|;)", v)
#[1] 1 2 5
于 2013-05-07T19:51:10.993 回答
3

棘手的部分是处理character(0),@BlueMagister 通过替换它来伪造它character(1)(这允许使用向量,但不允许表示原始问题)。也许

v <- list("ABC", "DEF;ABC;QWE", "TRF", character(0), "ABC;GFD")
v[sapply(v, length) != 0] <- strsplit(unlist(v), ";", fixed=TRUE)

进行字符串拆分。可能会在基础 R 中进行,但我建议使用IRanges

source("http://bioconductor.org/biocLite.R")
biocLite("IRanges")

安装,然后

library(IRanges)
w = CharacterList(v)

它给出了一个类似列表的结构,其中所有元素都必须是字符向量。

> w
CharacterList of length 5
[[1]] ABC
[[2]] DEF ABC QWE
[[3]] TRF
[[4]] character(0)
[[5]] ABC GFD

然后可以做一些有趣的事情,比如问“元素成员是否等于 ABC”

> w == "ABC"
LogicalList of length 5
[[1]] TRUE
[[2]] FALSE TRUE FALSE
[[3]] FALSE
[[4]] logical(0)
[[5]] TRUE FALSE

或“任何元素成员是否等于 ABC”

> any(w == "ABC")
[1]  TRUE  TRUE FALSE FALSE  TRUE

这将很好地扩展。对于不支持“开箱即用”的操作,策略(计算成本低)是unlist然后转换为等长向量,然后relist使用原始 CharacterList 作为骨架,例如reverse在每个成员上使用:

> relist(reverse(unlist(w)), w)
CharacterList of length 5
[[1]] CBA
[[2]] FED CBA EWQ
[[3]] FRT
[[4]] character(0)
[[5]] CBA DFG

正如@eddi 指出的那样,这比grep 慢。动机是 (a) 避免需要制定复杂的正则表达式,同时 (b) 为其他操作获得灵活性,人们可能希望对这种结构的数据进行操作。

于 2013-05-07T21:17:04.570 回答
2

strsplitsapply和一起使用%in%

v <- c("ABC","DEF;ABC;QWE","TRF",character(1),"ABC;GFD")
sapply(strsplit(v,";"),function(x) "ABC" %in% x)
#[1]  TRUE  TRUE FALSE FALSE  TRUE
于 2013-05-07T19:54:27.450 回答