R:如何从数据集的组合中执行更复杂的计算?

R: how to perform more complex calculations from a combn of a dataset?

现在,我有一个来自内置数据集 iris 的组合。到目前为止,我已经被引导能够找到这对值的 lm() 的系数。

myPairs <- combn(names(iris[1:4]), 2)

formula <- apply(myPairs, MARGIN=2, FUN=paste, collapse="~")

model <- lapply(formula, function(x) lm(formula=x, data=iris)$coefficients[2])

model

不过,我想更进一步,使用 lm() 的系数用于进一步的计算。我想做这样的事情:

Coefficient <- lm(formula=x, data=iris)$coefficients[2]
Spread <- myPairs[1] - coefficient*myPairs[2]
library(tseries)
adf.test(Spread)

程序本身很简单,但我还没有找到对数据集中的每个组合执行此操作的方法。 (作为旁注,adf.test 不会应用于此类数据,但我只是使用 iris 数据集进行演示)。 我想知道,为这样的过程编写一个循环会更好吗?

听起来您想编写自己的函数并在 myPairs 循环中调用它(应用):

yourfun <- function(pair){
  fm <- paste(pair, collapse='~')
  coef <- lm(formula=fm, data=iris)$coefficients[2]
  Spread <- iris[,pair[1]] - coef*iris[,pair[2]] 
  return(Spread)
} 

那么你可以调用这个函数:

model <- apply(myPairs, 2, yourfun)

我认为这是最干净的方式。但我不知道你到底想做什么,所以我正在为 Spread 编写示例。请注意,在我的示例中,您会收到警告消息,因为 Species 列是一个因素。

一些提示:我不会给你命名的东西与内置函数同名(modelformula 在你的原始版本中浮现在脑海中)。

此外,您可以简化您正在做的 paste - 请参阅下文。

最后,一个更笼统的声明:不要觉得所有事情都需要在某种 *apply 中完成。有时简洁和简短的代码实际上更难理解,请记住,*apply 函数最多只能提供相对于简单 for 循环的边际速度增益。 (R 并非总是如此,但在这一点上是这样。

# Get pairs
myPairs <- combn(x = names(x = iris[1:4]),m = 2)

# Just directly use paste() here
myFormulas <- paste(myPairs[1,],myPairs[2,],sep = "~")

# Store the models themselves into a list
# This lets you go back to the models later if you need something else
myModels <- lapply(X = myFormulas,FUN = lm,data = iris)

# If you use sapply() and this simple function, you get back a named vector
# This seems like it could be useful to what you want to do
myCoeffs <- sapply(X = myModels,FUN = function (x) {return(x$coefficients[2])})

# Now, you can do this using vectorized operations
iris[myPairs[1,]] - iris[myPairs[2,]] * myCoeffs[myPairs[2,]]

如果我没理解错的话,我相信上面的方法是可行的。请注意,目前输出中的名称将是无意义的,您需要将它们替换为您自己设计的内容(可能是 myFormulas 的值)。

您可以在 combn 内完成所有这些。

如果您只想运行对所有组合进行回归,并提取第二个系数,您可以这样做

fun <- function(x) coef(lm(paste(x, collapse="~"), data=iris))[2]
combn(names(iris[1:4]), 2, fun)

然后您可以扩展函数来计算点差

fun <- function(x) {
         est <- coef(lm(paste(x, collapse="~"), data=iris))[2]
         spread <- iris[,x[1]] - est*iris[,x[2]]
         adf.test(spread)
        }

out <- combn(names(iris[1:4]), 2, fun, simplify=FALSE)
out[[1]]

#   Augmented Dickey-Fuller Test

#data:  spread
#Dickey-Fuller = -3.879, Lag order = 5, p-value = 0.01707
#alternative hypothesis: stationary

将结果与 运行手动第一个结果进行比较

est <- coef(lm(Sepal.Length ~ Sepal.Width, data=iris))[2]
spread <- iris[,"Sepal.Length"] - est*iris[,"Sepal.Width"]
adf.test(spread)

#   Augmented Dickey-Fuller Test

# data:  spread
# Dickey-Fuller = -3.879, Lag order = 5, p-value = 0.01707
# alternative hypothesis: stationary