2016-01-18 55 views
3

我有一個數據幀如下:各執定界符從次串固定數量的端

df = data.frame(a = 1:4, strings = c('ooss_bboo_foo','ee_bbbbee_fffee','aas_baa_ffaa_daa', 'iisss_bbbbii_ffffii_dii_mii')) 

欲分割上_,產生新的列(或新的數據幀,不真的很重要)。出現次數的數量可以與min(lengths(strsplit(df$strings, "_")))max(lengths(strsplit(df$strings, "_")))

所需的輸出進行估算:

X1     X2  X3 
1 ooss     bboo  foo 
2 ee     bbbbee fffee 
3 aas_baa    ffaa  daa 
4 iisss_bbbbii_ffffii dii  mii 

我已經試過正則表達式的大量的已經和我很絕望已經...

+0

'do.call( 'rbind',strsplit(as.character(DF $字符串),「_(= [AZ] + $)| _(= [ az] + _ [az] + $)',perl = TRUE))' – rawr

回答

3

我已經假定了「蠻力」stringi版本。由於OP決定添加色彩評論,所以接受的答案和這一個之間的比較(我刪除了評論中的錯誤,我的答案比「更少但仍然是額外的答案」更快,如果這種情況對於人們來說很重要):??

library(stringi) 
library(magrittr) 
library(purrr) 
library(gsubfn) 
library(ggplot2) 
library(microbenchmark) 

df <- data.frame(a=1:4, 
       strings=c('ooss_bboo_foo', 
          'ee_bbbbee_fffee', 
          'aas_baa_ffaa_daa', 
          'iisss_bbbbii_ffffii_dii_mii')) 

str_split_right_fixed <- function(str, pat, n) { 
    stri_reverse(df$strings) %>% 
    stri_split_fixed(pat, n) %>% 
    map_df(function(x) { 
     data.frame(rbind(rev(stri_reverse(x))), stringsAsFactors=FALSE) 
    }) 
} 

gsubfn_split_fixed_right <- function(str, pat, n) { 
    pat <- paste(rep("(.*)", n), collapse = pat) 
    read.pattern(text = as.character(str), pattern = pat) 
} 

tab_split_fixed_right <- function(str, pat, n) { 
    repl <- paste(paste0("\\", 1:n), collapse = ",") 
    read.table(text = sub(pat, repl, str), sep = ",") 
} 

microbenchmark(str=str_split_right_fixed(df$strings, "_", 3), 
       gsb=gsubfn_split_fixed_right(df$strings, "_", 3), 
       tab=tab_split_fixed_right(df$strings, "_", 3), 
       times=1000) -> mb 

autoplot(mb) 

enter image description here

5

這裏有一對夫婦可能的解決方案:

1)read.patternread.pattern在gsubfn包中可以直接生成數據幀結果。沒有使用其他軟件包。它使用一個特別簡單的正則表達式。

首先我們創建模式,pat。例如,如果k3那麼pat"(.*)_(.*)_(.*)"。然後,只需運行read.pattern以產生所得data.frame:

library(gsubfn) 

strings <- as.character(df$strings) # ensure it's character, not factor 
k <- min(lengths(strsplit(strings, "_"))) # from question 

pat <- paste(rep("(.*)", k), collapse = "_") 
read.pattern(text = strings, pattern = pat, as.is = TRUE) 

,並提供:

    V1  V2 V3 
1    ooss bboo foo 
2     ee bbbbee fffee 
3    aas_baa ffaa daa 
4 iisss_bbbbii_ffffii dii mii 

2)子/函數read.table。相對於先前的解決方案,此解決方案涉及額外的步驟(sub/repl部分);但是,它根本不使用任何軟件包。它使用上面的strings,kpat。在k等於3的情況下,repl的值將是"\\1,\\2,\\3"

repl <- paste(paste0("\\", 1:k), collapse = ",") 
read.table(text = sub(pat, repl, strings), sep = ",", as.is = TRUE) 

給出相同的結果。 ","的兩個實例可以替換爲數據中找不到的任何字符。

注意:在上面的解決方案中,我們使用as.is = TRUE來製作輸出列字符,但如果factor是OK,則可以省略此參數。

+0

您是否介意闡述爲什麼它從最後而不是從一開始分裂?是'pattern'還是'read.pattern'中的技巧? –

+1

正則表達式是貪婪的,所以第一個'。*'將盡其所能。這總是如此,不僅僅是在'read.pattern'中。 –

+1

關鍵字是* backtracing * :) –