4

我对 R 很陌生,我对tryCatch. 我的目标是对大型数据集进行预测。如果预测无法放入内存,我想通过拆分数据来规避问题。

现在,我的代码大致如下:

tryCatch({
  large_vector = predict(model, large_data_frame)
}, error = function(e) { # I ran out of memory
  for (i in seq(from = 1, to = dim(large_data_frame)[1], by = 1000)) {
    small_vector = predict(model, large_data_frame[i:(i+step-1), ])
    save(small_vector, tmpfile)
  }
  rm(large_data_frame) # free memory
  large_vector = NULL
  for (i in seq(from = 1, to = dim(large_data_frame)[1], by = 1000)) {
    load(tmpfile)
    unlink(tmpfile)
    large_vector = c(large_vector, small_vector)
  }
})

关键是,如果没有发生错误,large_vector则按预期填充我的预测。如果发生错误,large_vector似乎只存在于错误代码的命名空间中——这是有道理的,因为我将它声明为一个函数。出于同样的原因,我收到一条警告说large_data_frame无法删除。

不幸的是,这种行为不是我想要的。我想large_vector从我的错误函数中分配变量。我认为一种可能性是指定环境并使用分配。因此,我将在我的错误代码中使用以下语句:

rm(large_data_frame, envir = parent.env(environment()))
[...]
assign('large_vector', large_vector, parent.env(environment()))

但是,这个解决方案对我来说似乎很脏。我想知道是否有可能用“干净”的代码来实现我的目标?

[编辑] 似乎有些混乱,因为我把代码放在上面主要是为了说明问题,而不是给出一个工作示例。这是一个显示命名空间问题的最小示例:

# Example 1 : large_vector fits into memory
rm(large_vector)
tryCatch({
  large_vector = rep(5, 1000)
}, error = function(e) {
  # do stuff to build the vector
  large_vector = rep(3, 1000)
})
print(large_vector)  # all 5

# Example 2 : pretend large_vector does not fit into memory; solution using parent environment
rm(large_vector)
tryCatch({ 
  stop();  # simulate error
}, error = function(e) {
  # do stuff to build the vector
  large_vector = rep(3, 1000)
  assign('large_vector', large_vector, parent.env(environment()))
})
print(large_vector)  # all 3

# Example 3 : pretend large_vector does not fit into memory; namespace issue
rm(large_vector)
tryCatch({ 
  stop();  # simulate error
}, error = function(e) {
  # do stuff to build the vector
  large_vector = rep(3, 1000)
})
print(large_vector)  # does not exist
4

3 回答 3

5

我会做这样的事情:

res <- tryCatch({
  large_vector = predict(model, large_data_frame)
}, error = function(e) { # I ran out of memory
  ll <- lapply(split(data,seq(1,nrow(large_data_frame),1000)),
         function(x)
             small_vector = predict(model, x))
  return(ll)
})
rm(large_data_frame)
if(is.list(ll)) 
  res <- do.call(rbind,res)

这个想法是在内存用完时返回一个预测结果列表。

注意,我不确定这里的结果,因为我们没有可重现的示例。

于 2013-03-08T10:45:52.477 回答
3

编辑:让我们再试一次:

您可以使用以下finally参数tryCatch

step<-1000
n<-dim(large_data_frame)[1]
large_vector <- NULL
tryCatch({
  large_vector <- predict(model, large_data_frame) 
}, error = function(e) { # ran out of memory
  for (i in seq(from = 1, to = n, by = step)) {
    small_vector <- predict(model, large_data_frame[i:(i+step-1),]) #predict in pieces
    save(small_vector,file=paste0("tmpfile",i)) #same pieces
  }  
 rm(large_data_frame) #free memory

},finally={if(is.null(large_vector)){ #if we run out of memory
   large_vector<-numeric(n) #make vector
   for (i in seq(from = 1, to = n, by = step)){
     #collect pieces
     load(paste0("tmpfile",i)) 
     large_vector[i:(i+step-1)] <- small_vector
   }
}})

这是一个简化版本,可以查看发生了什么:

large_vector<-NULL
rm(y)
tryCatch({
  large_vector <- y 
}, error = function(e) {# y is not found
  print("error")
},finally={if(is.null(large_vector)){
 large_vector<-1
}})
> large_vector
[1] 1

EDIT2:关于可能对您有用的范围的另一个提示(尽管可能不是在这种情况下,因为您不想large_vector事先声明):<<-操作员,来自 R-help:

运算符 <<- 和 ->> 通常仅在函数中使用,并导致通过父环境搜索正在分配的变量的现有定义......

因此,您可以像这样使用上面的示例代码:

large_vector<-NULL
rm(y)
tryCatch({
  large_vector <- y 
}, error = function(e) {# y is not found
  large_vector <<- 1
  print("error")
})
> large_vector
[1] 1
于 2013-03-08T10:35:46.647 回答
0

下面的代码是非常不言自明的。实际上,问题在于错误函数中的任何内容默认情况下都不会应用于父环境。

b=0

如上所述,这不起作用:

tryCatch(expr = {stop("error1")}, error=function(e) {b=1})
b

解决方案1:分配给父环境

tryCatch(expr = {stop("error2")}, error=function(e) {assign(x = "b", value = 2, envir = parent.env(env = environment()))})
b

expr解决方案2:最简单的(仅当您在and中都分配给 b 时才有效error

b = tryCatch(expr = {stop("error3")}, error=function(e) {b=3;return(b)})
b

于 2015-12-15T03:53:31.640 回答