使用 tm 在 R 函数中分配全局变量:linux 上的错误?
assign global variable in R function using tm: bug on linux?
使用 R 中的包 tm
,我想转换一个具有相当复杂功能的语料库,我需要一些副作用来存储相关信息。由于 content_transformer
需要特定的函数格式,因此简单的方法是在我的函数中使用 <<-
。以下代码出现问题:
library(tm)
a <- 4
n <- 2
corp<-VCorpus(VectorSource(rep("fish",n)))
(func<-content_transformer(
function(x) {
a <<- 42
return(x)
}))
corp<-tm_map(corp,func)
print(a)
它打印出错误的答案,即 4。但是当 n=1 时,它打印出正确的答案。所以我假设是 tm 执行的多线程无法像标量 R 那样工作。我猜这是一个错误,因为在 windows 上它起作用了。 (注意:我在 linux 上使用 R 3.1.2,在 windows 上使用 R 3.1.1)。
问题:这是一个错误吗?如果是,一个已知的错误?有没有不需要重构代码的简单解决方案?
谢谢!
编辑:使用 assing
的附加示例
rm(list=ls())
library(tm)
env <- new.env()
a <- 1
n <- 2
corp<-VCorpus(VectorSource(rep("fish",n)))
(func<-content_transformer(
function(x,e) {
assign("a", 42, envir=e)
print(e)
print(ls.str(e))
return(x)
}))
corp<-tm_map(corp,func,env)
print(env)
print(ls.str(env))
事实上,这在 Windows 下意外起作用,因为 mclapply
未在 windows 下定义,它只是对 lapply
.[=21= 的调用]
确实,当您调用 tm_map
时,您正在使用此函数:
tm:::tm_map.VCorpus
function (x, FUN, ..., lazy = FALSE)
{
if (lazy) {
fun <- function(x) FUN(x, ...)
if (is.null(x$lazy))
x$lazy <- list(index = rep(TRUE, length(x)), maps = list(fun))
else x$lazy$maps <- c(x$lazy$maps, list(fun))
}
else x$content <- mclapply(content(x), FUN, ...) ## this the important line
x
}
因此您可以通过调用 mclapply
重现 "odd/normal" 行为:
library(parallel)
res <- mclapply(1:2, function(x){a<<- 20;x})
a
[1] 4
a 没有变化,仍然等于 4。这是正常的并行行为,因为我们避免了副作用。在 windows mcapply
下只是对 lapply
的调用,因此全局变量的值被正确更改。
伪解
如果你想要全局副作用,这里最好使用 lapply
,但是如果你添加 a
作为函数的第二个参数,你可以在阅读中模拟全局变量。 .
func <-
function(x,a) {
a <- 42 ## use a here
x$a <- a ## assign it to the x environment
return(x) ## but the new value of a can not be used by others documents..
}
(Func<-content_transformer(func))
res <- tm_map(corp,Func,a=4)
使用 R 中的包 tm
,我想转换一个具有相当复杂功能的语料库,我需要一些副作用来存储相关信息。由于 content_transformer
需要特定的函数格式,因此简单的方法是在我的函数中使用 <<-
。以下代码出现问题:
library(tm)
a <- 4
n <- 2
corp<-VCorpus(VectorSource(rep("fish",n)))
(func<-content_transformer(
function(x) {
a <<- 42
return(x)
}))
corp<-tm_map(corp,func)
print(a)
它打印出错误的答案,即 4。但是当 n=1 时,它打印出正确的答案。所以我假设是 tm 执行的多线程无法像标量 R 那样工作。我猜这是一个错误,因为在 windows 上它起作用了。 (注意:我在 linux 上使用 R 3.1.2,在 windows 上使用 R 3.1.1)。
问题:这是一个错误吗?如果是,一个已知的错误?有没有不需要重构代码的简单解决方案?
谢谢!
编辑:使用 assing
的附加示例rm(list=ls())
library(tm)
env <- new.env()
a <- 1
n <- 2
corp<-VCorpus(VectorSource(rep("fish",n)))
(func<-content_transformer(
function(x,e) {
assign("a", 42, envir=e)
print(e)
print(ls.str(e))
return(x)
}))
corp<-tm_map(corp,func,env)
print(env)
print(ls.str(env))
事实上,这在 Windows 下意外起作用,因为 mclapply
未在 windows 下定义,它只是对 lapply
.[=21= 的调用]
确实,当您调用 tm_map
时,您正在使用此函数:
tm:::tm_map.VCorpus
function (x, FUN, ..., lazy = FALSE)
{
if (lazy) {
fun <- function(x) FUN(x, ...)
if (is.null(x$lazy))
x$lazy <- list(index = rep(TRUE, length(x)), maps = list(fun))
else x$lazy$maps <- c(x$lazy$maps, list(fun))
}
else x$content <- mclapply(content(x), FUN, ...) ## this the important line
x
}
因此您可以通过调用 mclapply
重现 "odd/normal" 行为:
library(parallel)
res <- mclapply(1:2, function(x){a<<- 20;x})
a
[1] 4
a 没有变化,仍然等于 4。这是正常的并行行为,因为我们避免了副作用。在 windows mcapply
下只是对 lapply
的调用,因此全局变量的值被正确更改。
伪解
如果你想要全局副作用,这里最好使用 lapply
,但是如果你添加 a
作为函数的第二个参数,你可以在阅读中模拟全局变量。 .
func <-
function(x,a) {
a <- 42 ## use a here
x$a <- a ## assign it to the x environment
return(x) ## but the new value of a can not be used by others documents..
}
(Func<-content_transformer(func))
res <- tm_map(corp,Func,a=4)