2012-05-14 47 views
19

Tôi gặp khó khăn trong việc tìm ra cách chuyển đổi dữ liệu từ định dạng dài sang định dạng rộng nhất khi tôi có nhiều biến số đo tôi muốn mang theo.Chuyển đổi dữ liệu từ định dạng dài sang định dạng rộng với nhiều cột số

Ví dụ: đây là khung dữ liệu đơn giản ở định dạng dài. ID được vấn đề này, thời gian là một biến thời gian, và X và Y là phép đo làm bằng ID vào TIME:

> my.df <- data.frame(ID=rep(c("A","B","C"), 5), TIME=rep(1:5, each=3), X=1:15, Y=16:30) 
> my.df 

    ID TIME X Y 
1 A 1 1 16 
2 B 1 2 17 
3 C 1 3 18 
4 A 2 4 19 
5 B 2 5 20 
6 C 2 6 21 
7 A 3 7 22 
8 B 3 8 23 
9 C 3 9 24 
10 A 4 10 25 
11 B 4 11 26 
12 C 4 12 27 
13 A 5 13 28 
14 B 5 14 29 
15 C 5 15 30 

Nếu tôi chỉ muốn biến các giá trị của thời gian vào tiêu đề cột chứa bao gồm X, tôi biết tôi có thể sử dụng dàn diễn viên từ các gói Reshape (hoặc dcast từ reshape2):

> cast(my.df, ID ~ TIME, value="X") 
    ID 1 2 3 4 5 
1 A 1 4 7 10 13 
2 B 2 5 8 11 14 
3 C 3 6 9 12 15 

Nhưng những gì tôi thực sự muốn làm được cũng mang theo Y như là một biến đo lường, và có các tên cột phản ánh cả hai biện pháp tên biến và giá trị thời gian:

ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5 
1 A 1 4 7 10 13 16 19 22 25 28 
2 B 2 5 8 11 14 17 20 23 26 29 
3 C 3 6 9 12 15 18 21 24 27 30 

(FWIW, tôi không thực sự quan tâm nếu tất cả dấu X đầu tiên được theo sau bởi Y, hoặc nếu chúng được xen kẽ như X_1, Y_1, X_2, Y_2, v.v.)

Tôi có thể đến gần bằng cách truyền dữ liệu dài hai lần và hợp nhất kết quả, mặc dù tên cột cần một số công việc và tôi cần phải chỉnh sửa nếu tôi cần thêm biến số thứ 3 hoặc thứ 4 ngoài X và Y:

merge(
cast(my.df, ID ~ TIME, value="X"), 
cast(my.df, ID ~ TIME, value="Y"), 
by="ID", suffixes=c("_X","_Y") 
) 

Có vẻ như một số kết hợp các hàm trong định dạng lại và/hoặc plyr sẽ có thể thực hiện điều này một cách tao nhã hơn là nỗ lực của tôi, cũng như xử lý nhiều biến số đo rõ ràng hơn. Một cái gì đó như cast (my.df, ID ~ TIME, giá trị = c ("X", "Y")), không hợp lệ. Nhưng tôi đã không thể hình dung ra được.

Mọi trình hướng dẫn R có thể giúp tôi không? Cảm ơn.

Trả lời

14

Để xử lý nhiều biến số như bạn muốn, bạn cần melt dữ liệu bạn có trước khi truyền.

library("reshape2") 

dcast(melt(my.df, id.vars=c("ID", "TIME")), ID~variable+TIME) 

mang đến cho

ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5 
1 A 1 4 7 10 13 16 19 22 25 28 
2 B 2 5 8 11 14 17 20 23 26 29 
3 C 3 6 9 12 15 18 21 24 27 30 

EDIT dựa trên nhận xét:

Khung dữ liệu

num.id = 10 
num.time=10 
my.df <- data.frame(ID=rep(LETTERS[1:num.id], num.time), 
        TIME=rep(1:num.time, each=num.id), 
        X=1:(num.id*num.time), 
        Y=(num.id*num.time)+1:(2*length(1:(num.id*num.time)))) 

