Kết hợp hai hoặc nhiều cột trong khung dữ liệu thành một cột mới với tên mới


104

Ví dụ nếu tôi có cái này:

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

Sau đó, làm cách nào để kết hợp hai cột nsthành một cột mới có tên xnhư sau:

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

Câu trả lời:


126

Sử dụng 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 - Cách thêm ký tự đặc biệt giữa các điểm dữ liệu bằng cách sử dụng paste()? Ví dụ trên, xcột phải có dữ liệu là 2-aa, sau đó 3-bb5-cc.
Chetan Arvind Patil

8
. @ thelatemail - Điều này phù hợp với tôi:paste(df$n,df$s,sep="-")
Chetan Arvind Patil

2
Làm thế nào bạn có thể bỏ qua NA nếu cột scó giá trị NA? (Tôi không muốn xem 3 NAnếu df$s[2]=NA)
Cina

34

Để chèn dấu phân tách:

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

1
. @ LittleBee - Điều này thêm khoảng cách giữa hai dữ liệu. Đầu ra cuối cùng chẳng hạn như: A - Bthay vì A-B. Có thể loại bỏ không gian thừa này không?
Chetan Arvind Patil

8
. @ LittleBee - Điều này đã làm việc cho tôi:paste(df$n,df$s,sep="-")
Chetan Arvind Patil

5
sử dụng paste0 thay vì dán
Ferroao

3
Điều này sẽ không cung cấp đầu ra mong muốn: OP yêu cầu một khoảng trống ở giữa các phần tử, không phải dấu phân tách khác (nhân tiện, tốt hơn nên đặt làm sepđối số ...). Tuy nhiên, câu trả lời khác, được đăng trước gần 4 năm so với câu trả lời của bạn, hoàn toàn trả lời câu hỏi.
Cath

16

Như đã được đề cập trong phần nhận xét của Uwe và UseR, một giải pháp chung trong tidyverseđịnh dạng sẽ là sử dụng lệnh 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 là gì trong ví dụ này?
Levi

@Levi, xđại diện cho tên của cột mới chứa các giá trị được kết hợp. Hãy nghĩ về dplyr's mutate:df %>% dplyr::mutate(x = "your operations")
Vesanen

13

Áp dụng một số ví dụ với NA và việc loại bỏ chúng bằng cách sử dụng

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

2
Nếu bạn muốn sử dụng các tidyrgói để tạo lại câu trả lời mong đợi của câu hỏi ban đầu này sẽ là một one-liner: tidyr::unite(df, x, n, s, sep = " ", remove = FALSE)[, c(names(df), "x")]. Tuy nhiên, tôi không thấy lý do để làm như vậy vì df$x <- paste(df$n,df$s)nó đơn giản hơn nhiều.
Uwe

@Ferroao Chà, các câu trả lời cũng không nên quá chung chung, nếu không mọi câu hỏi sẽ chỉ có một câu trả lời khổng lồ kết hợp mọi thứ. Việc loại bỏ NA không phải là một phần trong câu hỏi đơn giản của OP, vì vậy tôi không thấy làm thế nào mà sự phức tạp thêm đó lại tăng thêm giá trị cho một pastehoặc đơn giản tidyr::unite.
avid_useR

@Ferroao Cảm ơn, bạn đã cứu mạng tôi. làm ơn di chuyển hàm paste_noNA trước khi df $ x <-apply.
malajisi

11

Sử dụng 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

1
Không, như các câu trả lời đã có, bạn đang sử dụng dán , không phải biến đổi .
zx8754

Tôi nghĩ rằng tôi đang chứng minh cách các cột có thể được kết hợp như một phần của a dplyr::mutate(). Xin lỗi, tôi chỉ cố gắng tỏ ra hữu ích thôi - Tôi sẽ không làm ô nhiễm trang web nữa và kiêng các bài đăng sau này.
sbha

Xin lỗi, nếu nó phát ra là thô lỗ. Vấn đề OP của không được giải quyết bằng cách sử dụng đột biến , câu hỏi không phải là về làm thế nào để sử dụng dplyr , nhưng làm thế nào để kết hợp các giá trị cột. Tôi chỉ đơn giản là chỉ ra rằng họ cần dán không đột biến . Nếu chúng ta muốn chứng minh dplyr đúng cách là sử dụng hàm đoàn kết .
zx8754

9

Chúng ta có thể sử dụng paste0 :

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

Nếu bạn không muốn bất kỳ khoảng cách đệm nào được đưa vào trường được nối. Điều này hữu ích hơn nếu bạn định sử dụng trường kết hợp làm id duy nhất đại diện cho sự kết hợp của hai trường.


6

Thay vì

  • paste (dấu cách mặc định),
  • paste0(buộc bao gồm NAký tự bị thiếu ) hoặc
  • unite (giới hạn ở 2 cột và 1 dấu phân tách),

Tôi muốn đề xuất một giải pháp thay thế linh hoạt paste0nhưng cẩn thận hơn với 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

Được tạo vào ngày 2020-04-10 bởi gói reprex (v0.3.0)

ghi chú thêm từ str_ctài liệu

Giống như hầu hết các hàm R khác, các giá trị bị thiếu là "lây nhiễm": bất cứ khi nào một giá trị bị thiếu được kết hợp với một chuỗi khác, kết quả sẽ luôn bị thiếu. Sử dụng str_replace_na()để chuyển đổi NAsang"NA"


1
paste0(n,"-",s,".",b)str_c(n,"-",s,".",b)hoàn toàn giống nhau, cả hai đều sử dụng dấu phân tách mặc định là chuỗi trống ''. Tôi cũng không biết tại sao lại pastelà "ngăn nắp", ý bạn là bạn không thích khoảng trống?
Axeman,

paste0str_ckhông hoàn toàn giống nhau. hãy xem các liên kết sau: (1) rdocumentation.org/packages/stringr/versions/1.3.1/topics/str_c (2) stackoverflow.com/questions/53118271/…
avallecam

Ah tôi thấy! Cảm ơn! Chúng khác nhau như thế nào sẽ là một bổ sung tốt cho câu trả lời này (và str_ctài liệu cũng có thể chi tiết hơn!).
Axeman

@Axeman cảm ơn đề xuất của bạn. Tôi đã đơn giản hóa câu trả lời và thêm một ghi chú bổ sung về vấn đề này
avallecam

2

Có những câu trả lời tuyệt vời khác, nhưng trong trường hợp bạn không biết trước tên cột hoặc số cột bạn muốn nối, thì phần sau sẽ hữu ích.

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 = ""))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.