快速计算字符向量中的字符

时间:2011-10-22 00:09:23

标签: r

我有一个很长的单个字符向量,即somechars<-c("A","B","C","A"...)(长度在数百万的某个地方)

在这个向量中,我可以计算出“A”和“B”的总出现次数的最快方法是什么? 我尝试过使用greplapply,但这些都需要很长时间才能执行。

我目前的解决方案是:

tmp<-table(somechars)
sum(tmp["A"],tmp["B"])

但这还需要一段时间来计算。有没有更快的方法可以做到这一点?或者,我可以使用任何包,这已经更快了吗?我查看了stringr包但他们使用了一个简单的grep。

4 个答案:

答案 0 :(得分:9)

我认为这会是最快的......

sum(somechars %in% c('A', 'B'))

而且,它比...更快

sum(c(somechars=="A",somechars=="B"))

但不比......快......

sum(somechars=="A"|somechars=="B")

但是这可以通过你做了多少比较来确定...这让我回到了我的第一次猜测。一旦你想使用%in%版本加总超过2个字母是最快的。

答案 1 :(得分:8)

正则表达式很昂贵。您可以通过精确比较得到结果。

> somechars <- sample(LETTERS, 5e6, TRUE)
> sum(c(somechars=="A",somechars=="B"))
[1] 385675
> system.time(sum(c(somechars=="A",somechars=="B")))
   user  system elapsed 
  0.416   0.072   0.487 

更新以包括OP和其他答案的时间安排。还包括一个大于2个字符的测试。

> library(rbenchmark)
> benchmark( replications=5, order="relative",
+   grep = sum(grepl("A|B",somechars)),
+   table = sum(table(somechars)[c("A","B")]),
+   c = sum(c(somechars=="A",somechars=="B")),
+   OR = sum(somechars=="A"|somechars=="B"),
+   IN = sum(somechars %in% c("A","B")),
+   plus = sum(somechars=="A")+sum(somechars=="B") )
   test replications elapsed relative user.self sys.self user.child sys.child
6  plus            5   4.289 1.000000     3.836    0.436          0         0
3     c            5   4.991 1.163675     4.156    0.804          0         0
5    IN            5   5.480 1.277687     4.549    0.880          0         0
4    OR            5   5.574 1.299604     5.000    0.544          0         0
1  grep            5  16.426 3.829797    16.205    0.172          0         0
2 table            5  17.834 4.158079    12.793    4.884          0         0
> 
> benchmark( replications=5, order="relative",
+   grep = sum(grepl("A|B|C|D",somechars)),
+   table = sum(table(somechars)[c("A","B","C","D")]),
+   c = sum(c(somechars=="A",somechars=="B",
+             somechars=="C",somechars=="D")),
+   OR = sum(somechars=="A"|somechars=="B"|
+            somechars=="C"|somechars=="D"),
+   IN = sum(somechars %in% c("A","B","C","D")),
+   plus = sum(somechars=="A")+sum(somechars=="B")+
+          sum(somechars=="C")+sum(somechars=="D") )
   test replications elapsed relative user.self sys.self user.child sys.child
5    IN            5   5.513 1.000000     4.464    1.004          0         0
6  plus            5   8.603 1.560493     7.705    0.860          0         0
3     c            5  10.283 1.865228     8.648    1.560          0         0
4    OR            5  12.348 2.239797    10.849    1.464          0         0
2 table            5  17.960 3.257754    12.877    4.921          0         0
1  grep            5  21.692 3.934700    21.405    0.192          0         0

答案 2 :(得分:2)

根据我的期望,sum(x=='A') + sum(x=='B')是最快的。

与此处提出的其他解决方案不同,它不必执行任何其他不必要的操作,例如使用c(..)|连接中间结果。 它只是计数 - 唯一真正需要的东西!

R 2.13.1:

> x <- sample(letters, 1e7, TRUE)
> system.time(sum(x=='A') + sum(x=='B'))
   user  system elapsed 
   1.75    0.16    1.98 
> system.time(sum(c(x=='A', x=='B')))
   user  system elapsed 
   2.40    0.23    4.27 
> system.time(sum(x=='A' | x=='B'))
   user  system elapsed 
   2.25    0.19    2.54 

但真正有趣的是将sum(x %in% c('A','B'))与第一个最快的解决方案进行比较。在R 2.13.1中需要相同的时间,在R 2.11.1中,它要慢得多(与John报告的结果相同)!所以我建议使用第一个解决方案:sum(x=='A')+sum(x=='B')

答案 3 :(得分:0)

我最喜欢的工具是“我没有及时检查托马斯的解决方案”,

rle(sort(your_vector)) 

这当然是最简单的解决方案:-)。