Delete characters before regular expression (R)

南楼画角 提交于 2019-12-14 03:18:22

问题


I have a character vector of stock tickers where the ticker name is concatenated to the country in which that ticker is based in the following form: country_name/ticker_name. I am trying to split each string and delete everything from the '/' back, returning a character vector of only the ticker names. Here is an example vector:

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

My initial thought would be to use the stringr library. I don't have really any experience with that package, but here is what I was trying:

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

But I was unsure how to return only the second element of each list as a single vector.

How would I do this over a large character vector (~105 million entries)?


回答1:


Some benchmark here including all the methods suggested by @David Arenburg, and another method using str_extract from stringr package.

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

The tstrsplit method is the fastest.

Update:

Add another method from @Frank, this comparison is not strictly accurate which depends on the actual data, if there is a lot of duplicated cases as the sample_string is produced above, the advantage is quite obvious:

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



回答2:


Some helpful notes about your question: Firstly, there is a str_split_fixed function in the stringrpackage which does what you want it to do by calling 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]

It works by calling stringi::stri_split_fixed and is not dissimilar to

do.call("c", lapply(str_split(sample_string, '/'),"[[",2))

Secondly, another way to think about extracting each second element of the list is by doing exactly what tstrsplit is doing internally.

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

On a total side note, the above should be marginally faster than calling tstrsplit. This of course, is probably not worth typing at length but it helps to know what the function does.

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

Regarding this second method, in short, transposing this list of length 7 million, each with 2 elements will convert your result to a list of length 2, each with 7 million elements. You are then extracting the second element of this list.



来源:https://stackoverflow.com/questions/38623294/delete-characters-before-regular-expression-r

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!