2015-05-14 19 views
14

Khung dữ liệu của tôi chứa đầu ra của một cuộc khảo sát với một loại câu hỏi được chọn. Một số ô có nhiều giá trị.Cột danh sách phẳng trong khung dữ liệu có cột ID

df <- data.frame(a=1:3,b=I(list(1,1:2,1:3))) 
df 
    a  b 
1 1  1 
2 2 1, 2 
3 3 1, 2, 3 

Tôi muốn flatten ra danh sách để có được kết quả như sau:

df 
    a  b 
1 1  1 
2 2  1 
3 2  2 
4 3  1 
5 3  2 
6 3  3 

nên dễ nhưng bằng cách nào đó tôi không thể tìm thấy thuật ngữ tìm kiếm. cảm ơn.

Trả lời

16

Bạn chỉ có thể sử dụng unnest từ "tidyr":

library(tidyr) 
unnest(df, b) 
# a b 
# 1 1 1 
# 2 2 1 
# 3 2 2 
# 4 3 1 
# 5 3 2 
# 6 3 3 
+0

cảm ơn bạn! hoàn hảo, tôi đã nhìn vào tidyr nhưng không tìm thấy trường hợp cụ thể này – mloudon

+0

OP nói rằng nó phải dễ dàng, và bạn đã chứng minh rằng nó thật sự là dễ dàng! Công việc tốt đẹp! –

7

Sử dụng base R, một lựa chọn là stack sau khi đặt tên cho các list yếu tố của cột 'b' với điều đó trong những yếu tố của 'a'. Chúng tôi có thể sử dụng setNames để thay đổi tên.

stack(setNames(df$b, df$a)) 

Hoặc tùy chọn khác sẽ được sử dụng unstack để tự động đặt tên cho nguyên tố danh sách 'b' với 'a' yếu tố và sau đó làm stack để có được một sản lượng data.frame.

stack(unstack(df, b~a)) 

Hoặc chúng ta có thể sử dụng một chức năng thuận tiện listCol_l từ splitstackshape để chuyển đổi list-data.frame.

library(splitstackshape) 
listCol_l(df, 'b') 
+2

Công việc tuyệt vời. Tôi luôn thích nhìn thấy các giải pháp cơ sở đơn giản, thanh lịch. –

4

Dưới đây là một cách, với data.table:

require(data.table) 
data.table(df)[,as.integer(unlist(b)),by=a] 

Nếu b được lưu trữ một cách nhất quán, as.integer có thể được bỏ qua. Bạn có thể kiểm tra với

unique(sapply(df$b,class)) 
# [1] "numeric" "integer" 
+3

'df $ b [1] <- danh sách (1L)' chúng ta quá thủ công và không thực tế nếu OP có nhiều mục như vậy. Tôi nghĩ rằng một cái gì đó như, 'data.table (df) [, as.integer (unlist (b)), bởi = a]' nên làm –

+0

@DavidArenburg Yeah, hoặc nhập dữ liệu vào R "đúng" (theo nghĩa của lưu trữ như số nguyên lên phía trước). Tôi sẽ chuyển sang những gì bạn đã viết. – Frank

3

Đây là một giải pháp cơ sở khác, ít thanh lịch hơn so với bất kỳ giải pháp nào khác được đăng cho đến nay. Đăng bài vì lợi ích của sự hoàn chỉnh, mặc dù cá nhân tôi muốn giới thiệu giải pháp cơ sở của akrun.

with(df, cbind(a = rep(a, sapply(b, length)), b = do.call(c, b))) 

này xây dựng cột đầu tiên là các yếu tố của a, trong đó mỗi được lặp lại để phù hợp với chiều dài của mục danh sách tương ứng từ b. Cột thứ hai là b "được làm phẳng" bằng cách sử dụng do.call() với c().

Như Ananda Mahto đã nêu trong nhận xét, sapply(b, length) có thể được thay thế bằng lengths(b) trong phiên bản mới nhất của R (3.2, nếu tôi không nhầm).

+3

Trong phiên bản mới nhất của R, bạn có thể hoán đổi 'sapply (b, length)' với 'lengths (b)'. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto: Thật tuyệt vời, cảm ơn những người đứng đầu! –

+0

để lấy lại data.frame, bạn nên sử dụng tốt hơn: 'với (df, data.frame (a = rep (a, độ dài (b)), b = unlist (b)))' – Jaap

Các vấn đề liên quan