Не самое простое решение построить новый data.frame путем объединения двух наборов столбцов? Это может быть сделано без 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
Можете ли вы дайте мне знать, если это хорошо работает для ваших данных?
Для сортировки:
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: Учитывая, что у вас так много столбцов, вручную вызова c()
на каждой соответствующей дате и столбце Остаток не практично. Однако, немного поиграв, я понял, что вы можете комбинировать функции names()
, grep()
, do.call()
и c()
, чтобы автоматически извлекать и комбинировать данные так, как вы хотите. Вам также понадобится unname()
для удаления нежелательных имен элементов и replicate()
для повторной тиражирования столбца ID достаточное количество раз.
Во-первых, я выяснил способ создания рандомизированных входных данных.рамка для тестирования:
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
Теперь вы можете достичь желаемого перепрофилирование, используя следующие:
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
И для заказа:
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
Этот код работает в основном мгновенно. Ключом к скорости является то, что он извлекает каждый столбец ввода для целевого выходного столбца одновременно, подписывая data.frame (например, x[,grep('^Date[0-9]+$', names(x))]
для всех столбцов Date) и запускает все из них одним вызовом до c()
посредством одного вызова до do.call
, который игнорирует класс data.frame аргумента и просто рассматривает его как базовый список, который он есть. Конечным результатом является то, что вы получаете векторный столбец c()
в форме, которая составляет , почти, готовый к подключению к выходному data.frame (вам просто нужно удалить ненужные имена элементов, используя unname()
). Вам нужно сделать это для столбцов Date и столбцов Balance независимо (столбцы баланса, индексированные через x[,grep('^Balance[0-9]+$', names(x))]
) и упаковать их вместе в новом вызове построения data.frame. Единственный другой фрагмент головоломки состоит в том, чтобы воспроизвести столбец ввода ID достаточное количество раз ((ncol(x)-1)/2
), чтобы создать правильный столбец идентификатора вывода, который соответствует выходным векторам даты и баланса.
Это решение полностью векторизовано, без явных или скрытых петель. Кроме того, он использует только встроенную функциональность R; он не требует зависимости от каких-либо дополнительных пакетов. Я всегда стараюсь избегать использования дополнительных пакетов, которые, как правило, затрудняют сложность и трудности в обслуживании, поскольку расширяется объем знаний, необходимых для понимания кода.
могу Не комментируйте вашу конкретную проблему, но я призываю вас перейти на 'reshape2', который поставляется с значительно улучшенным API и реализован на C++, который имеет потенциально значительные улучшения производительности. –
@RobertLuyt, см. Мое редактирование. Дайте мне знать, если это сработает для вас. – bgoldst