2017-11-21 2 views
6

몇 개의 문자열이 있는데, 몇 가지 예가 있습니다.문자열의 부분 문자열과 숫자를 추출합니다. R

rfoutputtablep7q10000t20000c100 
rfoutputtablep7q1000t20000c100 
svmLinear2outputtablep7q20000t20000c100 
svmLinear2outputtablep7q5000t20000c100 

나는 열이있는 데이터 프레임을 만들고 싶어 : algorithm, p, q, tc 이러한 문자열에서 값을 추출합니다. 그래서 "outputtable" 전에 물건이 algorithm이며, "p" 다음의 숫자는 p의 가치 등

방법이 데이터 프레임을 생성 할 수 있습니다, "q" 후 수 q의 값입니다?

+0

'''tidyr :: separate'''를 몇 번 사용하십시오. – rsmith54

+0

정규 표현식을 사용할 수 있습니다. – kurdy

+0

정규식은 나를 혼란스럽게합니다. 당신이 저를 도울 수 있다면 정말 감사 할 것입니다. 나는 아직도 매우 초보자이다 : ( –

답변

5

기본 R 만 사용.

res <- do.call(rbind, strsplit(y, 'outputtable|p|q|t|c')) 
res <- as.data.frame(res[, -2]) 
res[-1] <- lapply(res[-1], function(x) as.numeric(as.character(x))) 
names(res) <- c("algorithm", "p", "q", "t", "c") 
res 
# algorithm p  q  t c 
#1   rf 7 10000 20000 100 
#2   rf 7 1000 20000 100 
#3 svmLinear2 7 20000 20000 100 
#4 svmLinear2 7 5000 20000 100 

데이터. 여기

y <- scan(text = '"rfoutputtablep7q10000t20000c100" 
"rfoutputtablep7q1000t20000c100" 
"svmLinear2outputtablep7q20000t20000c100" 
"svmLinear2outputtablep7q5000t20000c100"', 
what = character()) 
+2

'setNames (data.frame (doball, strsplit (x, '출력 테이블 \\ D | p | q | t | c'))), c ("A" , "p", "q", "t", "c"))' –

+0

@db 작동하지만 왜'\\ D'입니까? 십진수의 부정이 아닙니까? [regex] (http://127.0.0.1:16932/library/base/html/regex.html). –

+1

@db '\\ D'대신 '.' 점을 사용하려했는데 작동합니다. –

4
library(stringr) 
myd = c("p", "q", "t", "c") 
data.frame(sapply(myd, function(a) str_extract(str_extract(x, paste0(a, "\\d+")), "\\d+"))) 
# p  q  t c 
#1 7 10000 20000 100 
#2 7 1000 20000 100 
#3 7 20000 20000 100 
#4 7 5000 20000 100 

#For first column 
substr(x, 1, unlist(gregexpr("outputtable", x)) - 1) 
#[1] "rf"   "rf"   "svmLinear2" "svmLinear2" 

데이터

x = c("rfoutputtablep7q10000t20000c100", "rfoutputtablep7q1000t20000c100", 
"svmLinear2outputtablep7q20000t20000c100", "svmLinear2outputtablep7q5000t20000c100") 
4

알고리즘 얻을 수있는 긍정적 인 예견을 사용하여 페이지에 대한 긍정적 인 모습 숨김 https://regex101.com/r/7vDK1x/2

:

gsub("^(\\w+)(?=outputtable).*", "\\1", string, perl=TRUE) 

라이브 예를 , q, t 및 c (p를 다른 문자로 대체하십시오. (?<=p).

gsub(".*?(?<=q)(\\d+).*", "\\1", a, perl=TRUE) 
2

stringi 패키지를 사용하는 또 다른 해결책. 지금까지 제안 된 모든 솔루션을 비교하는 벤치 마크를 확인하십시오. stringi은 기본 R보다 약간 빠르지 만 간단한 솔루션을 찾는다면 물론 조금 더 복잡합니다. 따라서 속도 나 단순성에 대한 선호도에 따라 어느 쪽이든 좋습니다. 그러나 stringi는보다 복잡한 경우에 더 많은 유연성을 제공합니다. (우리는 모든 data.frame을 설정하고 형식을 변환 slighlty 다른 접근 방식을 사용했기 때문에 벤치 마크가 완벽하게 비교할 수 없습니다, 참고.)

업데이트 : 내 대답에 코드를 업데이트 한 Rui Barradas의 의견에 대응 . (i) 열을 숫자로 변환하는 것을 포함하여 stringi 접근 방식을 사용하여 함수를 제안 했으므로 완전한 작업을 수행 할 수 있습니다. (ii) 또한, 지금까지 제안 된 모든 접근법 (주석 포함)이 포함되도록 벤치 마크를 추가했습니다. 공정한 비교를 절반으로 달성하기 위해 제안 된 접근법을 수정 했으므로 출력은 동일합니다. 특히 비교를 위해 열을 숫자로 변환하는 것을 건너 뛰었으며 중간 할당 등을 피함으로써 명령을 유사하게 간결하게했습니다.

여전히 가장 빠른 것으로 보입니다.

공정한 비교 (특히 stringr 솔루션이 코드와 비슷하게 개선 될 수도 있지만, 패키지에 익숙하지 않으므로 제안 된 솔루션을 계속 유지함)와 관련하여 아무 것도 지켜 본다면 저를 시정하십시오.

library(stringi) 
library(stringr) 
library(microbenchmark) 

strings <- c("rfoutputtablep7q10000t20000c100", 
       "rfoutputtablep7q1000t20000c100", 
      "svmLinear2outputtablep7q20000t20000c100", 
      "svmLinear2outputtablep7q5000t20000c100") 


split_to_df <- function(string, splititems, colidschar, firstcolname, replsplit_tonames) { 

    data <- as.data.frame(do.call(rbind 
           ,stri_split_regex(strings, paste(splititems, collapse = "|"))) 
         ,stringsAsFactors = FALSE) 
    names(data) <- c(firstcolname, stri_replace_all_regex(splititems, replsplit_tonames, "")) 
    numericcols <- setdiff(1:ncol(data), colidschar) 
    data[,numericcols] <- lapply(data[,numericcols], as.numeric) 
    return(data) 

} 

stringi_approach_complete <- function() { 

    df <- split_to_df(string = strings 
        ,splititems = c("outputtablep(?=\\d)", "q(?=\\d)", "t(?=\\d)", "c(?=\\d)") 
        ,colidschar = 1 
        ,firstcolname = "A" 
        ,replsplit_tonames = "\\(.*\\)|outputtable") 
    # class(df$p) 
    # [1] "numeric" 
    # A p  q  t c 
    # 1   rf 7 10000 20000 100 
    # 2   rf 7 1000 20000 100 
    # 3 svmLinear2 7 20000 20000 100 
    # 4 svmLinear2 7 5000 20000 100 

} 


stringi_approach_compare <- function() { 

    data <- as.data.frame(do.call(rbind, stri_split_regex(strings, c("outputtable|p(?=\\d)|q(?=\\d)|t(?=\\d)|c(?=\\d)")))) 
    names(data) <- c("A", "p", "q", "t", "c") 
    #class(data$p) 
    #[1] "factor" 
    #data 
    # A p  q  t c 
    # 1   rf 7 10000 20000 100 
    # 2   rf 7 1000 20000 100 
    # 3 svmLinear2 7 20000 20000 100 
    # 4 svmLinear2 7 5000 20000 100 

} 


stringr_approach <- function() { 

    res <- data.frame(p = str_extract(str_extract(strings, "p\\d+"), "\\d+"), 
        q = str_extract(str_extract(strings, "q\\d+"), "\\d+"), 
        t = str_extract(str_extract(strings, "t\\d+"), "\\d+"), 
        c = str_extract(str_extract(strings, "c\\d+"), "\\d+")) 
    #class(res$p) 
    #[1] "factor" 
    #res 
    # p  q  t c 
    # 1 7 10000 20000 100 
    # 2 7 1000 20000 100 
    # 3 7 20000 20000 100 
    # 4 7 5000 20000 100 

} 

base_approach1 <- function() { 

    res <- do.call(rbind, strsplit(strings, 'outputtable|p|q|t|c')) 
    res <- as.data.frame(res[, -2]) 
    names(res) <- c("A", "p", "q", "t", "c") 
    #class(res$p) 
    #[1] "factor" 
    #res[-1] <- lapply(res[-1], function(x) as.numeric(as.character(x))) 
    #res 
    #   A p  q  t c 
    #1   rf 7 10000 20000 100 
    #2   rf 7 1000 20000 100 
    #3 svmLinear2 7 20000 20000 100 
    #4 svmLinear2 7 5000 20000 100 


} 

base_approach2 <- function() { 

    df <- setNames(data.frame(do.call(rbind, strsplit(strings, 'outputtable\\D|p|q|t|c'))), c("A", "p", "q", "t", "c")) 
    #class(df$p) 
    #[1] "factor" 
    #df 
    # A p  q  t c 
    # 1   rf 7 10000 20000 100 
    # 2   rf 7 1000 20000 100 
    # 3 svmLinear2 7 20000 20000 100 
    # 4 svmLinear2 7 5000 20000 100 

} 



microbenchmark(
    base_approach1(), 
    base_approach2(), 
    stringi_approach_compare(), 
    stringr_approach(), 
    stringi_approach_complete() 

) 

# Unit: microseconds 
#   expr     min  lq  mean median  uq  max neval 
# base_approach1()   260.139 273.3635 337.1985 285.6005 298.2330 5280.152 100 
# base_approach2()   352.906 362.1820 461.8205 374.8140 391.9850 4645.791 100 
# stringi_approach_compare() 280.667 297.8380 312.8426 307.3125 319.1545 654.098 100 
# stringr_approach()   849.499 867.6570 956.7596 886.2100 923.7115 5651.609 100 
# stringi_approach_complete() 319.747 333.9580 461.5521 346.7870 369.0900 10985.052 100 
+0

내 대답에 대한 의견에서 @db one-liner 벤치마킹 할 수 있습니까? 가장 빠른 것 같습니다. 어쨌든, upvote. –

+0

확실히, 좋은 생각, 의견을 조사하지 않은, 죄송합니다, 그것을 할거야. 내일... –

관련 문제