在正则表达式(R)之前删除字符

时间:2016-07-27 21:14:08

标签: r split stringr

我有一个股票代码的字符向量,其中股票代码名称连接到该股票代码所基于的国家/地区:country_name / ticker_name。我试图拆分每个字符串并从'/'后面删除所有内容,返回仅有股票名称的字符向量。这是一个示例向量:

sample_string <- c('US/SPY', 'US/AOL', 'US/MTC', 'US/PHA', 'US/PZI',
                   'US/AOL', 'US/BRCM')

我最初的想法是使用stringr库。我对这个软件包没有任何经验,但这就是我的尝试:

library(stringr)
split_string <- str_split(sample_string, '/')

但我不确定如何仅将每个列表的第二个元素作为单个向量返回。

我如何在大字符向量(约1.05亿条目)上执行此操作?

2 个答案:

答案 0 :(得分:3)

这里有一些基准,包括@David Arenburg建议的所有方法,以及使用str_extract包中的stringr的另一种方法。

sample_string <- rep(sample_string, 1000000)

library(data.table); library(stringr)
s1 <- function() sub(".*/(.*)", "\\1", sample_string)
s2 <- function() sub(".*/", "", sample_string)
s3 <- function() str_extract(sample_string, "(?<=/)(.*)")
s4 <- function() tstrsplit(sample_string, "/", fixed = TRUE)[[2]]

length(sample_string)
# [1] 7000000

identical(s1(), s2())
# [1] TRUE
identical(s1(), s3())
# [1] TRUE
identical(s1(), s4())
# [1] TRUE

microbenchmark::microbenchmark(s1(), s2(), s3(), s4(), times = 5)
# Unit: seconds
#  expr      min       lq     mean   median       uq      max neval
#  s1() 3.916555 3.917370 4.046708 3.923246 3.925184 4.551184     5
#  s2() 3.584694 3.593755 3.726922 3.610284 3.646449 4.199426     5
#  s3() 3.051398 3.062237 3.354410 3.138080 3.722347 3.797985     5
#  s4() 1.908283 1.964223 2.349522 2.117521 2.760612 2.996971     5

tstrsplit方法最快。

<强>更新

从@Frank添加另一个方法,这种比较并不严格准确,这取决于实际数据,如果上面生成sample_string时存在大量重复案例,则优势非常明显:

s5 <- function() setDT(list(sample_string))[, v := tstrsplit(V1, "/", fixed = TRUE)[[2]], by=V1]$v

identical(s1(), s5())
# [1] TRUE

microbenchmark::microbenchmark(s1(), s2(), s3(), s4(), s5(), times = 5)
# Unit: milliseconds
#  expr        min       lq      mean    median        uq       max neval
#  s1() 3905.97703 3913.264 3922.8540 3913.4035 3932.2680 3949.3575     5
#  s2() 3568.63504 3576.755 3713.7230 3660.5570 3740.8252 4021.8426     5
#  s3() 3029.66877 3032.898 3061.0584 3052.6937 3086.9714 3103.0604     5
#  s4() 1322.42430 1679.475 1985.5440 1801.9054 1857.8056 3266.1101     5
#  s5()   82.71379  101.899  177.8306  121.6682  209.0579  373.8141     5

答案 1 :(得分:2)

关于您的问题的一些有用的说明:首先,str_split_fixed包中有一个stringr函数,通过调用lapply来执行您希望它执行的操作。

library(data.table); library(stringr)
sample_string <- c('US/SPY', 'US/AOL', 'US/MTC', 'US/PHA', 'US/PZI',
                   'US/AOL', 'US/BRCM')
sample_string <- rep(sample_string, 1e5)
split_string <- str_split_fixed(sample_string, '/', 2)[,2]

它通过调用stringi::stri_split_fixed起作用,与

没有什么不同
do.call("c", lapply(str_split(sample_string, '/'),"[[",2))

其次,考虑提取列表中每个第二个元素的另一种方法是完全执行tstrsplit内部正在做的事情。

transpose(strsplit(sample_string, "/", fixed = T))[[2]]

总的来说,上述内容应该比调用tstrsplit略快。当然,这可能不值得打字,但它有助于了解该功能的作用。

library(data.table); library(stringr)
s4 <- function() tstrsplit(sample_string, "/", fixed = TRUE)[[2]]
s5 <- function() transpose(strsplit(sample_string, "/", fixed = T))[[2]]

identical(s4(), s5())
microbenchmark::microbenchmark(s4(), s5(), times = 20)

microbenchmark::microbenchmark(s4(), s5(), times = 20)
Unit: milliseconds
 expr      min       lq     mean   median       uq      max neval
 s4() 161.0744 193.3611 255.8136 234.9945 271.6811 434.7992    20
 s5() 140.8569 176.5600 233.3570 194.1676 251.7921 420.3431    20

关于第二种方法,简而言之,转换这个长度为700万的列表,每个包含2个元素,将结果转换为长度为2的列表,每个列表包含700万个元素。然后,您将提取此列表的第二个元素。