R正则表达式将字符串列拆分为多列

R regular expression to split string column into multiple columns

我在名为 PeakBoundaries 的数据框中有一列如下所示:

           chrom
 chr11:69464719-69502928
 chr7:55075808-55093954
 chr8:128739772-128762863
 chr3:169389459-169490555
 chr17:37848534-37877201
 chr19:30306758-30316875
 chr1:150496857-150678056
 chr12:69183279-69260755
 chr11:77610143-77641464
 chr8:38191804-38260814
 chr12:58135797-58156509

我想将列分开,以便列在数据框中如下所示:

chr       chrStart           chrEnd
chr11     69464719         69502928
chr7      55075808         55093954
chr8      128739772        128762863
chr3      169389459        169490555

等等

我已经尝试过正则表达式方法,但在让匹配项进入新列方面没有任何进展:

 PeakBoundaries$chrOnly <- PeakBoundaries[grep("\w+?=\:"),PeakBoundaries$chrom]

我遇到了错误: [.data.frame(PeakBoundaries, grep("\w+?=\:"), PeakBoundaries$chrom) 中的错误: 选择了未定义的列

试试这个 - 不需要正则表达式,只需要 strsplit 函数:

dat <- read.table(text="chr11:69464719-69502928
chr7:55075808-55093954
chr8:128739772-128762863
chr3:169389459-169490555
chr17:37848534-37877201
chr19:30306758-30316875
chr1:150496857-150678056
chr12:69183279-69260755
chr11:77610143-77641464
chr8:38191804-38260814
chr12:58135797-58156509", stringsAsFactors=FALSE)

dat[,2:4] <- matrix(unlist(strsplit(dat[,1],split = "\:|\-")), ncol=3, byrow=TRUE)

colnames(dat) <- c("chrom", "chr", "chrStart", "chrEnd")

# Convert last two columns from character to numeric:

dat$chrStart <- as.numeric(dat$chrStart)
dat$chrEnd <- as.numeric(dat$chrEnd)

结果

> res

                      chrom   chr  chrStart    chrEnd
1   chr11:69464719-69502928 chr11  69464719  69502928
2    chr7:55075808-55093954  chr7  55075808  55093954
3  chr8:128739772-128762863  chr8 128739772 128762863
4  chr3:169389459-169490555  chr3 169389459 169490555
5   chr17:37848534-37877201 chr17  37848534  37877201
6   chr19:30306758-30316875 chr19  30306758  30316875
7  chr1:150496857-150678056  chr1 150496857 150678056
8   chr12:69183279-69260755 chr12  69183279  69260755
9   chr11:77610143-77641464 chr11  77610143  77641464
10   chr8:38191804-38260814  chr8  38191804  38260814
11  chr12:58135797-58156509 chr12  58135797  58156509

编辑

你可以只使用现有的数据框做任何事情。将 dat[,1] 替换为 PeakBoundaries$chrom,将 dat[,2:4] 替换为 PeakBoundaries[,(ncol(PeakBoundaries)+1):(ncol(PeakBoundaries)+3)],您应该拥有它!

OP 编辑​​

好的,所以我认为我的数据集有些奇怪,但我在 Dominic 的帮助下对其进行了排序,现在是:

  PeakBoundaries <- as.data.frame(PeakBoundaries)
  PeakBoundaries <- PeakBoundaries[-1,]
  PeakBoundaries <- as.data.frame(PeakBoundaries)
  PeakBoundaries$PeakBoundaries <- 
             as.character(PeakBoundaries$PeakBoundaries)
  PeakBoundaries[,(ncol(PeakBoundaries)+1):(ncol(PeakBoundaries)+3)] <- 
             matrix(unlist(strsplit(PeakBoundaries$PeakBoundaries,
                                    split = "\:|\-")), ncol=3, byrow=TRUE)

Dominic 回答的较短版本,使插入成为一行:

dat <- data.frame(chrom = readLines(textConnection("chr11:69464719-69502928
chr7:55075808-55093954
chr8:128739772-128762863
chr3:169389459-169490555
chr17:37848534-37877201
chr19:30306758-30316875
chr1:150496857-150678056
chr12:69183279-69260755
chr11:77610143-77641464
chr8:38191804-38260814
chr12:58135797-58156509")) )

dat[, c('chr','chrStart','chrEnd')] <- t( sapply( dat$chrom, function(s) { str_split(s, '[:-]') [[1]] } ) )

dat$chrStart <- as.numeric(dat$chrStart)
dat$chrEnd <- as.numeric(dat$chrEnd)

我们可以试试

library(tidyr)
extract(dat, chrom, into=c('chr', 'chrStart', 'chrEnd'),
                 '([^:]+):([^-]+)-(.*)', convert=TRUE)
#     chr  chrStart    chrEnd
#1  chr11  69464719  69502928
#2   chr7  55075808  55093954
#3   chr8 128739772 128762863
#4   chr3 169389459 169490555
#5  chr17  37848534  37877201
#6  chr19  30306758  30316875
#7   chr1 150496857 150678056
#8  chr12  69183279  69260755
#9  chr11  77610143  77641464
#10  chr8  38191804  38260814
#11 chr12  58135797  58156509

或者使用开发版本 data.table 的更快选项。我们可以从 here

安装 v1.9.5
library(data.table) # v1.9.5+
nm1 <- c('chr', 'chrStart', 'chrEnd')
res <- setDT(tstrsplit(dat$chrom, '[:-]', type.convert=TRUE))
setnames(res, nm1)
res
#      chr  chrStart    chrEnd
# 1: chr11  69464719  69502928
# 2:  chr7  55075808  55093954
# 3:  chr8 128739772 128762863
# 4:  chr3 169389459 169490555
# 5: chr17  37848534  37877201
# 6: chr19  30306758  30316875
# 7:  chr1 150496857 150678056
# 8: chr12  69183279  69260755
# 9: chr11  77610143  77641464
#10:  chr8  38191804  38260814
#11: chr12  58135797  58156509

library(splitstackshape)
setnames(cSplit(dat, 'chrom', ':|-',fixed=FALSE,
                      type.convert=TRUE), nm1)[]

数据

dat <- structure(list(chrom = structure(c(2L, 9L, 10L, 8L, 6L, 7L, 1L, 
5L, 3L, 11L, 4L), .Label = c("chr1:150496857-150678056",
"chr11:69464719-69502928", 
"chr11:77610143-77641464", "chr12:58135797-58156509", 
"chr12:69183279-69260755", 
"chr17:37848534-37877201", "chr19:30306758-30316875",
 "chr3:169389459-169490555", 
"chr7:55075808-55093954", "chr8:128739772-128762863",
 "chr8:38191804-38260814"
 ), class = "factor")), .Names = "chrom", row.names = c(NA, -11L
 ), class = "data.frame")