将数据框中的两个或更多列合并为一个具有新名称的新列

155
例如,如果我有以下代码:
n = c(2, 3, 5) 
s = c("aa", "bb", "cc") 
b = c(TRUE, FALSE, TRUE) 
df = data.frame(n, s, b)

  n  s     b
1 2 aa  TRUE
2 3 bb FALSE
3 5 cc  TRUE

那么如何将两个列 ns 合并成一个名为 x 的新列,使其看起来像这样:
  n  s     b     x
1 2 aa  TRUE  2 aa
2 3 bb FALSE  3 bb
3 5 cc  TRUE  5 cc
9个回答

170

使用paste命令。

 df$x <- paste(df$n,df$s)
 df
#   n  s     b    x
# 1 2 aa  TRUE 2 aa
# 2 3 bb FALSE 3 bb
# 3 5 cc  TRUE 5 cc

.@thelatemail - 如何使用paste()在数据点之间添加特殊字符?对于上面的示例,x列应该具有数据为2-aa,然后是3-bb5-cc - Chetan Arvind Patil
10
这对我很有效:paste(df$n, df$s, sep="-") - Chetan Arvind Patil
4
如果列s中有缺失值,如何忽略NA?(如果df$s[2]=NA,我不想看到3 NA - Cina

54

插入分隔符的方法:

df$x <- paste(df$n, "-", df$s)

1
.@LittleBee - 这个程序在两个数据之间添加了一个空格。例如最终输出是 A - B 而不是 A-B。是否有可能去掉这个额外的空格? - Chetan Arvind Patil
9
@LittleBee - 这个对我有用:paste(df$n,df$s,sep="-") - Chetan Arvind Patil
5
请使用 paste0 代替 paste。 - Ferroao
3
这不会产生所需的输出:OP要求在元素之间有一个空格,而不是另一个分隔符(顺便说一句,更好的选择是使用sep参数...)。然而,在你之前大约4年发布的另一个答案完美地回答了这个问题。 - Cath

28

正如Uwe和UseR在评论中已经提到的那样,tidyverse格式中的通用解决方案是使用命令unite

library(tidyverse)

n = c(2, 3, 5) 
s = c("aa", "bb", "cc") 
b = c(TRUE, FALSE, TRUE) 

df = data.frame(n, s, b) %>% 
  unite(x, c(n, s), sep = " ", remove = FALSE)

2
在这个例子中,x是什么? - Levi
1
@Levi,这里的“x”表示包含合并值的新列的名称。类比于dplyr中的“mutate”:“df%>% dplyr :: mutate(x =" your operations ")”。 - Vesanen
请问为什么 mutate 是不正确的,而 unite 是正确的?我记得 Uwe 和 UseR 在评论中已经解释过了,但是我找不到那些评论——我想它们可能被删除了。谢谢! - jdcode

20

使用dplyr :: mutate

library(dplyr)
df <- mutate(df, x = paste(n, s)) 

df 
> df
  n  s     b    x
1 2 aa  TRUE 2 aa
2 3 bb FALSE 3 bb
3 5 cc  TRUE 5 cc

2
不,就像之前的回答一样,你正在使用 paste,而不是 mutate - zx8754
我原以为我正在展示如何将列作为dplyr :: mutate()的一部分进行组合。抱歉,只是想要帮忙 - 我不会再污染这个网站并且会避免未来的发帖。 - sbha
抱歉,如果听起来有点粗鲁。OP的问题并不是通过使用mutate解决的,问题不在于如何使用dplyr,而在于如何组合列值。我只是指出他们需要使用paste而不是mutate。如果我们想展示dplyr的正确方式,可以使用函数unite - zx8754
@zx8754,为什么 mutate 是不正确的,但 unite 是正确的?你分享的答案引用了 Uwe 和 UseR 的评论,但看起来这些评论已被删除。 - jdcode

16

使用apply函数进行NA值处理的示例:

n = c(2, NA, NA) 
s = c("aa", "bb", NA) 
b = c(TRUE, FALSE, NA) 
c = c(2, 3, 5) 
d = c("aa", NA, "cc") 
e = c(TRUE, NA, TRUE) 
df = data.frame(n, s, b, c, d, e)

paste_noNA <- function(x,sep=", ") {
gsub(", " ,sep, toString(x[!is.na(x) & x!="" & x!="NA"] ) ) }

sep=" "
df$x <- apply( df[ , c(1:6) ] , 1 , paste_noNA , sep=sep)
df

@Ferroao 谢谢,你救了我的命。请将 paste_noNA 函数移动到 df$x <-apply 之前。 - malajisi

14
我们可以使用paste0:
df$combField <- paste0(df$x, df$y)

如果您不希望在连接字段中引入任何填充空格,则可以使用此选项。如果您计划将组合字段用作表示两个字段组合的唯一标识符,则此选项更加有用。


8

替代默认的空格进行字符串拼接,可以使用以下三种方法之一:

  • paste (默认使用空格),
  • paste0 (将缺失值NA转换为字符型),或者
  • unite(限制为2列和1个分隔符)。

我建议一个与paste0同样灵活但更加小心处理NA的替代方法:stringr::str_c

library(tidyverse)

# check the missing value!!
df <- tibble(
  n = c(2, 2, 8),
  s = c("aa", "aa", NA_character_),
  b = c(TRUE, FALSE, TRUE)
)

df %>% 
  mutate(
    paste = paste(n,"-",s,".",b),
    paste0 = paste0(n,"-",s,".",b),
    str_c = str_c(n,"-",s,".",b)
  ) %>% 

  # convert missing value to ""
  mutate(
    s_2=str_replace_na(s,replacement = "")
  ) %>% 
  mutate(
    str_c_2 = str_c(n,"-",s_2,".",b)
  )
#> # A tibble: 3 x 8
#>       n s     b     paste          paste0     str_c      s_2   str_c_2   
#>   <dbl> <chr> <lgl> <chr>          <chr>      <chr>      <chr> <chr>     
#> 1     2 aa    TRUE  2 - aa . TRUE  2-aa.TRUE  2-aa.TRUE  "aa"  2-aa.TRUE 
#> 2     2 aa    FALSE 2 - aa . FALSE 2-aa.FALSE 2-aa.FALSE "aa"  2-aa.FALSE
#> 3     8 <NA>  TRUE  8 - NA . TRUE  8-NA.TRUE  <NA>       ""    8-.TRUE

这段内容是使用 reprex工具包 (v0.3.0) 创建于2020年04月10日。

str_c的文档中有额外的注释:

和大部分的R函数一样,缺失值是“传染性”的:只要其中一个字符串为缺失值,结果将总是缺失值。使用 str_replace_na() NA 转换为"NA"


1
paste0(n,"-",s,".",b)str_c(n,"-",s,".",b) 是完全相同的,它们都使用默认分隔符为空字符串 ''。我也不知道为什么 paste 是“整洁”的,你是说你不喜欢空格吗? - Axeman
paste0str_c并不完全相同。请查看以下链接:(1) https://www.rdocumentation.org/packages/stringr/versions/1.3.1/topics/str_c (2) https://dev59.com/86_la4cB1Zd3GeqPuYqs#53118273 - avallecam
啊,我明白了!谢谢!说明它们的不同之处将是这个答案的一个很好的补充(str_c文档也可以更加明确!)。 - Axeman
@Axeman 谢谢您的建议。我已经简化了答案,并在问题上添加了额外的注释。 - avallecam

6

还有其他很好的答案,但在你不知道要连接的列名或列数的情况下,以下方法是有用的。

df = data.frame(x = letters[1:5], y = letters[6:10], z = letters[11:15])
colNames = colnames(df) # could be any number of column names here
df$newColumn = apply(df[, colNames, drop = F], MARGIN = 1, FUN = function(i) paste(i, collapse = ""))

1
我想提出一种方法来连接大量/未知数量的列。Ben Ernest 提出的解决方案在大型数据集上可能会非常缓慢。
下面是我的建议解决方案:
# setup data.frame - Making it large for the time benchmarking
n = rep(c(2, 3, 5), 1000000)
s = rep(c("aa", "bb", "cc"), 1000000)
b = rep(c(TRUE, FALSE, TRUE), 1000000) 
df = data.frame(n, s, b)

# The proposed solution:
colNames = c("n", "s") # could be any number of column names here
df$x <- do.call(paste0, c(df[,colNames], sep=" "))

# running system.time on this yields:
# user  system elapsed 
# 1.861   0.005   1.865 

# compare with alternative method:
df$x <- apply(df[, colNames, drop = F], MARGIN = 1, 
                         FUN = function(i) paste(i, collapse = ""))
# running system.time on this yields:
# user  system elapsed 
#  16.127   0.147  16.304

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接