đưa ra một kết quả khác nhau (tất cả mục 2) vì ID/Sự kết hợp TIME không biểu thị một hàng duy nhất. Trên thực tế, có hai hàng với mỗi kết hợp ID/TIME. reshape2 giả định một giá trị duy nhất cho mỗi kết hợp có thể có của các biến và sẽ áp dụng hàm tổng hợp để tạo một biến duy nhất là có nhiều mục nhập. Đó là lý do tại sao có cảnh báo

Aggregation function missing: defaulting to length 

Bạn có thể nhận được thứ gì đó hoạt động nếu bạn thêm biến khác phá vỡ sự thừa đó.

my.df$cycle <- rep(1:2, each=num.id*num.time) 
dcast(melt(my.df, id.vars=c("cycle", "ID", "TIME")), cycle+ID~variable+TIME) 

này hoạt động vì cycle/ID/time tại xác định duy nhất một dòng trong my.df.

+0

Tôi đã cố gắng để đánh giá mà giải pháp là nhanh nhất, nhưng không tìm thấy một vấn đề với mã của bạn nếu khung dữ liệu như sau: num.id = 10 num.time = 10 my.df <- data. frame (ID = rep (LETTERS [1: num.id], num.time), TIME = rep (1: num.time, each = num.id), X = 1: (num.id * num.time), Y = (num.id * num.time) +1: (2 * chiều dài (1: (num.id * num.time)))) –

+0

Cảm ơn bạn rất nhiều. –

+0

Tuyệt vời, cảm ơn Brian. Kể từ khi diễn viên dường như đang làm việc, tôi đã không nhận ra tan chảy vẫn còn cần thiết. –

14
reshape(my.df, idvar = "ID", timevar = "TIME", direction = "wide") 

cho

ID X.1 Y.1 X.2 Y.2 X.3 Y.3 X.4 Y.4 X.5 Y.5 
1 A 1 16 4 19 7 22 10 25 13 28 
2 B 2 17 5 20 8 23 11 26 14 29 
3 C 3 18 6 21 9 24 12 27 15 30 
+0

Điều này thật tuyệt. Cảm ơn bạn! –

9

Sử dụng data.table_1.9.5, điều này có thể được thực hiện mà không có sự melt vì nó có thể xử lý nhiều value.var cột. Bạn có thể cài đặt nó từ here

library(data.table) 
dcast(setDT(my.df), ID~TIME, value.var=c('X', 'Y')) 
# ID 1_X 2_X 3_X 4_X 5_X 1_Y 2_Y 3_Y 4_Y 5_Y 
#1: A 1 4 7 10 13 16 19 22 25 28 
#2: B 2 5 8 11 14 17 20 23 26 29 
#3: C 3 6 9 12 15 18 21 24 27 30 
4

Dưới đây là một giải pháp với gói tidyr, trong đó chủ yếu đã thay thế Reshape và reshape2. Như với hai gói đó, chiến lược để lấy tập dữ liệu còn dài hơn, và sau đó rộng hơn.

library(magrittr); requireNamespace("tidyr"); requireNamespace("dplyr") 
my.df %>% 
    tidyr::gather_(key="variable", value="value", c("X", "Y")) %>% # Make it even longer. 
    dplyr::mutate(             # Create the spread key. 
    time_by_variable = paste0(variable, "_", TIME) 
) %>% 
    dplyr::select(ID, time_by_variable, value) %>%     # Retain these three. 
    tidyr::spread(key=time_by_variable, value=value)    # Spread/widen. 

Sau tidyr::gather() cuộc gọi, số liệu trung gian là:

ID TIME variable value 
1 A 1  X  1 
2 B 1  X  2 
3 C 1  X  3 
... 
28 A 5  Y 28 
29 B 5  Y 29 
30 C 5  Y 30 

Kết quả cuối cùng là:

ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5 
1 A 1 4 7 10 13 16 19 22 25 28 
2 B 2 5 8 11 14 17 20 23 26 29 
3 C 3 6 9 12 15 18 21 24 27 30 
Các vấn đề liên quan