【发布时间】:2015-06-24 09:55:05
【问题描述】:
如果我有一系列字符,例如"AABBABBBAAAABBAAAABBBAABBBBABABB"。
有没有办法让 R 计算 A 的运行次数并说明每个长度有多少?
所以我想知道连续有多少个 3 A 的实例,有多少个单个 A 的实例,连续有多少个 2 A 的实例,等等。
【问题讨论】:
如果我有一系列字符,例如"AABBABBBAAAABBAAAABBBAABBBBABABB"。
有没有办法让 R 计算 A 的运行次数并说明每个长度有多少?
所以我想知道连续有多少个 3 A 的实例,有多少个单个 A 的实例,连续有多少个 2 A 的实例,等等。
【问题讨论】:
table(rle(strsplit("AABBABBBAAAABBAAAABBBAABBBBABABB","")[[1]]))
给予
values
lengths A B
1 3 1
2 2 3
3 0 2
4 2 1
其中(向下读取 A 列)意味着有 3 个长度为 1 的 A 运行、2 个长度为 2 的 A 运行和 2 个长度为 4 的运行。
【讨论】:
rle 通常很快,但strsplit 可能很慢。
table(nchar(strsplit(x, "[^A]+")[[1]])),因为 OP 只关心“A”。
strsplit 返回一个列表(在这种情况下,由于参数仅包含一个元素,因此它返回一个包含一个元素的列表,其中包含拆分后的字符向量)。我想要字符向量而不是它包含的列表; [[1]] 是实现这一目标的一种方法。
试试
v1 <- scan(text=gsub('[^A]+', ',', str1), sep=',', what='', quiet=TRUE)
table(v1[nzchar(v1)])
# A AA AAAA
# 3 2 2
或者
library(stringi)
table(stri_extract_all_regex(str1, '[A]+')[[1]])
# A AA AAAA
# 3 2 2
set.seed(42)
x1 <- stri_rand_strings(1,1e7, pattern='[A-G]')
system.time(table(stri_split_regex(x1, "[^A]+", omit_empty = TRUE)))
# user system elapsed
# 0.829 0.002 0.831
system.time(table(stri_extract_all_regex(x1, '[A]+')[[1]]))
# user system elapsed
# 0.790 0.002 0.791
system.time(table(rle(strsplit(x1,"")[[1]])) )
# user system elapsed
# 30.230 1.243 31.523
system.time(table(strsplit(x1, "[^A]+")))
# user system elapsed
# 4.253 0.006 4.258
system.time(table(attr(gregexpr("A+",x1)[[1]], 'match.length')))
# user system elapsed
# 1.994 0.004 1.999
library(microbenchmark)
microbenchmark(david=table(stri_split_regex(x1, "[^A]+", omit_empty = TRUE)),
akrun= table(stri_extract_all_regex(x1, '[A]+')[[1]]),
david2 = table(strsplit(x1, "[^A]+")),
glen = table(rle(strsplit(x1,"")[[1]])),
plannapus = table(attr(gregexpr("A+",x1)[[1]], 'match.length')),
times=20L, unit='relative')
#Unit: relative
# expr min lq mean median uq max neval cld
# david 1.0000000 1.000000 1.000000 1.000000 1.0000000 1.000000 20 a
# akrun 0.7908313 1.023388 1.054670 1.336510 0.9903384 1.004711 20 a
# david2 4.9325256 5.461389 5.613516 6.207990 5.6647301 5.374668 20 c
# glen 14.9064240 15.975846 16.672339 20.570874 15.8710402 15.465140 20 d
#plannapus 2.5077719 3.123360 2.836338 3.557242 2.5689176 2.452964 20 b
str1 <- 'AABBABBBAAAABBAAAABBBAABBBBABABB'
【讨论】:
stringi,很难竞争,但我会更新以使其完整
这是使用strsplit的另一种方式
x <- "AABBABBBAAAABBAAAABBBAABBBBABABB"
table(strsplit(x, "[^A]+"))
# A AA AAAA
# 3 2 2
或与stringi 包类似
library(stringi)
table(stri_split_regex(x, "[^A]+", omit_empty = TRUE))
【讨论】:
为了完整起见,这里有另一种方法,使用 regmatches 和 gregexpr 组合来提取正则表达式:
x <- "AABBABBBAAAABBAAAABBBAABBBBABABB"
table(regmatches(x,gregexpr("A+",x))[[1]])
# A AA AAAA
# 3 2 2
或者实际上,由于gregexpr 将捕获的子字符串的长度作为属性,甚至可以直接这样做:
table(attr(gregexpr("A+",x)[[1]],'match.length'))
# 1 2 4
# 3 2 2
【讨论】:
stringi 的技术(请参阅他的答案)或 base 方式:paste(sample(c("A","B"),100,replace=TRUE),collapse="")