web-dev-qa-db-fra.com

Ajouter des variables en retard à un modèle lm?

J'utilise lm sur une série chronologique, qui fonctionne assez bien en fait, et c'est super super rapide.

Disons que mon modèle est:

> formula <- y ~ x

Je l'entraîne sur un set d'entraînement:

> train <- data.frame( x = seq(1,3), y = c(2,1,4) )
> model <- lm( formula, train )

... et je peux faire des prédictions pour de nouvelles données:

> test <- data.frame( x = seq(4,6) )
> test$y <- predict( model, newdata = test )
> test
  x        y
1 4 4.333333
2 5 5.333333
3 6 6.333333

Cela fonctionne très bien, et c'est vraiment rapide.

Je veux ajouter des variables retardées au modèle. Maintenant, je pourrais le faire en augmentant mon ensemble d’entraînement original:

> train$y_1 <- c(0,train$y[1:nrow(train)-1])
> train
  x y y_1
1 1 2   0
2 2 1   2
3 3 4   1

mettre à jour la formule:

formula <- y ~ x * y_1

... et la formation marchera très bien:

> model <- lm( formula, train )
> # no errors here

Cependant, le problème est qu’il n’ya aucun moyen d’utiliser «prédire», car il n’ya aucun moyen de renseigner y_1 dans un ensemble de tests par lots.

Maintenant, pour beaucoup d'autres choses de régression, il existe des moyens très pratiques de les exprimer dans la formule, tels que poly(x,2) et ainsi de suite, et ceux-ci fonctionnent directement à l'aide des données de test et de formation non modifiées.

Donc, je me demande s’il existe un moyen d’exprimer des variables décalées dans la formule, de sorte que predict puisse être utilisé? Idéalement:

formula <- y ~ x * lag(y,-1)
model <- lm( formula, train )
test$y <- predict( model, newdata = test )

... sans devoir augmenter (vous ne savez pas si c'est le bon mot) les jeux de données de formation et de test, et pouvoir simplement utiliser predict directement?

19
Hugh Perkins

Regardez par exemple le paquet dynlm qui vous donne des opérateurs de décalage. Plus généralement, les vues de tâches sur l'économétrie et les séries chronologiques vous en offriront beaucoup plus.

Voici le début de ses exemples - un décalage de un et douze mois:

R>      data("UKDriverDeaths", package = "datasets")
R>      uk <- log10(UKDriverDeaths)
R>      dfm <- dynlm(uk ~ L(uk, 1) + L(uk, 12))
R>      dfm

Time series regression with "ts" data:
Start = 1970(1), End = 1984(12)

Call:
dynlm(formula = uk ~ L(uk, 1) + L(uk, 12))

Coefficients:
(Intercept)     L(uk, 1)    L(uk, 12)  
      0.183        0.431        0.511  

R> 
13
Dirk Eddelbuettel

Suite à la suggestion de Dirk sur dynlm, je ne comprenais pas vraiment comment prédire, mais cela m'a conduit au paquet dyn via https://stats.stackexchange.com/questions/6758/1-step-ahead-predictions -with-dynlm-r-package

Après plusieurs heures d’expérimentation, j’ai trouvé la fonction suivante pour gérer la prédiction. Il y avait pas mal de trucs en route, par exemple vous ne sembliez pas pouvoir utiliser une série temporelle rbind, et le résultat de predict est compensé par start et tout un tas de choses de ce genre, alors je pense que cette réponse ajoute de manière significative par rapport à nommer un paquet, bien que j’ai voté pour la réponse de Dirk.

Ainsi, une solution qui fonctionne est la suivante:

  • utiliser le paquetage dyn
  • utiliser la méthode suivante pour la prédiction

méthode Predict:

# pass in training data, test data,
# it will step through one by one
# need to give dependent var name, so that it can make this into a timeseries
predictDyn <- function( model, train, test, dependentvarname ) {
    Ntrain <- nrow(train)
    Ntest <- nrow(test)
    # can't rbind ts's apparently, so convert to numeric first
    train[,dependentvarname] <- as.numeric(train[,dependentvarname])
    test[,dependentvarname] <- as.numeric(test[,dependentvarname])
    testtraindata <- rbind( train, test )
    testtraindata[,dependentvarname] <- ts( as.numeric( testtraindata[,dependentvarname] ) )
    for( i in 1:Ntest ) {
       result <- predict(model,newdata=testtraindata,subset=1:(Ntrain+i-1))
       testtraindata[Ntrain+i,dependentvarname] <- result[Ntrain + i + 1 - start(result)][1]
    }
    return( testtraindata[(Ntrain+1):(Ntrain + Ntest),] )
}

Exemple d'utilisation:

library("dyn")

# size of training and test data
N <- 6
predictN <- 10

# create training data, which we can get exact fit on, so we can check the results easily
traindata <- c(1,2)
for( i in 3:N ) { traindata[i] <- 0.5 + 1.3 * traindata[i-2] + 1.7 * traindata[i-1] }
train <- data.frame( y = ts( traindata ), foo = 1)

# create testing data, bunch of NAs
test <- data.frame( y = ts( rep(NA,predictN) ), foo = 1)

# fit a model
model <- dyn$lm( y ~ lag(y,-1) + lag(y,-2), train )
# look at the model, it's a perfect fit. Nice!
print(model)

test <- predictDyn( model, train, test, "y" )
print(test)

# Nice plot
plot(test$y, type='l')

Sortie:

> model

Call:
lm(formula = dyn(y ~ lag(y, -1) + lag(y, -2)), data = train)

Coefficients:
(Intercept)   lag(y, -1)   lag(y, -2)  
        0.5          1.7          1.3  

> test
             y foo
7     143.2054   1
8     325.6810   1
9     740.3247   1
10   1682.4373   1
11   3823.0656   1
12   8686.8801   1
13  19738.1816   1
14  44848.3528   1
15 101902.3358   1
16 231537.3296   1

Edit: hmmm, c'est quand même super lent. Même si je limite les données de la subset à quelques lignes constantes du jeu de données, cela prend environ 24 millisecondes par prédiction ou, pour ma tâche, 0.024*7*24*8*20*10/60/60 = 1.792 hours: -O

5
Hugh Perkins

Essayez la fonction ARIMA. Le paramètre AR est destiné à l'auto-régression, ce qui signifie un y décalé. xreg = vous permet d'ajouter d'autres variables X. Vous pouvez obtenir des prédictions avec Predict.ARIMA. 

1
PL84

Voici une pensée:

Pourquoi ne créez-vous pas un nouveau bloc de données? Remplissez un bloc de données avec les régresseurs dont vous avez besoin. Vous pouvez avoir des colonnes telles que L1, L2, ..., Lp pour tous les décalages de toutes les variables souhaitées, puis vous utilisez vos fonctions exactement comme vous le feriez pour un type de régression de type section transversale.

Étant donné que vous n’aurez pas à exploiter vos données à chaque fois que vous appelez des fonctions d’ajustement et de prédiction, mais que vous aurez transformé les données une fois, elles seront considérablement plus rapides. Je sais qu'Eviews et Stata fournissent des opérateurs en retard. Il est vrai que cela présente un certain confort. Mais il est également inefficace si vous n'avez pas besoin de tout, des fonctions telles que "lm" calcul. Si vous avez quelques centaines de milliers d'itérations à effectuer et que vous n'avez besoin que de la prévision ou de la valeur et de critères d'information tels que BIC ou AIC, vous pouvez battre "lm" en vitesse en évitant de faire des calculs que vous ne ferez utiliser - écrivez simplement un estimateur OLS dans une fonction et vous êtes prêt à partir.

0
Stéphane