2013-07-05 32 views
7

我有一個df(day.df)與列vial我試圖分裂成四個新的列。新的列將是treatmentgenderlineblockday.df數據幀也有保留的列response & explanatory字符串拆分在R與複雜的部門

所以day.df目前看起來是這樣的(前4 31000行):

vial response explanatory 
    Xm1.1 0  4 
    Xm2.1 0  4 
    Xm3.1 0  4 
    Xm4.1 0  4 
    .  .  . 
    .  .  .   
    .  .  . 

vial列的當前內容是這樣的.. Xm1.2

  • 的第一個字符(顯示爲X)可以是XA - 這將是 treament
  • 第二個字符(示例中顯示爲m)可以是mf - 這是gender
  • 第三個字符(顯示爲1),範圍從1 - 40 - 此 是line
  • 第四個也是最後一個字符是block,範圍從1 - 4
  • 「。」需要丟棄

這樣的新day.df會是這個樣子(我用4「隨機」行說明每個新列內的變化):

 vial response explanatory treatment gender line block 
     Xm1.1 0  4   X   m  1  1 
     Am1.1 0  4   A   m  1  1 
     Xf3.2 0  4   X   f  3  2 
     Xm4.2 0  4   X   m  4  2 
     .  .  . 
     .  .  .   
     .  .  . 

我已經在網上看看如何做到這一點,這是最接近我來;我試圖分裂vial列這樣的...

> a=strsplit(day.df$vial,"") 
> a[1] "Xm1.2" 

,但有問題時,該字符串的「行」節去> 9,因爲那時兩個字符的在那裏,如(該行地方vialAf20.2 )。

> a[300] 
[[1]] 
[1] "A" "f" "2" "0" "." "2" 

應閱讀:

> a[300] 
[[1]] 
[1] "A" "f" "20" "." "2" 



所以我需要幫助解決的步驟是:

  1. 與字符串時的line部分解決這個問題超過9。
  2. 分割字符串列表添加到day.df數據框的四個必需列

回答

8

使用gsubstrsplit這樣的:

v <- c('Xm1.1','Xf3.2') 
h <- gsub('(X|A)(m|f)([0-9]{1,2})[.]([1-4])','\\1|\\2|\\3|\\4',v) 
do.call(rbind,strsplit(h,'[|]')) 

    [,1] [,2] [,3] [,4] 
[1,] "X" "m" "1" "1" 
[2,] "X" "f" "3" "2" 

的結果是一個data.frame,你可以cbind它到您的原始data.frame。

EDIT @GriffinEvo應用&測試的代碼:

a = gsub('(X|A)(m|f)([0-9]{1,2})[.]([1-4])', 
      '\\1|\\2|\\3|\\4',day.df$vial) 

do.call(rbind, strsplit(a,'[|]')) 
day.df = cbind(day.df,do.call(rbind,strsplit(a,'[|]'))) 
colnames(day.df)[4:7] = c ("treatment" , "gender" , "line" , "block") 
+0

代表[GriffinEvo](http://stackoverflow.com/users/1040035/griffinevo):應用和測試代碼:'a = gsub('(X | A)(m | f)([0- 9] {1,2})[。]([1-4])','\\ 1 | \\ 2 | \\ 3 | \\ 4',day.df $ vial)do.call(rbind, strsplit(a,'[|]'))day.df = cbind(day.df,do.call(rbind,strsplit(a,'[|]')))colnames(day.df)[4:7] = c(「治療」,「性別」,「行」,「塊」)。有關正確的格式,請參閱[評論](http://stackoverflow.com/review/suggested-edits/2449097)。 –

4

讀取數據:

Lines <- "vial response explanatory 
    Xm1.1 0  4 
    Xm2.1 0  4 
    Xm3.1 0  4 
    Xm4.1 0  4 
" 

day.df <- read.table(text = Lines, header = TRUE, as.is = TRUE) 

1)然後使用strapplyc處理它。 (我們使用as.is=TRUE,使day.df$vial是字符,但如果你的數據幀中的一個factor然後用as.character(day.df$vial)替換day.df$Vial)。這種方法確實解析只在一個很短的代碼行:

library(gsubfn)  
s <- strapplyc(day.df$vial, "(.)(.)(\\d+)[.](.)", simplify = rbind) 

# we can now cbind it to the original data frame 
colnames(s) <- c("treatment", "gender", "line", "block") 
cbind(day.df, s) 

這給:

vial response explanatory treatment gender line block 
1 Xm1.1  0   4   X  m 1  1 
2 Xm2.1  0   4   X  m 2  1 
3 Xm3.1  0   4   X  m 3  1 
4 Xm4.1  0   4   X  m 4  1 

2)這是一種不同的方法。這不使用任何軟件包和相對簡單(沒有正則表達式的話),只是涉及一個R聲明包括cbind'ing:

transform(day.df, 
treatment = substring(vial, 1, 1),  # 1st char 
gender = substring(vial, 2, 2),   # 2nd char 
line = substring(vial, 3, nchar(vial)-2), # 3rd through 2 prior to last char 
block = substring(vial, nchar(vial)))  # last char 

結果是如前。

更新:增加了第二種方法。

更新:一些簡化。

1

另一種不需要使用正則表達式的方法是將substr()與代碼的最後一部分是數字值的事實結合使用。

比方說,你的數據是這樣的:

d1 <- read.table(header=TRUE,text=" 
    vial response explanatory 
    Xm1.1 0  4 
    Xm2.1 0  4 
    Xm3.2 0  4 
    Xm44.1 0  4") 

那麼結果可以通過以下方式實現:

d1$line <- as.integer(substr(x=d1$vial,3,6)) 
d1$block <- (as.numeric(substr(x=d1$vial,3,6)) %% 1)*10 
d1$treatment <- substr(x=d1$vial,1,1) 
d1$gender <- substr(x=d1$vial,2,2) 

數字部分正好有兩個符號後總是從不論位數。我們提取該部分,並在第一行的小數點之前取數字,在第二行取小數點後的數字。提取治療和性別很簡單。