使用data.table在R中逐行查找

时间:2014-01-27 16:01:56

标签: r data.table

我按日期列出了排名因子和相应值的表格,但我还要按排名而不是因子来显示数据。在第一步中,我确定每个等级的相应因子(输出中的.fact列),在第二步中,我使用因子来确定每个等级的相应值(输出中的.val2列)。实际数据集包括更多日期和因素(名称和计数各不相同)。每行对应于特定日期每个因子的模型预测排名,值数据是实现值。

下面的代码可行,但是有更高效(更快)的方法来完成下面的行式查找操作吗?我读过的许多data.table建议都不鼓励使用.SD[, with=FALSE],但我还没有找到另一种解决方案。

library(data.table)
dt = data.table(Date = c("1/31/2013", "2/28/2013", "3/31/2013", 
                         "4/30/2013", "5/31/2013"), 
                A.rnk = c(5L, 2L, 2L, 3L, 3L), 
                B.rnk = c(4L, 3L, 1L, 2L, 5L), 
                C.rnk = c(3L, 1L, 4L, 1L, 1L), 
                D.rnk = c(2L, 4L, 3L, 5L, 2L),
                E.rnk = c(1L, 5L, 5L, 4L, 4L),
                A.val = rnorm(5), B.val = rnorm(5), 
                C.val = rnorm(5), D.val = rnorm(5),
                E.val = rnorm(5))
nms = c("A", "B", "C", "D", "E")
rnks = as.character(1:5)

# determine the factor (A,B,C) for each rank, by date
dt = dt[, c(rnks):={
  cols = .SD[, paste0(nms, ".rnk"), with=FALSE]
  cols = names(cols)[order(cols)]
  as.list(stringr::str_extract(cols, stringr::perl(".{1}(?=.rnk)")))
}, by=Date]

# determine the factor value (val) for each rank, by date
dt[, paste0(rnks, ".val2"):=
     .SD[, paste0(.SD[, rnks, with=FALSE], ".val"), with=FALSE], by=Date]

1 个答案:

答案 0 :(得分:2)

这是一个完整的重写。根据您的要求,最好使用长格式中的数据,如下所示。它使用reshape2包,其中包含函数meltdcast,分别将数据转换为长格式和宽格式。

  

请注意,在melt的当前开发版本(1.8.11)中实现了dcastdata.table的更快版本(在C中)。因此,在data.table的下一个版本之后,您可以使用相同的代码,但是您不必将其转换回data.table(使用下面显示的as.dat.table完成后) meltdcast+它会快得多。

现在解决方案:

# loading packages
require(data.table)
require(reshape2)

# long format on just the .rnk columns
dt.m <- as.data.table(melt(dt, id="Date", measure=2:6))
setnames(dt.m, c("Date", "var1", "val1"))
dt.m[, c("var2", "val2") := as.data.table(melt(dt, id="Date", 
               measure=7:11))[, list(variable, value)]]
# sort by date column by reference
setkey(dt.m, Date)

# here you can alternatively use `order`, but `fastorder` is well, faster
oo <- data.table:::fastorder(as.list(dt.m)[c("Date","val1")])
dt.m[, val3 := rep(nms, length.out=length(oo))[oo]]
dt.m[, val4 := val2[val1], by=Date]

ans1 <- as.data.table(dcast(dt.m, Date ~ var1, value.var="val3"))[, Date := NULL]
ans2 <- as.data.table(dcast(dt.m, Date ~ var2, value.var="val4"))[, Date := NULL]
setnames(ans1, rnks)
setnames(ans2, paste(rnks, ".val2", sep=""))
cbind(dt, ans1, ans2)