2015-08-08 3 views
1

У меня есть data.frame так:Форсирование ddply

n = 50 
df = data.frame(group=sample(1:as.integer(n/2),n,replace=T), 
       x = runif(n), 
       y = runif(n), 
       z = runif(n)) 
df = df[with(df,order(group)),] 

Что мне нужно сделать, для каждого уникального значения group, чтобы произвести сегменты, то есть, где производятся новые столбцы, xend, yend и zend, которые являются значениями x, y, z значений предыдущей точки в этой группе. Для последнего значения в группе концы берутся как первая точка в группе.

Я могу сделать это следующим образом:

res = ddply(df,"group",function(d){ 
    ixc = c("x","y","z") 
    dfE = d[,ixc] 
    dfE = rbind(dfE[nrow(dfE),],dfE[1:(nrow(dfE)-1),]) 
    colnames(dfE) = paste0(ixc,"end") 
    cbind(d,dfE) 
}) 
print(head(res)) 

Это тривиально, когда n мала, однако, когда n становится большой, то время для выполнения выше становится существенным, есть более быстрый способ сделайте это, возможно, используя data.table?

ответ

4

Вы можете сделать это с помощью функции shift от data.table. Примером xend:

library(data.table) #v1.9.5 
setDT(df)[, xend := shift(x, 1L, fill=x[.N], type="lag"), by="group"] 

Для всех столбцов:

setDT(df)[, c("xend","yend","zend") := .(shift(x, 1L, fill=x[.N], type="lag"), 
             shift(y, 1L, fill=y[.N], type="lag"), 
             shift(z, 1L, fill=z[.N], type="lag")), 
      by="group"] 

это дает:

> head(df) 
    group   x   y   z  xend  yend  zend 
1:  1 0.56725304 0.7539735 0.20542455 0.71538606 0.3864990 0.01586889 
2:  1 0.64251519 0.1255183 0.93371528 0.56725304 0.7539735 0.20542455 
3:  1 0.14182485 0.7351444 0.89199415 0.64251519 0.1255183 0.93371528 
4:  1 0.06613097 0.7625182 0.92669617 0.14182485 0.7351444 0.89199415 
5:  1 0.71538606 0.3864990 0.01586889 0.06613097 0.7625182 0.92669617 
6:  4 0.27188921 0.5496977 0.09282217 0.27188921 0.5496977 0.09282217 

Другой подход, предложенный @akrun в комментариях:

setDT(df)[, c("xend","yend","zend") := lapply(.SD, function(x) shift(x, fill=x[.N])), 
      by="group"] 

Хотя этот подход требует меньшего набора текста и дает большую гибкость в отношении включения переменных, он также значительно медленнее.


В вопросе, вы заявили:

Для последнего значения в группе, концы принимаются в качестве первой точки в группе.

Однако в соответствии с желаемым поведением, как вы описали, для последнего значения в группе используется предыдущее значение в группе. Я предположил, что вы имеете в виду:

Для первого значения в группе, в качестве последней точки .


Примечание: Я использовал development version of data.table для этого.


Б данные:

set.seed(1) 
n = 1e5 
df = data.frame(group=sample(1:as.integer(n/2),n,replace=T), 
       x = runif(n), 
       y = runif(n), 
       z = runif(n)) 
df = df[with(df,order(group)),] 
+0

Какую версию data.table вы используете, шахта версия 1.9.2, и она не содержит какой-либо функции «сдвига». –

+0

Ошибка в '.data.table' (setDT (df),,': = '(xend, shift (x, 1L, fill = x [.N],: не удалось найти функцию« shift » –

+0

Да, Я разработал это, версия 1.9.5 –

Смежные вопросы