R 将多列粘贴在一起
我在一个数据框中有一组列,我想将它们粘贴在一起(以“-”分隔),如下所示:R 将多列粘贴在一起,r,paste,r-faq,purrr,R,Paste,R Faq,Purrr,我在一个数据框中有一组列,我想将它们粘贴在一起(以“-”分隔),如下所示: data <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i')) i.e. a b c d 1 a d g
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
i.e.
a b c d
1 a d g
2 b e h
3 c f i
do.call(sprintf, c(d[cols], '%s-%s-%s'))
我通常可以通过以下方式来实现:
within(data, x <- paste(b,c,d,sep='-'))
in(data,x#您的起始数据.)。。
数据#您的起始数据。。
数据<代码>库(plyr)
ldply(应用)数据,1,功能(x)数据帧(
x=粘贴(x[2:4],sep=“”,collapse=“-”))
#x
#1 a-d-g
#2b-e-h
#3c-f-i
#仅使用名称的矢量:
ldply(应用)数据,1,功能(x)数据帧(
x=粘贴(x[c('b','c','d')],sep=“”,collapse=“-”))
#或者同等地:
mynames库(plyr)
ldply(应用)数据,1,功能(x)数据帧(
x=粘贴(x[2:4],sep=“”,collapse=“-”))
#x
#1 a-d-g
#2b-e-h
#3c-f-i
#仅使用名称的矢量:
ldply(应用)数据,1,功能(x)数据帧(
x=粘贴(x[c('b','c','d')],sep=“”,collapse=“-”))
#或者同等地:
mynames我将构建一个新的data.frame:
d <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i'))
cols <- c( 'b' , 'c' , 'd' )
data.frame(a = d[, 'a'], x = do.call(paste, c(d[ , cols], list(sep = '-'))))
d我要构建一个新的data.frame:
d <- data.frame('a' = 1:3, 'b' = c('a','b','c'), 'c' = c('d', 'e', 'f'), 'd' = c('g', 'h', 'i'))
cols <- c( 'b' , 'c' , 'd' )
data.frame(a = d[, 'a'], x = do.call(paste, c(d[ , cols], list(sep = '-'))))
d作为上的一个变量,定义了数据
,并在cols
cols <- c("b", "c", "d")
给
> data
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
作为上的一个变体,使用已定义的数据
,以及在cols
cols <- c("b", "c", "d")
给
> data
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
使用tidyr
包,这可以在一个函数调用中轻松处理
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
tidyr::unite_(data, paste(colnames(data)[-1], collapse="_"), colnames(data)[-1])
a b_c_d
1 1 a_d_g
2 2 b_e_h
3 3 c_f_i
使用tidyr
包,这可以在一个函数调用中轻松处理
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
tidyr::unite_(data, paste(colnames(data)[-1], collapse="_"), colnames(data)[-1])
a b_c_d
1 1 a_d_g
2 2 b_e_h
3 3 c_f_i
只需使用Reduce
添加额外的解决方案,这可能比do慢。call
但可能比apply
要好,因为它将避免矩阵的转换。此外,对于循环,我们可以使用setdiff
来删除不需要的列
cols <- c('b','c','d')
data$x <- Reduce(function(...) paste(..., sep = "-"), data[cols])
data[setdiff(names(data), cols)]
# a x
# 1 1 a-d-g
# 2 2 b-e-h
# 3 3 c-f-i
另一个选项是使用.SDcols
而不是中的mget
setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD), .SDcols = cols]
只需使用Reduce
添加额外的解决方案,这可能比do慢。call
但可能比apply
要好,因为它将避免矩阵的转换。此外,对于循环,我们可以使用setdiff
来删除不需要的列
cols <- c('b','c','d')
data$x <- Reduce(function(...) paste(..., sep = "-"), data[cols])
data[setdiff(names(data), cols)]
# a x
# 1 1 a-d-g
# 2 2 b-e-h
# 3 3 c-f-i
另一个选项是使用.SDcols
而不是中的mget
setDT(data)[, x := Reduce(function(...) paste(..., sep = "-"), .SD), .SDcols = cols]
我对Anthony Damico、Brian Diggs和data_steve的答案在一个小样本tbl_df
上进行了基准测试,得到了以下结果
> data <- data.frame('a' = 1:3,
+ 'b' = c('a','b','c'),
+ 'c' = c('d', 'e', 'f'),
+ 'd' = c('g', 'h', 'i'))
> data <- tbl_df(data)
> cols <- c("b", "c", "d")
> microbenchmark(
+ do.call(paste, c(data[cols], sep="-")),
+ apply( data[ , cols ] , 1 , paste , collapse = "-" ),
+ tidyr::unite_(data, "x", cols, sep="-")$x,
+ times=1000
+ )
Unit: microseconds
expr min lq mean median uq max neval
do.call(paste, c(data[cols], sep = "-")) 65.248 78.380 93.90888 86.177 99.3090 436.220 1000
apply(data[, cols], 1, paste, collapse = "-") 223.239 263.044 313.11977 289.514 338.5520 743.583 1000
tidyr::unite_(data, "x", cols, sep = "-")$x 376.716 448.120 556.65424 501.877 606.9315 11537.846 1000
我对Anthony Damico、Brian Diggs和data_steve的答案在一个小样本tbl_df
上进行了基准测试,得到了以下结果
> data <- data.frame('a' = 1:3,
+ 'b' = c('a','b','c'),
+ 'c' = c('d', 'e', 'f'),
+ 'd' = c('g', 'h', 'i'))
> data <- tbl_df(data)
> cols <- c("b", "c", "d")
> microbenchmark(
+ do.call(paste, c(data[cols], sep="-")),
+ apply( data[ , cols ] , 1 , paste , collapse = "-" ),
+ tidyr::unite_(data, "x", cols, sep="-")$x,
+ times=1000
+ )
Unit: microseconds
expr min lq mean median uq max neval
do.call(paste, c(data[cols], sep = "-")) 65.248 78.380 93.90888 86.177 99.3090 436.220 1000
apply(data[, cols], 1, paste, collapse = "-") 223.239 263.044 313.11977 289.514 338.5520 743.583 1000
tidyr::unite_(data, "x", cols, sep = "-")$x 376.716 448.120 556.65424 501.877 606.9315 11537.846 1000
在我看来,sprintf
-函数也应该在这些答案中占有一席之地。您可以如下使用sprintf
:
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
i.e.
a b c d
1 a d g
2 b e h
3 c f i
do.call(sprintf, c(d[cols], '%s-%s-%s'))
其中:
[1] "a-d-g" "b-e-h" "c-f-i"
并创建所需的数据帧:
data.frame(a = d$a, x = do.call(sprintf, c(d[cols], '%s-%s-%s')))
给予:
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
尽管sprintf
与@BrianDiggs的do.call
/paste
组合相比没有明显的优势,但当您还想填充所需字符串的某些部分或指定位数时,它尤其有用。有关几个选项,请参阅?sprintf
另一种变体是从以下位置使用pmap
:
注意:此pmap
解决方案仅在列不是因子时有效
更大数据集上的基准:
# create a larger dataset
d2 <- d[sample(1:3,1e6,TRUE),]
# benchmark
library(microbenchmark)
microbenchmark(
docp = do.call(paste, c(d2[cols], sep="-")),
appl = apply( d2[, cols ] , 1 , paste , collapse = "-" ),
tidr = tidyr::unite_(d2, "x", cols, sep="-")$x,
docs = do.call(sprintf, c(d2[cols], '%s-%s-%s')),
times=10)
使用数据:
d <- data.frame(a = 1:3, b = c('a','b','c'), c = c('d','e','f'), d = c('g','h','i'))
d在我看来,sprintf
-函数也应该在这些答案中占有一席之地。您可以使用sprintf
,如下所示:
data <- data.frame('a' = 1:3,
'b' = c('a','b','c'),
'c' = c('d', 'e', 'f'),
'd' = c('g', 'h', 'i'))
i.e.
a b c d
1 a d g
2 b e h
3 c f i
do.call(sprintf, c(d[cols], '%s-%s-%s'))
其中:
[1] "a-d-g" "b-e-h" "c-f-i"
并创建所需的数据帧:
data.frame(a = d$a, x = do.call(sprintf, c(d[cols], '%s-%s-%s')))
给予:
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
尽管sprintf
与@BrianDiggs的do.call
/paste
组合相比没有明显的优势,但当您还想填充所需字符串的某些部分或指定位数时,它尤其有用。有关几个选项,请参阅?sprintf
另一种变体是从以下位置使用pmap
:
注意:此pmap
解决方案仅在列不是因子时有效
更大数据集上的基准:
# create a larger dataset
d2 <- d[sample(1:3,1e6,TRUE),]
# benchmark
library(microbenchmark)
microbenchmark(
docp = do.call(paste, c(d2[cols], sep="-")),
appl = apply( d2[, cols ] , 1 , paste , collapse = "-" ),
tidr = tidyr::unite_(d2, "x", cols, sep="-")$x,
docs = do.call(sprintf, c(d2[cols], '%s-%s-%s')),
times=10)
使用数据:
d <- data.frame(a = 1:3, b = c('a','b','c'), c = c('d','e','f'), d = c('g','h','i'))
d这里有一种非常非常规(但快速)的方法:使用fwrite
fromdata.table
将列“粘贴”在一起,然后使用frad
将其读回。为了方便起见,我将这些步骤编写为一个名为fpaste
的函数:
fpaste <- function(dt, sep = ",") {
x <- tempfile()
fwrite(dt, file = x, sep = sep, col.names = FALSE)
fread(x, sep = "\n", header = FALSE)
}
fpaste这里有一个相当非常规(但快速)的方法:使用fwrite
fromdata.table
将列“粘贴”在一起,然后使用fread
将其读回。为了方便起见,我将这些步骤编写为一个名为fpaste
的函数:
fpaste <- function(dt, sep = ",") {
x <- tempfile()
fwrite(dt, file = x, sep = sep, col.names = FALSE)
fread(x, sep = "\n", header = FALSE)
}
fpaste我知道这是一个老问题,但我认为我应该按照提问者的建议,使用paste()函数给出简单的解决方案:
data_1<-data.frame(a=data$a,"x"=paste(data$b,data$c,data$d,sep="-"))
data_1
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
data\u 1我知道这是一个老问题,但我认为我应该按照提问者的建议,使用paste()函数给出简单的解决方案:
data_1<-data.frame(a=data$a,"x"=paste(data$b,data$c,data$d,sep="-"))
data_1
a x
1 1 a-d-g
2 2 b-e-h
3 3 c-f-i
data\u 1请注意,如果要将a
列以外的所有列粘贴在一起,您可能需要使用d[,name(d)!=“a']
,而不是d[,cols]
列。作为一种标准解决方案,我认为您可以将其缩短为cbind(a=d['a'],x=do.call(粘贴,c(d[cols],sep='-'))
,例如,在使用cbind的data.frame
方法时,避免使用逗号、list
和data.frame
。请注意,您可能希望使用d[,name(d)!=“a'”而不是d[,cols]
如果除了a
列以外的所有列都要粘贴在一起,那么我认为你可以将其缩短为cbind(a=d['a'],x=do.call(粘贴,c(d[cols],sep='-'))
,例如,避免使用逗号、list
和data.frame