Скользящая регрессия и предсказание с помощью lm() и predict()

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

fit model      predict
----------     -------
dat[1:3, ]     dat[4, ]
dat[1:4, ]     dat[5, ]
    .             .
    .             .
dat[-1, ]      dat[nrow(dat), ]

Я знаю, что мне делать для определенного подмножества (связанного с этим вопросом: predict() и newdata - как это работает?). Например, чтобы предсказать последнюю строку, я делаю

dat1 = dat[1:(nrow(dat)-1), ]
dat2 = dat[nrow(dat), ]

fit = lm(log(clicks) ~ log(v1) + log(v12), data=dat1)
predict.fit = predict(fit, newdata=dat2, se.fit=TRUE)

Как я могу сделать это автоматически для всех подмножеств и потенциально извлечь то, что я хочу, в таблицу?

  • Из fit мне понадобится summary(fit)$adj.r.squared;
  • Из predict.fit мне нужно predict.fit$fit значение.

Спасибо.


person JohnnyDeer    schedule 26.06.2016    source источник
comment
Я добавил пример того, как создать таблицу результатов из вывода, пожалуйста, проверьте его. Я сделал это только для 1 из 3 типов объектов вывода, которые создает мое решение, но одна и та же методология работает для всех 3.   -  person Hack-R    schedule 26.06.2016


Ответы (2)


(Эффективное) решение

Вот что вы можете сделать:

p <- 3  ## number of parameters in lm()
n <- nrow(dat) - 1

## a function to return what you desire for subset dat[1:x, ]
bundle <- function(x) {
  fit <- lm(log(clicks) ~ log(v1) + log(v12), data = dat, subset = 1:x, model = FALSE)
  pred <- predict(fit, newdata = dat[x+1, ], se.fit = TRUE)
  c(summary(fit)$adj.r.squared, pred$fit, pred$se.fit)
  }

## rolling regression / prediction
result <- t(sapply(p:n, bundle))
colnames(result) <- c("adj.r2", "prediction", "se")

Обратите внимание, что я сделал несколько вещей внутри функции bundle:

  • Я использовал аргумент subset для выбора подмножества, которое подходит
  • Я использовал model = FALSE, чтобы не сохранять кадр модели, поэтому мы сохраняем рабочее пространство.

В целом, очевидной петли нет, но используется sapply.

  • Подгонка начинается с p, минимального количества данных, необходимых для подбора модели с p коэффициентами;
  • Подгонка заканчивается на nrow(dat) - 1, так как нам как минимум нужен последний столбец для предсказания.

Тест

Пример данных (с 30 «наблюдениями»)

dat <- data.frame(clicks = runif(30, 1, 100), v1 = runif(30, 1, 100),
                  v12 = runif(30, 1, 100))

Применение кода выше дает results (всего 27 строк, усеченный вывод для 5 строк)

            adj.r2 prediction        se
 [1,]          NaN   3.881068       NaN
 [2,]  0.106592619   3.676821 0.7517040
 [3,]  0.545993989   3.892931 0.2758347
 [4,]  0.622612495   3.766101 0.1508270
 [5,]  0.180462206   3.996344 0.2059014

Первый столбец представляет собой скорректированное значение R.squared для подобранной модели, а второй столбец представляет собой прогноз. Первое значение для adj.r2 равно NaN, потому что первая модель, которую мы подогнали, имеет 3 коэффициента для 3 точек данных, поэтому разумная статистика недоступна. То же самое происходит и с se, поскольку подобранная линия не имеет нулевых остатков, поэтому прогноз выполняется без неопределенности.

person Zheyuan Li    schedule 26.06.2016
comment
Возможно, вы могли бы ответить мне на последний вопрос? - person JohnnyDeer; 28.06.2016

Я просто создал случайные данные для этого примера. Я называю объект data, потому что именно так он назывался в вопросе в то время, когда я писал это решение (назовите его как угодно).

(Эффективное) решение

data <- data.frame(v1=rnorm(100),v2=rnorm(100),clicks=rnorm(100))

data1 = data[1:(nrow(data)-1), ]
data2 = data[nrow(data), ]

