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