7

我有一个 df ( day.df) 列vial,我试图将其拆分为四个新列。新列将是treatment gender line block. day.df数据框还具有将保留的列& responseexplanatory

所以day.df目前看起来像这样(31000 行中的前 4 行):

    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.
  • 第四个也是最后一个字符是blockand 范围从1-4
  • 这 ”。” 需要丢弃

因此,新的day.df看起来像这样(我使用四个“随机”行来说明每个新列中的变化):

        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 时出现问题,因为那里有两个字符,例如(对于vialis的行Af20.2)。

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

应该读作:

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



所以我需要帮助解决的步骤是:

  1. 克服line超过9时字符串部分的问题。
  2. 将拆分字符串的列表添加到day.df所需的四个列中的数据框中
4

3 回答 3

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中。

编辑 @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")
于 2013-07-05T12:06:07.433 回答
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=TRUEday.df$vial是字符,但如果它factor在您的数据框中,则替换day.df$Vialas.character(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

结果和以前一样。

更新:添加了第二种方法。

更新:一些简化。

于 2013-07-05T12:14:00.050 回答
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)

数字部分总是在正好两个符号之后开始,不管数字的数量。我们提取该部分,并在第一行取小数点前的数字,在第二行取小数点后的数字。提取治疗和性别很简单。

于 2013-07-05T12:22:22.090 回答