R:在函数参数中为一般(通用)使用的函数指定变量名

时间:2011-11-14 12:25:13

标签: r variables functional-programming dataframe

这是我的小功能和数据。请注意,我想设计一个非一般用途的功能。

dataf <- data.frame (A= 1:10, B= 21:30, C= 51:60, D = 71:80)

myfun <- function (dataframe, varA, varB) {
              daf2 <- data.frame (A = dataframe$A*dataframe$B, 
              B= dataframe$C*dataframe$D)
              anv1 <- lm(varA ~ varB, daf2)
              print(anova(anv1)) 
             }             

myfun (dataframe = dataf, varA = A, varB = B)

Error in eval(expr, envir, enclos) : object 'A' not found

当我指定数据$ variable name时,它可以使用,但我不想制作这样的规范,因此它要求用户在函数中写入数据和变量名。

 myfun (dataframe = dataf, varA = dataf$A, varB = dataf$B)
Analysis of Variance Table

Response: varA
          Df Sum Sq Mean Sq    F value    Pr(>F)    
varB       1   82.5    82.5 1.3568e+33 < 2.2e-16 ***
Residuals  8    0.0     0.0                         
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 
Warning message:
In anova.lm(anv1) :
  ANOVA F-tests on an essentially perfect fit are unreliable

在这种情况下最佳做法是什么?我可以将数据框附加到函数内吗?这样做有什么不利或潜在的冲突/危险?请参阅输出中的masked语句。我相信一旦附上会继续提醒会话权吗?这里提供的功能只是示例,我需要更多的下游分析,其中来自不同数据帧的变量名称可以是/应该是相同的。我期待一个程序员解决方案。

myfun <- function (dataframe, varA, varB) {
              attach(dataframe)
                 daf2 <- data.frame (A = A*B, B= C*D)
              anv1 <- lm(varA ~ varB, daf2)
              return(anova(anv1))
             }             

myfun (dataframe = dataf, varA = A, varB = B)

The following object(s) are masked from 'dataframe (position 3)':

    A, B, C, D
Analysis of Variance Table

Response: varA
          Df Sum Sq Mean Sq    F value    Pr(>F)    
varB       1   82.5    82.5 1.3568e+33 < 2.2e-16 ***
Residuals  8    0.0     0.0                         
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 
Warning message:
In anova.lm(anv1) :
  ANOVA F-tests on an essentially perfect fit are unreliable

3 个答案:

答案 0 :(得分:7)

让我们调查(参见我添加的评论)您的原始函数和调用,假设您的意思是将您感兴趣的列的名称传递给函数:

myfun <- function (dataframe, varA, varB) {
              #on this next line, you use A and B. But this should be what is
              #passed in as varA and varB, no?
              daf2 <- data.frame (A = dataframe$A*dataframe$B, B=dataframe$C*dataframe$D)
              #so, as a correction, we need:
              colnames(daf2)<-c(varA, varB)
              #the first argument to lm is a formula. If you use it like this,
              #it refers to columns with _names_ varA and varB, not as names
              #the _contents_ of varA and varB!!
              anv1 <- lm(varA ~ varB, daf2)
              #so, what we really want, is to build a formula with the contents
              #of varA and varB: we have to this by building up a character string:
              frm<-paste(varA, varB, sep="~")
              anv1 <- lm(formula(frm), daf2)
              print(anova(anv1)) 
             }             
#here, you pass A and B, because you are used to being able to do that in a formula
#(like in lm). But in a formula, there is a great deal of work done to make that
#happen, that doesn't work for most of the rest of R, so you need to pass the names
#again as character strings:
myfun (dataframe = dataf, varA = A, varB = B)
#becomes:
myfun (dataframe = dataf, varA = "A", varB = "B")

注意:在上面,我保留了原始代码,因此您可能必须删除其中一些以避免您最初获得的错误。您的问题的本质是您应该始终将列名称作为字符传递,并使用它们。这是R中公式的语法糖使人们陷入不良习惯和误解的地方之一......

现在,替代方案:实际使用变量名称的唯一位置在公式中。因此,如果您不清楚稍后可以清理的结果中的一些轻微的外观差异,您可以进一步简化问题:您无需传递列名!!

myfun <- function (dataframe) {
              daf2 <- data.frame (A = dataframe$A*dataframe$B, B=dataframe$C*dataframe$D)
              #now we know that columns A and B simply exist in data.frame daf2!!
              anv1 <- lm(A ~ B, daf2)
              print(anova(anv1))
             }             

作为最后一条建议:我不会在你的最后声明中打印出来:如果你没有,但是直接从R命令行使用这种方法,它仍会为你执行打印。作为一个额外的优点,您可以使用从方法返回的对象执行进一步的工作。

通过试用清除功能:

dataf <- data.frame (A= 1:10, B= 21:30, C= 51:60, D = 71:80)
myfun <- function (dataframe, varA, varB) {
               frm<-paste(varA, varB, sep="~")
               anv1 <- lm(formula(frm), dataframe)
               anova(anv1)
             }
 myfun (dataframe = dataf, varA = "A", varB = "B")
  myfun (dataframe = dataf, varA = "A", varB = "D")
    myfun (dataframe = dataf, varA = "B", varB = "C")

答案 1 :(得分:3)

你总是可以去(恐怖)parse()路线:

Rgames: foo<- data.frame(one=1:5,two=6:10)
Rgames: bar <- function(y) eval(parse(text=paste('foo$',y,sep='')))  

也就是说,在函数内部,获取函数的参数,并使用eval(parse(...))设置构建内部数据框或所需数据向量对。

答案 2 :(得分:0)

我不确定是否完全理解你的问题,所以这就是我所理解的:你希望你的函数对从作为参数给出的data.frame中提取的数据调用lm()函数,以及列在这个由其他参数指定的data.frame中?

对我来说,最简单的解决方案是模仿lm()行为并向用户询问公式:

dataf <- data.frame(A=1:10, B=21:30, C=51:60, D=71:80)

myfun <- function(formula, dataframe) {
  daf2 <- data.frame(A=dataframe$A*dataframe$B, B=dataframe$C*dataframe$D)
  anv1 <- lm(formula=formula, data=daf2)
  print(anova(anv1))
}

myfun(formula=A~B, dataframe=dataf)

另一个解决方案是自己构建公式:

dataf <- data.frame(A=1:10, B=21:30, C=51:60, D=71:80)

myfun <- function(dataframe, varA, varB) {
  daf2 <- data.frame(A=dataframe$A*dataframe$B, B=dataframe$C*dataframe$D)
  frm = as.formula(sprintf("%s~%s", varA, varB))
  anv1 <- lm(frm, daf2)
  print(anova(anv1))
}

myfun(dataframe=dataf, varA="A", varB="B") 

我对attach并不熟悉,但我尽可能避免使用它,因为你提到的掩盖问题。如果你detach它在函数的末尾,我认为它不会导致边界效应,但你也可以发出警告。