在数据框中分隔符处拆分列

我想在数据帧中根据分隔符将一列拆分为两列,

a|b
b|c

成为

a    b
b    c

在一个数据框架内。

谢谢!

328732 次浏览
strsplit(c('a|b','b|c'),'|',fixed=TRUE)

@ Taesung Shin 是对的,但是接下来只需要一些魔法就可以把它变成 data.frame。 为了避免歧义,我加了一个“ x | y”行:

df <- data.frame(ID=11:13, FOO=c('a|b','b|c','x|y'))
foo <- data.frame(do.call('rbind', strsplit(as.character(df$FOO),'|',fixed=TRUE)))

或者,如果您想替换现有 data.frame 中的列:

within(df, FOO<-data.frame(do.call('rbind', strsplit(as.character(FOO), '|', fixed=TRUE))))

结果是:

  ID FOO.X1 FOO.X2
1 11      a      b
2 12      b      c
3 13      x      y

哈德利有一个非常优雅的解决方案,使用函数 colsplit在他的 reshape包中的数据帧内完成这项工作。

require(reshape)
> df <- data.frame(ID=11:13, FOO=c('a|b','b|c','x|y'))
> df
ID FOO
1 11 a|b
2 12 b|c
3 13 x|y
> df = transform(df, FOO = colsplit(FOO, split = "\\|", names = c('a', 'b')))
> df
ID FOO.a FOO.b
1 11     a     b
2 12     b     c
3 13     x     y

正好碰到这个问题,因为它是在 最近关于 SO 的一个问题链接。

厚颜无耻的答案: 使用我的“ splitstackform”软件包中的 cSplit:

df <- data.frame(ID=11:13, FOO=c('a|b','b|c','x|y'))
library(splitstackshape)
cSplit(df, "FOO", "|")
#   ID FOO_1 FOO_2
# 1 11     a     b
# 2 12     b     c
# 3 13     x     y

这个特殊的函数还处理分割多个列,即使每个列有不同的分隔符:

df <- data.frame(ID=11:13,
FOO=c('a|b','b|c','x|y'),
BAR = c("A*B", "B*C", "C*D"))
cSplit(df, c("FOO", "BAR"), c("|", "*"))
#   ID FOO_1 FOO_2 BAR_1 BAR_2
# 1 11     a     b     A     B
# 2 12     b     c     B     C
# 3 13     x     y     C     D

Essentially, it's a fancy convenience wrapper for using read.table(text = some_character_vector, sep = some_sep) and binding that output to the original data.frame. In other words, another A base R approach could be:

df <- data.frame(ID=11:13, FOO=c('a|b','b|c','x|y'))
cbind(df, read.table(text = as.character(df$FOO), sep = "|"))
ID FOO V1 V2
1 11 a|b  a  b
2 12 b|c  b  c
3 13 x|y  x  y

结合@Ramnath 和@Tommy 的回答,我找到了一种方法,对于一个或多个列,以 R 为基数是可行的。

基本用法:

> df = data.frame(
+   id=1:3, foo=c('a|b','b|c','c|d'),
+   bar=c('p|q', 'r|s', 's|t'), stringsAsFactors=F)
> transform(df, test=do.call(rbind, strsplit(foo, '|', fixed=TRUE)), stringsAsFactors=F)
id foo bar test.1 test.2
1  1 a|b p|q      a      b
2  2 b|c r|s      b      c
3  3 c|d s|t      c      d

多栏:

> transform(df, lapply(list(foo,bar),
+ function(x)do.call(rbind, strsplit(x, '|', fixed=TRUE))), stringsAsFactors=F)
id foo bar X1 X2 X1.1 X2.1
1  1 a|b p|q  a  b    p    q
2  2 b|c r|s  b  c    r    s
3  3 c|d s|t  c  d    s    t

更好地命名多个拆分列:

> transform(df, lapply({l<-list(foo,bar);names(l)=c('foo','bar');l},
+                          function(x)do.call(rbind, strsplit(x, '|', fixed=TRUE))), stringsAsFactors=F)
id foo bar foo.1 foo.2 bar.1 bar.2
1  1 a|b p|q     a     b     p     q
2  2 b|c r|s     b     c     r     s
3  3 c|d s|t     c     d     s     t

最新流行的 tidyr软件包使用 separate来实现这一点。它使用正则表达式,因此您必须转义 |

df <- data.frame(ID=11:13, FOO=c('a|b', 'b|c', 'x|y'))
separate(data = df, col = FOO, into = c("left", "right"), sep = "\\|")


#   ID left right
# 1 11    a     b
# 2 12    b     c
# 3 13    x     y

不过在这种情况下,默认值足够聪明,可以正常工作(它会寻找非字母数字字符进行拆分)。

separate(data = df, col = FOO, into = c("left", "right"))