2017-11-21 54 views
6

いくつかの例がありますが、いくつかの文字列があります。文字列の部分文字列と数字を抽出するR

rfoutputtablep7q10000t20000c100 
rfoutputtablep7q1000t20000c100 
svmLinear2outputtablep7q20000t20000c100 
svmLinear2outputtablep7q5000t20000c100 

は、私は列のデータフレームを作りたい:algorithmpqt、およびc及びこれらの文字列から値を抽出します。だから、"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、 'outputtable \\ D | p | q | t | c')))、c(" A " 、 "p"、 "q"、 "t"、 "c")) ' –

+0

@dbなぜそれがうまくいかないのですか?それは小数点の否定ではありませんか? [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" 

DATA

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

アルゴリズムを取得するには正の先読みを使用します。

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

ライブ例:https://regex101.com/r/7vDK1x/2

pの正見ビハインド、q、t、c(pを他の文字で置き換える(?<=p)

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

stringiパッケージを使用して、別の解決策。これまでに提案されているすべてのソリューションを比較するベンチマークを確認します。 stringiはベースRよりもわずかに速いですが、単純な解決策を探すならば、もちろんもう少し複雑です。したがって、あなたのスピードやシンプルさに応じてどちらかが良いです。しかし、stringiはより複雑なケースに対して柔軟性を提供します。 (私たちはすべてのdata.frameを設定し、型を変換するためのslighlty異なるアプローチを使用していたので、ベンチマークは完全に同等ではありませんが、注意してください。)

UPDATE:私は私の答えにコードを更新したRui Barradasのコメントを受けて 。 (i)カラムの数値への変換を含むstringiのアプローチを使用して関数を提案しました。 (ii)さらに、ベンチマークを追加して、これまでに提案されているすべてのアプローチ(コメントにも)が含まれるようにしました。公正な比較の半分を達成するために、私は提案されたアプローチを修正したので、出力は同じです。特に、比較のために列の数値への変換をスキップして、暫定的な代入などを避けてコマンドを同様に簡潔にしました。stringiはまだまだ最速です。

公平な比較に関して何かを監督している場合は、私を修正してください(特に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

確かに、良いアイデアは、コメントを見ていません、申し訳ありません、私はそれをやります明日... –

関連する問題