R

时间:2015-08-10 13:53:06

标签: r apply

我在调用boxcox函数时遇到使用apply函数的问题。

数据集由35个样本组成,2天内有3个治疗(有些人在几天内重复,但总是在治疗组内),有大约1000个测量/因变量,我这里仅包括5个(#1,2,4, 7,9)。

NUM day trt 1   2   4   7   9  
8145    7   L   0.986   0.423   0.86    0.648   2.031  
8169    7   L   1.013   0.512   1.157   0.633   0.55  
8201    7   L   0.236   6.144   0.604   1.759   1.181  
8212    7   L   0.455   0.707   0.693   0.972   0.615  
8168    7   L   1.261   0.618   1.138   0.943   0.868  
8193    7   L   1.754   0.273   1.224   0.719   0.895  
8145    13  L   1.257   0.36    1.505   0.729   0.735  
8169    13  L   1.549   0.577   1.53    0.771   1.116  
8201    13  L   0.489   0.378   0.842   1.538   1.676  
8212    13  L   0.991   0.34    1.03    1.157   1.076  
8168    13  L   1.355   0.391   1.416   0.953   1.479  
8193    13  L   1.029   0.308   1.027   0.902   1.934  
8214    7   C   1.224   0.298   1.113   1.445   0.218  
8139    7   C   1.277   0.554   1.443   0.895   0.74  
8151    7   C   1.312   2.025   1.197   0.675   0.791  
8160    7   C   1.555   0.405   1.432   0.826   0.501  
8196    7   C   0.938   0.717   0.917   0.801   1.462  
8213    7   C   0.835   1.863   0.942   1.967   0.739  
8139    13  C   0.958   0.275   1.273   1.351   0.842  
8151    13  C   0.864   0.517   0.98    1.368   1.865  
8160    13  C   1.516   0.895   1.318   0.551   0.779  
8239    13  C   1.071   0.194   0.955   1.87    0.68  
8196    13  C   1.299   0.594   1.14    0.877   1.873  
8213    13  C   1.601   0.733   1.375   0.738   1.273  
8231    7   H   1.401   0.483   1.001   1.052   0.548  
8232    7   H   1.292   0.574   1.634   0.641   0.464  
8219    7   H   0.785   0.396   0.886   0.903   1.734  
8177    7   H   0.525   0.252   0.563   0.914   1.174  
8143    7   H   1.398   0.266   0.947   0.94    0.781  
8219    13  H   0.903   6.225   1.109   1.218   1.073  
8143    13  H   1.086   0.435   1.4 0.922   0.925  
8167    13  H   0.83    0.574   1.09    1.338   1.563  
8231    13  H   1.498   0.482   1.375   0.855   0.719  
8232    13  H   1.055   0.811   0.887   0.606   0.634  
8177    13  H   0.857   1.324   0.954   1.635   0.675  

我试图在R中的MASS包中运行boxcox函数来评估是否需要转换数据,如果是,则根据具有最大对数似然(或其舍入)的lamda值进行转换。

linear.f=function(x){lm(x~day+trt+day*trt, data=data)}
linear.multiple=apply(data[,4:ncol(data)],2,linear.f)

工作正常

单独运行boxcox功能也可以正常工作

boxcox(lm(x~day+trt+day*trt,data=data))$x[which.max(boxcox(lm(x~day+trt+day*trt, data=data))$y)]

投入使用的功能:

lamda.f=function(x){boxcox(lm(x~day+trt+day*trt, data=data))$x[which.max(boxcox(lm(x~day+trt+day*trt, data=data))$y)]}

但是,尝试使用apply在所有列/因变量中运行boxcox时会出现问题:

lamda.multiple=apply(data[,4:ncol(data)],2,lamda.f)

错误:

 Error in model.frame.default(formula = x ~ day + trt + day * trt, data = data,  : 
  invalid type (list) for variable 'x'

我做的事情显然不正确吗?因为boxcox将在每列数据上逐个工作..

我也尝试过使用for循环代替申请但不成功

非常感谢任何建议或帮助。

1 个答案:

答案 0 :(得分:1)

此问题与apply()电话无关。这与您在公式中使用x这一事实有关,但您传递给lm()的数据集没有x列。

lm()功能有点"宽松",也许是不可取的。如果在给定数据集中找不到给定公式中的符号,则lm()允许它绑定到可以在公式的闭包环境链中找到的任何变量。来自https://stat.ethz.ch/R-manual/R-devel/library/stats/html/model.frame.html

  

公式,子集和in ...中的所有变量首先在数据中查找,然后在公式环境中查找(有关详细信息,请参阅公式()的帮助)并收集到数据框中。

     

...

     

只有类型为raw,logical,integer,real,complex或character的变量才能包含在模型框架中:这包括分类变量,例如因子(其基础类型为整数),但不包括列表。

现在,实际上,您的linear.f()lamda.f()函数都有一个函数参数x,这样lm()调用就可以成功,在中< / em>功能。 IOW,当lm()在这些函数内运行时,x无法绑定到给定数据集(data)中的任何列,但随后绑定到闭包环境中的函数参数公式(当前函数评估的评估环境)。因此,lm()调用成功。

进一步详细说明:评估函数时,其参数始终存储在为特定函数的特定评估创建的评估环境中。由于您已经在函数内部定义了公式,因此它会关闭当前评估环境,因此当lm()运行时,在未能绑定到数据集中的列之后,搜索目标符号x首先命中该环境并绑定到环境中的函数参数条目。

我注意到您表示lm() + boxcox()的一次性顶层呼叫成功。这很奇怪,因为没有要绑定的函数参数。我只能猜测,在您运行该行代码时,您碰巧在全局环境中拥有一个对模型有效的变量x。如果没有,则它应该失败,因为公式中的x符号在数据集或闭包环境链中没有任何内容可以绑定。请注意, lm() 应该失败;我甚至没有在这里谈论boxcox()

if (exists('x')) rm(x); ## remove global x
lm(x~day+trt+day*trt,data=data);
## Error in eval(expr, envir, enclos) : object 'x' not found

现在,当你运行第二次应用调用时,我们可能会猜到你用一个列表覆盖了全局x变量,这会产生你得到的确切错误信息:

x <- list();
lm(x~day+trt+day*trt,data=data);
## Error in model.frame.default(formula = x ~ day + trt + day * trt, data = data,  :
##   invalid type (list) for variable 'x'

但这里肯定会有其他事情发生。回想一下我如何指出linear.f()lamda.f()都有一个函数参数x,所以lm()应该绑定到那个,因为那是一个有效的预测器矢量,它应该是成功的。

在我看来,boxcox()正在自行调用lm(),并且在某种程度上阻止了闭包链搜索。我相信我可以用以下代码证明这个猜想,它使用IIFEs(最初是一个JavaScript术语,但适用于具有一流可表达函数的任何语言,如R):

if (exists('x')) rm(x); ## remove global x
data2 <- data.frame(y=1:3); ## no x
(function(x) lm(y~x,data2))(1:3); ## x binds to function parameter
##
## Call:
## lm(formula = y ~ x, data = data2)
##
## Coefficients:
## (Intercept)            x
##           0            1
##
(function(x) boxcox(lm(y~x,data2)))(1:3);
## Error in eval(expr, envir, enclos) : object 'x' not found
traceback();
## 14: eval(expr, envir, enclos)
## 13: eval(predvars, data, env)
## 12: model.frame.default(formula = y ~ x, data = data2, drop.unused.levels = TRUE)
## 11: stats::model.frame(formula = y ~ x, data = data2, drop.unused.levels = TRUE)
## 10: eval(expr, envir, enclos)
## 9: eval(mf, parent.frame())
## 8: lm(formula = y ~ x, data = data2, y = TRUE, qr = TRUE)
## 7: eval(expr, envir, enclos)
## 6: eval(call, parent.frame())
## 5: update.default(object, y = TRUE, qr = TRUE, ...)
## 4: update(object, y = TRUE, qr = TRUE, ...)
## 3: boxcox.lm(lm(y ~ x, data2))
## 2: boxcox(lm(y ~ x, data2)) at #1
## 1: (function(x) boxcox(lm(y ~ x, data2)))(1:3)

正如您所看到的,boxcox()似乎正在运行lm(),但与直接lm()调用不同,无法绑定到函数参数x,即使它应该能够,因为传递给boxcox()的公式参数包含闭包环境指针。我想我们可以将这个问题归结为boxcox()函数的弱点。

无论如何,对于解决方案,一个好的方法是依赖于闭包环境系统来解析未绑定的公式符号,而是始终确保给定的数据集包含所有列的列公式中的符号。简单的例子:

data2 <- data.frame(y=1:3,x=10:12);
boxcox(lm(y~x,data2)); ## succeeds

然而,在您的情况下,这并不是那么简单,因为您有一个动态结果变量。一个好的方法是在将data.frame传递给lm()调用之前用结果变量补充你的data.frame,例如与cbind(data,x)

不幸的是,令人惊讶的是,我收到了以下错误:

lamda.f <- function(x) { data.x <- cbind(data,x); boxcox(lm(x~day+trt+day*trt,data=data.x))$x[which.max(boxcox(lm(x~day+trt+day*trt,data=data.x))$y)]; };
lamda.multiple <- apply(data[,4:ncol(data)],2,lamda.f);
## Error in is.data.frame(data) : object 'data.x' not found

我甚至尝试从lm()调用中分离boxcox()调用,以防boxcox()对其参数进行某种疯狂的非标准评估,从而尝试评估data.x在上下文中会阻止与lamda.f()评估环境的绑定:

lamda.f <- function(x) { data.x <- cbind(data,x); m <- lm(x~day+trt+day*trt,data=data.x); b <- boxcox(m); b$x[which.max(b$y)]; };
lamda.multiple <- apply(data[,4:ncol(data)],2,lamda.f);
## Error in is.data.frame(data) : object 'data.x' not found

在我看来,boxcox()在很大程度上取决于全球环境。从函数作用域内运行boxcox()并依赖于任何局部变量就会破坏它。我怀疑它正在检查存储在模型对象上的调用(例如m$call)并尝试直接读取符号。无论如何,这真的很奇怪。

我认为你可以通过在全局环境中存储补充的data.frame并确保它在boxcox()运行的那一刻存在来解决这个问题。您可以使用超级对齐运算符:

lamda.f <- function(x) { data.x <<- cbind(data,x); m <- lm(x~day+trt+day*trt,data=data.x); b <- boxcox(m); b$x[which.max(b$y)]; };
lamda.multiple <- apply(data[,4:ncol(data)],2,lamda.f);
lamda.multiple;
##         X1         X2         X4         X7         X9
##  1.2323232 -0.6666667  0.7474747 -0.6666667  0.2222222