R: Как выполнить более сложные вычисления из combn набора данных?

прямо сейчас у меня есть combn из встроенного набора данных 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)

сама процедура достаточно проста, но я не смог найти способ сделать это для каждого combn в данных набор. (Как sidenote, adf.тест не будет применяться к таким данным, но я просто использую набор данных Iris для демонстрации). Мне интересно, было бы лучше написать цикл для такой процедуры?

3 ответов


вы можете сделать все это в 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

звучит так, как будто вы хотите написать свою собственную функцию и вызвать ее в цикле 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)

Я думаю, что это самый чистый способ. Но я не знаю, что именно вы хотите сделать, поэтому я придумал пример для распространения. Обратите внимание, что в моем примере вы получаете предупреждающие сообщения, так как столбец Species фактор.


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

кроме того, вы можете упростить 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).