R 将j应用于data.table中的两组i和by

R 将j应用于data.table中的两组i和by,r,data.table,R,Data.table,我有一个data.table,如下所示: dt=data.table(ID=rep(1:6,each=2),Set=c("a","b"),Value=rnorm(12)) 我想要一个data.table解决方案,其结果如下: dt.test=data.table(ID=dt[Set=="a",Value,by=ID][order(ID),ID],Value=dt[Set=="a",Value,by=ID][order(ID),Value]-dt[Set=="b",Value,by=ID][or

我有一个data.table,如下所示:

dt=data.table(ID=rep(1:6,each=2),Set=c("a","b"),Value=rnorm(12))
我想要一个data.table解决方案,其结果如下:

dt.test=data.table(ID=dt[Set=="a",Value,by=ID][order(ID),ID],Value=dt[Set=="a",Value,by=ID][order(ID),Value]-dt[Set=="b",Value,by=ID][order(ID),Value])
但是我不想为了使
而必须调用
dt
两次

任何帮助都将不胜感激。

您可以:

# reshape the data table
df.test <- dcast(data = dt, ID ~ Set, value.var = 'Value')

# create new column
df.test <- df.test[, Values := a - b][,.(ID, Values)]
#重塑数据表
df.test您可以执行以下操作:

# reshape the data table
df.test <- dcast(data = dt, ID ~ Set, value.var = 'Value')

# create new column
df.test <- df.test[, Values := a - b][,.(ID, Values)]
#重塑数据表

df.test迄今为止最快的解决方案:

dt[ dt[, .I[1], ID ]$V1][, `:=`(Set = NULL, Value = Value - dt[dt[, .I[2], ID ]$V1]$Value)][]
基准

microbenchmark::microbenchmark(
  ricardo.solution = data.table(ID=dt[Set=="a",Value,by=ID][order(ID),ID],Value=dt[Set=="a",Value,by=ID][order(ID),Value]-dt[Set=="b",Value,by=ID][order(ID),Value]),
  YOLO.solution = {df.test <- dcast(data = dt, ID ~ Set, value.var = 'Value')
                   df.test <- df.test[, Values := a - b][,.(ID, Values)]},
  this.answer = dt[ dt[, .I[1], ID ]$V1][, `:=`(Set = NULL, Value = Value - dt[dt[, .I[2], ID ]$V1]$Value)][]
)

# Unit: milliseconds
#             expr      min       lq     mean   median       uq       max neval
# ricardo.solution 5.197409 5.338703 6.024780 5.526993 5.748874 45.018507   100
#    YOLO.solution 2.617082 2.719060 3.006002 2.784585 2.948021 17.891175   100
#      this.answer 1.432812 1.479057 1.525045 1.502857 1.539461  1.896759   100
microbenchmark::microbenchmark(
ricardo.solution=data.table(ID=dt[Set==“a”,Value,by=ID][order(ID),ID],Value=dt[Set==“a”,Value,by=ID][order(ID),Value]--dt[Set==“b”,Value,by=ID][order(ID),Value]),

YOLO.solution={df.test迄今为止最快的解决方案:

dt[ dt[, .I[1], ID ]$V1][, `:=`(Set = NULL, Value = Value - dt[dt[, .I[2], ID ]$V1]$Value)][]
基准

microbenchmark::microbenchmark(
  ricardo.solution = data.table(ID=dt[Set=="a",Value,by=ID][order(ID),ID],Value=dt[Set=="a",Value,by=ID][order(ID),Value]-dt[Set=="b",Value,by=ID][order(ID),Value]),
  YOLO.solution = {df.test <- dcast(data = dt, ID ~ Set, value.var = 'Value')
                   df.test <- df.test[, Values := a - b][,.(ID, Values)]},
  this.answer = dt[ dt[, .I[1], ID ]$V1][, `:=`(Set = NULL, Value = Value - dt[dt[, .I[2], ID ]$V1]$Value)][]
)

# Unit: milliseconds
#             expr      min       lq     mean   median       uq       max neval
# ricardo.solution 5.197409 5.338703 6.024780 5.526993 5.748874 45.018507   100
#    YOLO.solution 2.617082 2.719060 3.006002 2.784585 2.948021 17.891175   100
#      this.answer 1.432812 1.479057 1.525045 1.502857 1.539461  1.896759   100
microbenchmark::microbenchmark(
ricardo.solution=data.table(ID=dt[Set==“a”,Value,by=ID][order(ID),ID],Value=dt[Set==“a”,Value,by=ID][order(ID),Value]--dt[Set==“b”,Value,by=ID][order(ID),Value]),

YOLO.solution={df.test使用
shift
处理不同后续行中相同列的值:

dt[, .(Value = Value - shift(Value, type = "lead")), by = ID][!is.na(Value), ]
导致

   ID      Value
1:  1  0.7455129
2:  2 -0.1529171
3:  3 -1.0823840
4:  4  1.5533354
5:  5 -1.2234450
6:  6 -0.5912473
基准测试(由于@Wimpel提供了代码库而受到赞扬!):


请注意,对于这少量的输入数据,基准不是很有代表性…

使用
shift
处理不同后续行中相同列的值:

dt[, .(Value = Value - shift(Value, type = "lead")), by = ID][!is.na(Value), ]
导致

   ID      Value
1:  1  0.7455129
2:  2 -0.1529171
3:  3 -1.0823840
4:  4  1.5533354
5:  5 -1.2234450
6:  6 -0.5912473
基准测试(由于@Wimpel提供了代码库而受到赞扬!):


请注意,对于这少量的输入数据,基准并不是很有代表性…

重塑并不是真正的data.table解决方案。第二个会给我一个相同大小的dt,这不是我想要的。无论如何,谢谢。您应该运行这段代码,它给出的答案与您的问题中预期的完全相同。@RicardoFernandesCampos
dcast
是一个
data.table
解决方案,在这种情况下,因为它被覆盖了,请参见
?data.table::dcast
@R Yoda,我不知道dcast有data.table版本。谢谢。而且,很抱歉,@YOLO,我想我还没有正确地查看您的答案。重塑不是一个真正的data.table解决方案。第二个是给我一个大小相同的dt,这不是我想要的。无论如何,谢谢。你应该运行这个代码,它给出的答案与你的问题中预期的完全相同。@RicardoFernandesCampos
dcast
是一个
数据。表
解决方案在这种情况下,因为它被覆盖了,请参见
?data.table::dcast
@R Yoda,我不知道dcast有一个data.table版本。谢谢。而且,对不起,@YOLO,我想我没有正确地看你的答案。我可以假设每个ID正好出现两次并且顺序正确吗?a
shift
将是自然的…我可以假设每个ID正好出现两次并且顺序正确吗?a
shift
将是自然的。。。