Câu hỏi Tách cột tại dấu phân cách trong khung dữ liệu [trùng lặp]


Câu hỏi này đã có câu trả lời ở đây:

Tôi muốn chia một cột thành hai trong khung dữ liệu dựa trên dấu phân tách. Ví dụ,

a|b
b|c

để trở thành

a    b
b    c

trong một khung dữ liệu.

Cảm ơn!


76
2017-08-15 18:37


gốc


Liên quan: stackoverflow.com/questions/7033187/sets-in-r-dataframe/… - Chase


Các câu trả lời:


@Taesung Shin là đúng, nhưng sau đó chỉ cần thêm một số phép thuật để biến nó thành data.frame. Tôi đã thêm dòng "x | y" để tránh sự mơ hồ:

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

Hoặc, nếu bạn muốn thay thế các cột trong data.frame hiện có:

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

Sản xuất:

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

74
2017-08-15 19:00



Bạn sẽ làm gì nếu đó là một cột trong một khung dữ liệu lớn có sẵn với 100 cột? - Jeff Erickson
câu hỏi hay. Tôi sẽ thực hiện việc chia nhỏ, biến nó thành một khung dữ liệu, đổi tên nó một cách thích hợp ( rename chức năng từ reshape gói là tiện dụng để làm điều này một cách nhanh chóng) và sau đó rbind nó với khung dữ liệu hiện có - nỗ lực thêm để chèn nó vào vị trí của cột đơn trước đó chứ không phải là cột đầu tiên hoặc cột cuối cùng ... - Ben Bolker
Tôi phiên bản cập nhật của tôi xử lý một số 100 của các cột khác quá. - Tommy
+1 Đây là giải pháp chung nhất. Nó thậm chí có thể xử lý các tình huống có số lượng giá trị khác nhau được phân tách bằng dấu '|'. Tất nhiên, người ta phải đối phó với kết quả của rbind mà có thể tái chế cho những hàng có ít nguyên tố hơn. Nhưng giải pháp khác sẽ thất bại trong trường hợp này. - Yu Shen
Hãy cẩn thận, length(strsplit('a|', '|', fixed=TRUE)) Là 1 -- như tài liệu nói: "... nhưng nếu có một kết quả phù hợp ở cuối chuỗi, đầu ra giống với kết quả đã loại bỏ." Như @YuShen nói, giải pháp này sẽ "tái chế". Đối với tôi, tôi chỉ muốn không gian trống rỗng, không tái chế. - The Red Pea


Hadley có một giải pháp rất tao nhã để làm điều này bên trong các khung dữ liệu trong reshape gói, sử dụng hàm colsplit.

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

52
2017-08-15 19:52



Có cách nào để có được điều này mà không có tên cột kết quả là "FOO.a" và "FOO.b" nhưng chỉ là "a" và "b" (đủ dễ dàng để thay đổi, nhưng chỉ tự hỏi ...)? - Amyunimus
Bạn có thể làm như sau with(df, cbind(ID, colsplit(df$FOO, pattern = "\\|", names = c('a', 'b')))). Lưu ý rằng tham số split đã được đổi tên thành pattern trong reshape2 đó là phiên bản sau của reshape gói. - Ramnath
Chỉnh sửa của tôi được ngăn chặn vào lúc này ... Tôi sẽ chỉ cập nhật câu trả lời của bạn để in df sau mỗi bài tập ... yêu cầu (định dạng lại)> 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 = chuyển đổi (df, FOO = colsplit (FOO, split = "\\ |", tên = c ('a', 'b')))> df ID FOO.a FOO.b 1 11 ab 2 12 bc 3 13 xy - The Red Pea
Ngoài ra, có cách nào để làm điều đó nếu bạn không biết số lượng cột sẽ dẫn đến kết quả không? - The Red Pea
Vấn đề nhỏ với giải pháp này. Nó chia tách các cột thành một khung dữ liệu 'lồng nhau', do đó nếu bạn cần sử dụng dữ liệu cho một ô sử dụng ggplot2, các tên cột không được nhận dạng. Tôi đã tìm thấy separate chức năng trong tidyr hữu ích hơn cho mục đích này. Xem câu trả lời bằng @Gregor - Alison Bennett


Mới nổi tiếng tidyr gói thực hiện điều này với separate. Nó sử dụng cụm từ thông dụng, do đó bạn sẽ phải thoát khỏi |

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

mặc dù trong trường hợp này các giá trị mặc định đủ thông minh để hoạt động (tìm kiếm các ký tự không phải chữ và số để chia nhỏ).

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

45
2018-02-19 17:28



Giải pháp này cực kỳ đơn giản. Cảm ơn!! - Francisco QV


Chỉ cần đi qua câu hỏi này vì nó đã được liên kết trong một câu hỏi gần đây về SO.

Shameless plug of a answer: Sử dụng cSplit từ gói "splitstackshape" của tôi:

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

Hàm đặc biệt này cũng xử lý tách nhiều cột, ngay cả khi mỗi cột có một dấu phân cách khác nhau:

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

Về cơ bản, nó là một wrapper tiện lợi ưa thích để sử dụng read.table(text = some_character_vector, sep = some_sep) và ràng buộc đầu ra đó với bản gốc data.frame. Nói cách khác, một Phương pháp R cơ bản có thể là:

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

30
2017-12-05 16:12



Tôi đặc biệt thích rằng bạn không phải xác định tên cột mà dữ liệu sẽ chuyển thành 'thành' - tospig
Đồng ý với tospig. Tôi cũng thích phương pháp bản địa đó read.table(c('a|b','c|d'), '|') có thể thực hiện thủ thuật nếu chúng ta đang tạo một data.frame mới, mặc dù SO đã nói về "trong một khung dữ liệu [hiện tại]". - The Red Pea
Nhược điểm của read.table, sep chỉ có thể là một byte và trình tách băm được hiểu là nhận xét? read.table(text=c('a#b'), sep='#') chỉ tạo ra một cột - tôi mong đợi hai cột. - The Red Pea
@ TheRedPea, trên điện thoại ngay bây giờ, nhưng bạn không thể nhận được kết quả mong muốn bằng cách chỉ định ký tự nhận xét trong read.table như ""? - A5C1D2H2I1M1N2O1R2T1
@AnandaMahto bạn hoàn toàn chính xác; điều này tạo ra 2 cột: read.table(text=c('a#b'), sep='#', comment.char = '') và đối với dấu phân tách ký tự đơn, nếu tôi chuyển c ('a ~~ b') vào gsub, tôi có thể nhận được dấu phân cách đơn byte mà tôi cần: gsub('~~','~', c('a~~b')) - The Red Pea


strsplit(c('a|b','b|c'),'|',fixed=TRUE)

6
2017-08-15 18:52





Kết hợp các câu trả lời của @Ramnath và @ Tommy cho phép tôi tìm một phương pháp làm việc trong cơ sở R cho một hoặc nhiều cột.

Sử dụng cơ bản:

> 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

Nhiều cột:

> 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

Đặt tên tốt hơn cho nhiều cột được chia nhỏ:

> 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

4
2018-02-19 17:21