【问题标题】:Speeding up a function加速函数
【发布时间】:2019-08-08 06:46:30
【问题描述】:

我想计算大型面板数据集的一阶差异。然而,目前这需要一个多小时。我真的很想知道是否还有任何选择可以加快这一进程。以数据库为例:

set.seed(1)
DF <- data.table(panelID = sample(50,50),                                                    # Creates a panel ID
                      Country = c(rep("A",30),rep("B",50), rep("C",20)),                      
                      Group = c(rep(1,20),rep(2,20),rep(3,20),rep(4,20),rep(5,20)),
                      Time = rep(seq(as.Date("2010-01-03"), length=20, by="1 month") - 1,5),
                      norm = round(runif(100)/10,2),
                      Income = sample(100,100),
                      Happiness = sample(10,10),
                      Sex = round(rnorm(10,0.75,0.3),2),
                      Age = round(rnorm(10,0.75,0.3),2),
                      Educ = round(rnorm(10,0.75,0.3),2))           
DF [, uniqueID := .I]  

所以我尝试过的是:

DFx <- DF
start_time <- Sys.time()
    DF <- DF[, lapply(.SD, function(x) x - shift(x)), by = panelID, .SDcols = (sapply(DF, is.numeric))]
end_time <- Sys.time()
DF <- DFx
start_time2 <- Sys.time()
    cols = sapply(DF, is.numeric)
    DF <- DF[, lapply(.SD, function(x) x - shift(x)), by = panelID, .SDcols = cols]
end_time2 <- Sys.time()
DF <- DFx
start_time3 <- Sys.time()
DF <- DF[order(panelID)] # Sort on year
nm1 <- sapply(DF, is.numeric) # Get the numerical columns  
nm1 = names(nm1) 
nm2 <- paste("delta", nm1, sep="_")[-6] # Paste
DF <- DF[,(nm2) := .SD - shift(.SD), by=panelID] # Creates 
end_time3 <- Sys.time()
end_time3 - start_time3
end_time2 - start_time2
end_time - start_time

由于某种原因,第三个选项适用于我的实际数据库,但不适用于本示例。它给出了错误:Error in FUN(left, right) : non-numeric argument to binary operator。对于我的实际数据库,这种计算方式也相当慢(然后我仍然需要子集)。

有什么方法可以加快速度吗?

【问题讨论】:

  • 你为什么不使用diff函数?
  • 我从之前发布的问题中获得了这些选项。 diff 更快吗?
  • 在设置options(datatable.verbose = TRUE) 时,我认为您的第一个选项没有什么特别的问题。我真的很惊讶这需要这么长时间。您的panelID 数量一定很大。
  • 如果我增加输入 data.table 的大小,function(x) c(NA, diff(x)) 的速度似乎是原来的两倍。
  • 嗯,非常相关。 melt你的data.table,这样你就不需要lapply

标签: r optimization data.table lapply


【解决方案1】:

data.table 针对多行而不是多列进行了优化。由于您有很多列,您可以尝试融合 data.table:

DFm <- melt(DF[, cols, with = FALSE][, !"uniqueID"], id = "panelID") 
#coerces all numers to double (common type), 
#you could separate the data.table by integer/double to avoid this

DFm[, value := c(NA, diff(value)), by = .(panelID, variable)]


dcast(DFm, panelID + rowidv(DFm, cols = c("panelID", "variable")) ~ variable, value.var = "value")

【讨论】:

  • 非常感谢罗兰。这非常有帮助。我现在正在尝试,但是当应用 melt 时出现错误:Error in [.data.table(DF, , cols, with = FALSE) : Item 10 of j is 12 which is outside the column number range [1,ncol=11] 我不确定为什么会发生这种情况(或如何找出答案)。有什么想法吗?
  • 很明显,cols 中有数字 12,但 DF 中只有 11 列。
  • 对不起,我是个白痴,我忽略了 cols 被使用(并且没有被指定)。现在可以使用了!
  • 那么,大约 15 分钟?那还是很慢的。如果我经常需要这个,我会用 Rcpp 编写一个函数。
  • @jangorecki 但这不是这里的瓶颈。只是有大量的组。
猜你喜欢
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 1970-01-01
相关资源
最近更新 更多