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

Delete characters before regular expression (R)

我有一个股票行情的字符向量,其中行情名称以以下形式连接到该行情所在的国家/地区:country_name/ticker_name。我正在尝试拆分每个字符串并从“/”后面删除所有内容,returning 一个仅包含代码名称的字符向量。这是一个示例向量:

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, '/')

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

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

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

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

关于你的问题的一些有用的注释:首先,stringr包中有一个 str_split_fixed 函数,它通过调用 lapply.[=19 来完成你想要它做的事情=]

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 万个元素的列表。然后您将提取此列表的第二个元素。