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

例如,如果我有这个:

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
574218 次浏览

使用 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

使用 NAs 及其删除的一些例子适用于

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

用于插入分隔符:

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

我们可以使用 面团:

df$combField <- paste0(df$x, df$y)

如果不希望在连接的字段中引入任何填充空间。如果您计划将组合字段用作表示两个字段组合的唯一 id,那么这将更加有用。

使用 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

正如 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)

而不是

  • 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 软件包于2020-04-10创作(v0.3.0)

str_c文档中的附加说明

与大多数其他 R 函数一样,缺失的值具有“传染性”: 每当一个缺失的值与另一个字符串组合在一起时,结果总是会丢失。使用 str_replace_na()NA转换为 "NA"

还有其他很好的答案,但是如果您不知道列名或者事先要连接的列数,下面的答案很有用。

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 = ""))

我还想提出一种连接大量/未知数量的列的方法。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