【问题标题】:Slow for loop in RR中的慢for循环
【发布时间】:2016-06-23 20:38:33
【问题描述】:

我正在尝试从多个 NCDef (.nc) 格式的文件中提取数据。我编写的代码可以运行,但速度很慢,如果有任何建议,我将不胜感激!

我的工作代码使用 RNetCDF 提取一个名为 temp 的文件,并将其转换为一个“长列表”,其中每个变量都有一个或三个维度(lat、lon 和 pft)。然后,我一次从每个变量中提取数据(varlist[j])并将其转换为数据框。然后,Adply 通过三个维度中的每一个来打破这一点。最后一步,创建files,允许我使用 cbind 和 rbind 将所有文件放在一个大数据框中。

代码如下:

setwd("C:/Users/User/Box Sync/_PhD/PhD_Research/Albedo/Data_CLM/PFTRuns/2005/")
fname<-"b40.20th.1deg.bdrd.002bc.clm2.h0.2005-"
numlist<-c('01','02','03','04','05','06','07','08','09','10','11','12')
varlist<-c(1,2,4,8,9,21)
varname<-c("lon","lat","pft","pft_wtgcell","pft_wtcol","FSR")
files<-matrix(data=NA, nrow=12, ncol=length(varlist))

`for (i in 12:12) {
  temp<- paste(c(fname, numlist[i],'.nc'), collapse='')
  temp<-read.nc(open.nc(temp))
  temp<-structure(temp, row.names = c(NA, -288), class = "data.frame")
  for (j in 3:length(varlist)) {
    newname<-paste(c("Y2005", numlist[i],".", varname[j]), collapse='')
    if (j<4){
        assign(newname, adply(temp[,varlist[j]], c(1)))}
    else{
        assign(newname, adply(temp[,varlist[j]], c(1,2,3)))}
    files[i,j]<-newname}}`

编辑 这是 read.nc(open.nc()) 输出的示例。 Example Output

【问题讨论】:

  • 如果您正在寻找流程改进,您可能希望发布更多代码。发布read.nc(open.nc(temp) 的输出样本会有所帮助。避免多次转换到数据帧并在最后执行该操作可能会提高性能。从 plyr 包迁移到 dplyr 也可能是另一个性能提升。
  • 感谢您的想法,我已经添加了该输出,并显示了更多代码。

标签: r performance loops


【解决方案1】:

查看您的问题。您有一系列 3d 数组,您希望将它们展平为 1d 数组并与坐标向量(lon、lat 和 put)对齐。
虽然包 plyr 有许多非常有用的功能,但它们往往很慢。和你上面的例子一样。

这里是我为测试创建的示例数据:

#create some test data
set.seed(1)
lon<-1:300
lat<-1:200
pft<-1:15
tot<-length(lon)*length(lat)*length(pft)
pft_wtgcell<- array(rnorm(tot, 10), dim=c(length(lon),length(lat),length(pft)))
pft_wtcol<- array(rnorm(tot, 60, 2), dim=c(length(lon),length(lat),length(pft)))
FSR<- array(rnorm(tot, 100, 3), dim=c(length(lon),length(lat),length(pft)))
temp<-list(lon=lon, lat=lat, pft=pft, pft_wtgcell=pft_wtgcell, pft_wtcol=pft_wtcol, FSR=FSR)

这是我的解决方案:

numlist<-c('01','02','03','04','05','06','07','08','09','10','11','12')
#varlist<-c(1,2,4,8,9,21)
varname<-c("lon","lat","pft","pft_wtgcell","pft_wtcol","FSR")
files<-matrix(data=NA, nrow=12, ncol=length(varname))
#loop to cycle through the file starts here:
i<-1

#crate data.frame for lon, lat and pft
newname<-paste(c("Y2005", numlist[i],".", varname[1]), collapse='')
coord<-expand.grid(temp$lon, temp$lat, temp$pft)
assign(newname, coord)
files[i,1]<-newname
#loop through the variables of interest
#  could probly be simplified.
for (j in 4:length(varname)) {
  newname<-paste(c("Y2005", numlist[i],".", varname[j]), collapse='')
  assign(newname, as.data.frame.table(temp[[varname[j] ]])$Freq)
  files[i,j]<-newname
}

我避免将示例数据转换为数据框,并决定直接在列表上工作。 expand.grid 函数快速创建包含 lon、lat 和 pft 的所有可能组合的数据框。搜索有关如何展平 3d 数组的提示时,我发现了对在这种情况下有效的 as.data.frame.table 函数的引用,而且我只是存储最后(展平)数据列。只有需要的数据存储在 data.frame 中,rbinds 的执行速度也应该更快。

我没有对错误进行广泛的检查,但在我的笔记本电脑上,我看到上述测试用例的速度提高了 500 倍。

如果这对你有用,请接受答案,否则我可以再调整一些。

【讨论】:

  • 不使用assign当然可以解决这个问题。
  • 是的,我宁愿不使用 assign 语句,但由于原始代码使用它来创建结果“文件”矩阵,所以我把它留在了。
  • 谢谢,这很有帮助!我不能完全按原样使用它,因为我还需要能够从 ncdef 文件中读取 lat、lon 和 pft,但我可以先读取它们,然后使用它们创建“坐标”作为你在上面显示。
  • 调整它以使用您的建议,见下文。现在运行得非常快,谢谢!
  • 糟糕,我的错误。它应该是:expand.grid(temp$lon, temp$lat, temp$pft)。我修复了上面的代码以反映更正。这就是在没有实际数据的情况下发生的情况。我很高兴你能找出正确的。
【解决方案2】:

这是我在@Dave2e 的帮助下确定的答案

#Library Settings #------------------------------------------------------------------------------------
library(RNetCDF);library(data.table);library(plyr); library(arrayhelpers)
#File Settings #---------------------------------------------------------------------------------------
setwd("C:/Users/User/Box Sync/_PhD/PhD_Research/Albedo/Data_CLM/PFTRuns/2005/")
fname<-"b40.20th.1deg.bdrd.002bc.clm2.h0.2005-"
numlist<-c('01','02','03','04','05','06','07','08','09','10','11','12')
varlist<-c(1,2,4,8,9,21)
varname<-c("lon","lat","pft","pft_wtgcell","pft_wtcol","FSR")
files<-matrix(data=NA,ncol=12)

for (i in 1:12) {
  temp<- paste(c(fname, numlist[i],'.nc'), collapse='')
  temp<-read.nc(open.nc(temp))
  for (j in 1:3){
    vars<-temp[[varlist[j]]]
    newname<-paste(c("Y2005",".", varname[j]), collapse='')
    assign(newname, vars)}
  coord<-expand.grid(Y2005.lon, Y2005.lat, Y2005.pft)
  coord$month<-c(numlist[i])
  newname<-paste(c("Y2005", numlist[i]), collapse=''); assign(newname, coord)
  for (j in 4:length(varlist)){
    temp2<-array2df(temp[[varlist[j]]], label.x=varname[j])
    assign(newname, cbind(temp2, get(newname)))}
  files[i]<-newname}
Y2005<-lapply(files, cbind)

【讨论】:

    猜你喜欢
    • 2016-07-12
    • 2021-05-28
    • 1970-01-01
    • 2014-05-17
    • 1970-01-01
    • 2011-07-28
    • 2016-11-23
    • 2011-05-11
    • 2016-01-01
    相关资源
    最近更新 更多