R: указание имени переменной в параметре функции для функции общего (универсального) использования - PullRequest
4 голосов
/ 14 ноября 2011

Вот моя маленькая функция и данные. Обратите внимание, что я хочу создать функцию, не предназначенную для личного пользования, для общего пользования.

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

Это работает, когда я задаю имя переменной $ data, но я не хочу делать такую ​​спецификацию, чтобы пользователю требовалось записать в функцию как данные, так и имя переменной.

 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

Какова лучшая практика в этой ситуации? я могу поставить прикрепить фрейм данных внутри функции? какие могут быть недостатки или потенциальные конфликты / опасности при этом? Смотрите замаскированный оператор в выводе. Я полагаю, что как только оно будет прикреплено, оно останется приложенным напоминанием о сессии, верно? Функция, представленная здесь, является просто примером, мне нужно больше последующего анализа, где имена переменных из разных фреймов данных могут быть / должны быть идентичными. Я ожидаю решения программиста по этому вопросу.

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 ]

7 голосов
/ 14 ноября 2011

Давайте исследуем (см. Добавленные мной комментарии) исходную функцию и вызов, предполагая, что вы хотите передать имена интересующих вас столбцов в функцию:

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))
             }             

В качестве последнего совета: я бы воздержался от вызова print в вашем последнем утверждении: если вы этого не сделаете, но используйте этот метод непосредственно из командной строки 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")
3 голосов
/ 14 ноября 2011

Вы всегда можете пойти по маршруту (ужасы) parse():

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

То есть, внутри вашей функции, получить аргументы функции и создать внутренний фрейм данных или парывекторы данных, которые вы хотите использовать с помощью установки eval (parse (...)).

0 голосов
/ 14 ноября 2011

Я не уверен, что полностью понимаю вашу проблему, поэтому вот что я понял: вы хотите, чтобы ваша функция вызывала функцию lm() для данных, извлеченных из data.frame, заданного в качестве аргумента, и столбцов в этом 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 сделаете это в конце функции, я думаю, что это не вызовет эффекта границы, но вы также можете выдать предупреждение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...