R 问题:执行 lm 然后执行 boxcox 以找到合适的 lambda 值

R issue : performing lm and then a boxcox to find a proper lambda value

我在 data.frame 中有一个气候数据数据集(列是测量站,行表示测量时间),我正试图在 Yeo-Johnson 变换中找到合适的 lambda 值限制偏度对主成分分析的影响。

显然,第一步是获取对数似然以找到最佳 lambda:我使用以下内容,其中 i 是列的索引:

getYeoJohsnonLambda <- function(myClimateData,cols,lambda_min, lambda_max,eps)
...
lambda <- seq(lambda_min,lambda_max,eps)
for(i in cols)
    {
    formula <- as.formula(paste("myClimateData$",colnames(myClimateData)[i],"~1"))
    currentModel <- lm(formula,myClimateData)
    print(currentModel)
    myboxCox <- boxCox(currentModel, lambda = lambda ,family="yjPower", plotit = FALSE)
    ...
    }

当我试图为气候数据时间序列调用它时,例如:

`climateData <-data.frame(c(8.2,6.83,5.46,4.1,3.73,3.36,3,3,3,3,3.7),c(0,0.66,1.33,2,2,2,2,2,2,2,1.6))`

我收到这个错误:Error in is.data.frame(data) : object 'myClimateData' not found

这很奇怪,因为 lm 似乎找到了它并且 return 是正确的,并且应该找到 myClimateData,因为它是函数的参数之一,对吗?

这里有一个不对函数进行故障排除的解决方案getYeoJohsnonLambda:

iris.dat <- iris[-5]
vars <- names(iris.dat)
lmd <- seq(.1, 1, .1) #lambda_min, lambda_max, eps

all.form <- lapply(vars, function(x) as.formula(paste0(x, "~ 1")))
all.lm <- lapply(all.form, lm, data=iris.dat)

library(MASS)
all.bcox <- lapply(all.form, boxcox, data=iris.dat, 
            lambda=lmd, family="yjPower", plotit=FALSE)

遗憾的是,问题似乎出在函数 boxCox 而不是您的 getYeoJohsnonLambda 函数。作为 BrodieG pointed out in a related question,此函数使用 parent.frame 作为 eval 的参数,这在文档中被认为是不好的做法。

解决此问题的一种方法是在调用之前构建模型,如 Adam Quek 的回答中所建议:

library(car)

climateData <- data.frame(c(8.2,6.83,5.46,4.1,3.73,3.36,3,3,3,3,3.7),c(0,0.66,1.33,2,2,2,2,2,2,2,1.6))
names(climateData) <- c("a","b")

modelList <- list()
for(k in 1:ncol(climateData)) {
  modelList[[k]] <- lm(as.formula(paste0(names(climateData)[k],"~1")),data=climateData)
}

getYeoJohnsonLambda <- function(myClimateData, cols, lambda_min, lambda_max, eps)
{
  #Recommended values for lambda_min = -0.5 and lambda_max = 2.0, eps = 0.1
  myboxCox <- list()
  lmd <- seq(lambda_min,lambda_max,eps)
  for(i in cols)
  {
    cat("Creating model for column # ",i,"\n") 
    currentModel <- modelList[[i]]
    myboxCox[[i]] <- boxCox(currentModel, lambda = lmd ,family="yjPower", plotit = FALSE)

  }
  return(myboxCox)
}

test <- getYeoJohnsonLambda(climateData,c(1,2) ,-0.5,2,0.1)

其他解决方案(可以说更清洁):在 VGAM

中使用 yeo.johnson
library(VGAM)

getYeoJohnsonLambda_VGAM <- function(myClimateData, cols, lambda_min, lambda_max, eps)
{
  #Recommended values for lambda_min = -0.5 and lambda_max = 2.0, eps = 0.1
  myboxCox <- list()
  lmd <- seq(lambda_min,lambda_max,eps)
  return(apply(climateData,2,yeo.johnson,lambda=lmd))
}

test2 <- getYeoJohnsonLambda_VGAM(climateData,c(1,2) ,-0.5,2,0.1)