Không phải là giải pháp đơn giản nhất để xây dựng một data.frame mới bằng cách kết hợp hai bộ cột? Điều này có thể được thực hiện mà không cần reshape
:
r> x <- data.frame(ID=1:4, Date=as.POSIXct(c('2014-01-01','2014-01-01','2014-01-01','2014-01-01')), Balance=c(10000,50000,30000,5000), Date2=as.POSIXct(c('2014-01-02','2014-01-02','2014-01-02','2014-01-02')), Balance2=c(5000,30000,15000,3500));
r> y <- data.frame(ID=c(x$ID,x$ID), Date=c(x$Date,x$Date2), Balance=c(x$Balance,x$Balance2));
r> y;
ID Date Balance
1 1 2014-01-01 10000
2 2 2014-01-01 50000
3 3 2014-01-01 30000
4 4 2014-01-01 5000
5 1 2014-01-02 5000
6 2 2014-01-02 30000
7 3 2014-01-02 15000
8 4 2014-01-02 3500
Bạn có thể cho tôi biết nếu điều này hoạt động tốt cho dữ liệu của bạn không?
Đối với sắp xếp:
r> z <- y[order(y$ID,y$Date),]; rownames(z) <- 1:nrow(z);
r> z;
ID Date Balance
1 1 2014-01-01 10000
2 1 2014-01-02 5000
3 2 2014-01-01 50000
4 2 2014-01-02 30000
5 3 2014-01-01 30000
6 3 2014-01-02 15000
7 4 2014-01-01 5000
8 4 2014-01-02 3500
Edit: Xét bạn có rất nhiều cột, tay gọi c()
trên mỗi ngày tương ứng và Cân bằng cột là không thực tế. Tuy nhiên, sau khi chơi một chút, tôi nhận ra rằng bạn có thể kết hợp các hàm names()
, grep()
, do.call()
và c()
để tự động trích xuất và kết hợp dữ liệu của bạn theo cách bạn muốn. Bạn cũng sẽ cần unname()
để xóa các tên phần tử không mong muốn và replicate()
để nhân rộng cột ID một số lần đủ.
Trước tiên, tôi đã tìm ra cách tạo dữ liệu đầu vào ngẫu nhiên.khung để thử nghiệm:
r> randDate <- function() as.Date('2014-01-01')+as.integer(runif(1,max=30));
r> randBalance <- function() 5000+as.integer(runif(1,max=18))*5000;
r> n <- 700;
r> x <- setNames(do.call(data.frame, c(list(1:4), replicate(n, list(do.call(c, replicate(4, randDate(), simplify=F)), do.call(c, replicate(4, randBalance(), simplify=F))), simplify=F))), c('ID', sapply(1:n, function(x) c(paste0('Date',x), paste0('Balance',x)))));
r> x;
ID Date1 Balance1 Date2 Balance2 Date3 Balance3 ... Balance698 Date699 Balance699 Date700 Balance700
1 1 2014-01-29 10000 2014-01-08 50000 2014-01-05 40000 ... 30000 2014-01-23 35000 2014-01-08 45000
2 2 2014-01-30 65000 2014-01-15 10000 2014-01-11 45000 ... 75000 2014-01-29 25000 2014-01-04 50000
3 3 2014-01-11 75000 2014-01-14 70000 2014-01-24 45000 ... 50000 2014-01-02 10000 2014-01-01 50000
4 4 2014-01-11 25000 2014-01-11 20000 2014-01-24 20000 ... 50000 2014-01-08 70000 2014-01-11 75000
Bây giờ, bạn có thể đạt được định hình lại mong muốn bằng cách sử dụng sau đây:
r> y <- data.frame(ID=do.call(c, replicate((ncol(x)-1)/2, x$ID, simplify=F)), Date=unname(do.call(c, x[,grep('^Date[0-9]+$', names(x))])), Balance=unname(do.call(c, x[,grep('^Balance[0-9]+$', names(x))])));
r> y;
ID Date Balance
1 1 2014-01-29 10000
2 2 2014-01-30 65000
3 3 2014-01-11 75000
4 4 2014-01-11 25000
5 1 2014-01-08 50000
6 2 2014-01-15 10000
...
2795 3 2014-01-02 10000
2796 4 2014-01-08 70000
2797 1 2014-01-08 45000
2798 2 2014-01-04 50000
2799 3 2014-01-01 50000
2800 4 2014-01-11 75000
Và đối với trật tự:
r> z <- y[order(y$ID,y$Date),]; rownames(z) <- 1:nrow(z);
r> z;
ID Date Balance
1 1 2014-01-01 55000
2 1 2014-01-01 20000
3 1 2014-01-01 15000
4 1 2014-01-01 75000
5 1 2014-01-01 40000
6 1 2014-01-01 85000
...
2795 4 2014-01-30 15000
2796 4 2014-01-30 65000
2797 4 2014-01-30 5000
2798 4 2014-01-30 70000
2799 4 2014-01-30 35000
2800 4 2014-01-30 30000
Mã này chạy về cơ bản ngay lập tức. Chìa khóa cho tốc độ là nó trích xuất từng cột đầu vào cho một cột đầu ra mục tiêu cùng lúc bằng cách subscripting data.frame (ví dụ: x[,grep('^Date[0-9]+$', names(x))]
cho tất cả các cột Date) và chạy tất cả chúng thông qua một cuộc gọi đến c()
qua một cuộc gọi đến do.call
, bỏ qua lớp data.frame của đối số và chỉ coi nó là danh sách cơ bản. Kết quả cuối cùng là bạn nhận được một vector c()
-kết hợp của cột đầu ra theo một biểu mẫu là gần như sẵn sàng để đính kèm vào tệp dữ liệu đầu ra (bạn chỉ cần xóa các tên phần tử không mong muốn bằng cách sử dụng unname()
). Bạn cần thực hiện việc này cho cột Ngày và Cột cân bằng một cách độc lập (cột Số dư được lập chỉ mục qua x[,grep('^Balance[0-9]+$', names(x))]
) và gộp chúng lại với nhau trong một cuộc gọi xây dựng data.frame mới. Phần khác của câu đố là sao chép cột ID đầu vào đủ số lần ((ncol(x)-1)/2
) để tạo cột ID đầu ra chính xác tương ứng với vectơ đầu ra ngày và số dư.
Giải pháp này hoàn toàn được vector hóa, không có vòng lặp rõ ràng hoặc ẩn. Ngoài ra, nó chỉ sử dụng chức năng R tích hợp; nó không yêu cầu sự phụ thuộc vào bất kỳ gói bổ sung nào. Tôi luôn cố gắng tránh sử dụng các gói phần mềm bổ sung, có xu hướng thêm những khó khăn phức tạp và bảo trì sau này, vì chiều rộng kiến thức cần thiết để hiểu được mã tăng lên.
tôi có thể 't bình luận về vấn đề cụ thể của bạn nhưng tôi thúc giục bạn chuyển sang 'reshape2', đi kèm với một API được cải thiện rất nhiều, và được thực hiện trong C++ đi kèm với những cải tiến hiệu năng tiềm năng đáng kể. –
@RobertLuyt, xem chỉnh sửa của tôi. Hãy cho tôi biết nếu nó làm việc cho bạn. – bgoldst