for(i in 3:nrow(data)){
  nam  <- paste("predict", i, sep = "")
  nam1 <- paste("fit", i, sep = "")
  nam2 <- paste("summary_fit", i, sep = "")

  fit = lm(clicks ~ v1 + v2, data=data[1:i,])
  tmp  <- predict(fit, newdata=data2, se.fit=TRUE)
  tmp1 <- fit
  tmp2 <- summary(fit)
  assign(nam, tmp)
  assign(nam1, tmp1)
  assign(nam2, tmp2)
}

Все нужные вам результаты будут сохранены в создаваемых объектах данных.

Например:

> summary_fit10$r.squared
[1] 0.3087432

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

rm(data,data1,data2,i,nam,nam1,nam2,fit,tmp,tmp1,tmp2)
frames <- ls()

frames.fit     <- frames[1:98] #change index or use pattern matching as needed
frames.predict <- frames[99:196]
frames.sum     <- frames[197:294]

fit.table <- data.frame(intercept=NA,v1=NA,v2=NA,sourcedf=NA)
for(i in 1:length(frames.fit)){
  tmp <- get(frames.fit[i])
  fit.table              <- rbind(fit.table,c(tmp$coefficients[[1]],tmp$coefficients[[2]],tmp$coefficients[[3]],frames.fit[i]))
}

fit.table

> fit.table
             intercept                   v1                   v2 sourcedf
2  -0.0647017971121678     1.34929652763687   -0.300502017324518    fit10
3  -0.0401617893034109   -0.034750571912636  -0.0843076273486442   fit100
4   0.0132968863522573     1.31283604433593   -0.388846211083564    fit11
5   0.0315113918953643     1.31099122173898   -0.371130010135382    fit12
6    0.149582794027583    0.958692838785998   -0.299479715938493    fit13
7  0.00759688947362175    0.703525856001948   -0.297223988673322    fit14
8    0.219756240025917    0.631961979610744   -0.347851129205841    fit15
9     0.13389223748979    0.560583832333355   -0.276076134872669    fit16
10   0.147258022154645    0.581865844000838   -0.278212722024832    fit17
11  0.0592160359650468    0.469842498721747   -0.163187274356457    fit18
12   0.120640756525163    0.430051839741539   -0.201725012088506    fit19
13   0.101443924785995     0.34966728554219   -0.231560038360121    fit20
14  0.0416637001406594    0.472156988919337   -0.247684504074867    fit21
15 -0.0158319749710781    0.451944113682333   -0.171367482879835    fit22
16 -0.0337969739950376    0.423851304105399   -0.157905431162024    fit23
17  -0.109460218252207     0.32206642419212   -0.055331391802687    fit24
18  -0.100560410735971    0.335862465403716  -0.0609509815266072    fit25
19  -0.138175283219818    0.390418411384468  -0.0873106257144312    fit26
20  -0.106984355317733    0.391270279253722  -0.0560299858019556    fit27
21 -0.0740684978271464    0.385267011513678  -0.0548056844433894    fit28
person Hack-R    schedule 26.06.2016
comment
Пока выглядит хорошо, но как я могу увидеть значения или таблицу прогнозов? Проведя некоторое исследование, rollapply также может быть вариантом, но, к сожалению, я слишком новичок, чтобы иметь дело с этим. - person JohnnyDeer; 26.06.2016
comment
@JohnnyDeer Да, есть несколько функций скользящей регрессии, которые вы могли бы использовать, но они вам действительно не нужны для этого. Нужные вам результаты находятся в наборах данных, которые это создает, и вы можете увидеть их с помощью str(predict3) или путем доступа ко всему объекту или его элементам. Если вам нужна таблица результатов, это не проблема, но, пожалуйста, задайте для нее отдельный вопрос. Использование str описывает структуру, чтобы вы знали, как получить программный доступ к нужным элементам. - person Hack-R; 26.06.2016
comment
@JohnnyDeer Я также собираюсь сделать обновление, чтобы предоставить больше информации в выходных наборах данных. Посмотрите сейчас. - person Hack-R; 26.06.2016
comment
@JohnnyDeer снова обновлен, чтобы дать вам пример таблицы результатов - person Hack-R; 26.06.2016