LFE软件包中felm的预测方法

25

有没有一种简洁的方法可以获得felm模型的predict行为?

library(lfe)
model1 <- lm(data = iris, Sepal.Length ~ Sepal.Width + Species)
predict(model1, newdata = data.frame(Sepal.Width = 3, Species = "virginica"))
# Works

model2 <- felm(data = iris, Sepal.Length ~ Sepal.Width | Species)
predict(model2, newdata = data.frame(Sepal.Width = 3, Species = "virginica"))
# Does not work

预测不起作用,因为它创建了felm类对象,而预测对其无效。 - Ajay Ohri
1
只是一点提醒,你不需要说“data(iris)”,因为鸢尾花数据已经被延迟加载了。 - Gregor Thomas
1
关于将预测添加到felm中,请创建一个请求到r-proj-c。
methods("predict") [1] predict.ar* predict.Arima* predict.arima0*
[4] predict.glm predict.HoltWinters* predict.lm
[7] predict.loess* predict.mlm* predict.nls*
[10] predict.poly* predict.ppr* predict.prcomp*
[13] predict.princomp* predict.smooth.spline* predict.smooth.spline.fit* [16] predict.StructTS*
- Ajay Ohri
我认为需要对felm()函数(以及它调用的函数)进行相当多的重新设计,因为当前的实现并没有存储固定效应系数,甚至似乎也没有截距 - 参见这个答案,这是一个与此问题至少非常相似的问题。 - duckmayr
6个回答

15

更新(2020-04-02):这个答案是由Grant提供的,使用新软件包fixest提供了更简洁的解决方案。

作为一种解决方法,您可以按照以下方式组合felmgetfedemeanlist

library(lfe)

lm.model <- lm(data=demeanlist(iris[, 1:2], list(iris$Species)), Sepal.Length ~ Sepal.Width)
fe <- getfe(felm(data = iris, Sepal.Length ~ Sepal.Width | Species))
predict(lm.model, newdata = data.frame(Sepal.Width = 3)) + fe$effect[fe$idx=="virginica"]

这个想法是使用demeanlist将变量居中,然后使用lm估计在使用居中变量时Sepal.Width的系数,从而得到一个lm对象,可以在其上运行predict。然后运行felm+getfe来获得固定效应的条件均值,并将其加到predict的输出中。


你如何为多个前端执行此操作? - wolfsatthedoor
你需要将另一个前端添加到demeanlist和getfe命令中,然后在最终总和中再添加另一个项。 - pbaylis
1
嗯,它并不像我想的那么通用。你不能使用我的代码来构建yhat的标准误差,置信区间或预测区间。我不知道如何做到这一点,所以我发布了一个类似于这个问题的问题,看看是否有其他人有想法。https://dev59.com/Yajka4cB1Zd3GeqPEdCs - pbaylis
为了支持这个答案,我认为他的问题并没有要求推断,只是点估计。但我同意你的观点,知道分布会更好。希望有人能回答另一个问题。 - wolfsatthedoor
1
不,我们想使用原始值,因为我们估计的系数仍然代表未居中模型中的相同内容。您可以通过在“lm”等效项上运行预测来进行双重检查: lm2 <- lm(data = iris, Sepal.Length ~ Sepal.Width + factor(Species)) predict(lm2, newdata = data.frame(Sepal.Width = 3, Species = "virginica")) - pbaylis
显示剩余2条评论

11

虽然有些晚,但新的fixest包(链接)具有可预测方法。它使用与lfe非常相似的语法支持高维固定效应(和聚类等)。令人惊讶的是,在我测试的基准案例中,它也比lfe快得多。

library(fixest)

model_feols <- feols(data = iris, Sepal.Length ~ Sepal.Width | Species)
predict(model_feols, newdata = data.frame(Sepal.Width = 3, Species = "virginica"))
# Works

6
这可能不是您要寻找的答案,但似乎作者没有为“lfe”包添加任何功能,以便使用已安装的“felm”模型对外部数据进行预测。主要关注点似乎在于固定效应组的分析。然而,在该软件包的文档中提到了以下内容值得注意:
“该对象类似于“lm”对象,并且为lm设计的一些后处理方法可能有效。但是,可能需要强制转换对象才能成功执行此操作。”
因此,可能可以将“felm”对象强制转换为“lm”对象,以获得一些额外的“lm”功能(如果对象中存在执行所需计算所需的所有必要信息)。
“lfe”软件包旨在运行在非常大的数据集上,并努力节省内存:由于这个直接结果,“felm”对象不使用/包含qr分解,与“lm”对象相反。不幸的是,“lm”“predict”过程依赖于此信息以计算预测。因此,强制转换“felm”对象并执行预测方法会失败:
> model2 <- felm(data = iris, Sepal.Length ~ Sepal.Width | Species)
> class(model2) <- c("lm","felm") # coerce to lm object
> predict(model2, newdata = data.frame(Sepal.Width = 3, Species = "virginica"))
Error in qr.lm(object) : lm object does not have a proper 'qr' component.
 Rank zero or should not have used lm(.., qr=FALSE).

如果您非常需要使用这个包来进行预测,那么您可以通过使用对象中可用的信息编写自己简化版本的功能。例如,OLS回归系数可以通过model2$coefficients获得。


有用的评论。谢谢。 - kennyB

4

如果您希望忽略预测中的群组效应、为新 X 进行预测并仅想要置信区间,那么这应该可以解决问题。它首先查找 clustervcv 属性,然后是 robustvcv,最后是 vcv

predict.felm <- function(object, newdata, se.fit = FALSE,
                         interval = "none",
                         level = 0.95){
  if(missing(newdata)){
    stop("predict.felm requires newdata and predicts for all group effects = 0.")
  }

  tt <- terms(object)
  Terms <- delete.response(tt)
  attr(Terms, "intercept") <- 0

  m.mat <- model.matrix(Terms, data = newdata)
  m.coef <- as.numeric(object$coef)
  fit <- as.vector(m.mat %*% object$coef)
  fit <- data.frame(fit = fit)

  if(se.fit | interval != "none"){
    if(!is.null(object$clustervcv)){
      vcov_mat <- object$clustervcv
    } else if (!is.null(object$robustvcv)) {
      vcov_mat <- object$robustvcv
    } else if (!is.null(object$vcv)){
      vcov_mat <- object$vcv
    } else {
      stop("No vcv attached to felm object.")
    }
    se.fit_mat <- sqrt(diag(m.mat %*% vcov_mat %*% t(m.mat)))
  }
  if(interval == "confidence"){
    t_val <- qt((1 - level) / 2 + level, df = object$df.residual)
    fit$lwr <- fit$fit - t_val * se.fit_mat
    fit$upr <- fit$fit + t_val * se.fit_mat
  } else if (interval == "prediction"){
    stop("interval = \"prediction\" not yet implemented")
  }
  if(se.fit){
    return(list(fit=fit, se.fit=se.fit_mat))
  } else {
    return(fit)
  }
}

3
为了扩展pbaylis的回答,我创建了一个稍微冗长的函数,可以很好地扩展以允许多个固定效应。请注意,您必须手动输入在felm模型中使用的原始数据集。该函数返回一个包含两个项目的列表:预测向量和基于新数据的数据框,其中包括预测和固定效应作为列。
predict_felm <- function(model, data, new_data) {

  require(dplyr)

  # Get the names of all the variables
  y <- model$lhs
  x <- rownames(model$beta)
  fe <- names(model$fe)

  # Demean according to fixed effects
  data_demeaned <- demeanlist(data[c(y, x)],
                             as.list(data[fe]),
                             na.rm = T)

  # Create formula for LM and run prediction
  lm_formula <- as.formula(
    paste(y, "~", paste(x, collapse = "+"))
  )

  lm_model <- lm(lm_formula, data = data_demeaned)
  lm_predict <- predict(lm_model,
                        newdata = new_data)

  # Collect coefficients for fe
  fe_coeffs <- getfe(model) %>% 
    select(fixed_effect = effect, fe_type = fe, idx)

  # For each fixed effect, merge estimated fixed effect back into new_data
  new_data_merge <- new_data
  for (i in fe) {

    fe_i <- fe_coeffs %>% filter(fe_type == i)

    by_cols <- c("idx")
    names(by_cols) <- i

    new_data_merge <- left_join(new_data_merge, fe_i, by = by_cols) %>%
      select(-matches("^idx"))

  }

  if (length(lm_predict) != nrow(new_data_merge)) stop("unmatching number of rows")

  # Sum all the fixed effects
  all_fixed_effects <- base::rowSums(select(new_data_merge, matches("^fixed_effect")))

  # Create dataframe with predictions
  new_data_predict <- new_data_merge %>% 
    mutate(lm_predict = lm_predict, 
           felm_predict = all_fixed_effects + lm_predict)

  return(list(predict = new_data_predict$felm_predict,
              data = new_data_predict))

}

model2 <- felm(data = iris, Sepal.Length ~ Sepal.Width | Species)
predict_felm(model = model2, data = iris, new_data = data.frame(Sepal.Width = 3, Species = "virginica"))
# Returns prediction and data frame

-2

我认为你可能需要的是lme4包。我能够使用它来实现预测:

library(lme4)
data(iris)

model2 <- lmer(data = iris, Sepal.Length ~ (Sepal.Width | Species))
predict(model2, newdata = data.frame(Sepal.Width = 3, Species = "virginica"))
       1 
6.610102 

你可能需要尝试一下来指定你想要的特定效果,但是这个软件包有很好的文档,所以不应该是问题。


这似乎无法复制上面的示例,并且在应该有model2的地方有results2。 - kennyB
修复了 results2 中的错误拼写。我看到这两个答案之间的差异为0.001,这可能只是由于两个模型实现方式略有不同所导致的。 - Tchotchke
仍然在我的电脑上似乎无法运行。我得到了这个错误Error: sum(nb) == q is not TRUE - kennyB
我更新了完整的代码(包括库和数据),并且在我的Mac和PC上都能正常运行。我在我的Mac上使用R 3.1.1。我不确定为什么它对你不起作用-我的原始想法是由于NA,但我们只在一个观察值上进行预测,所以这不应该是一个问题。 - Tchotchke
是的,这很奇怪。我正在使用3.2.0版本,也尝试了3.1.3版本。无论如何,你的回答并没有回答问题,问题明确要求felm模型的predict方法。 - kennyB
4
lmer实现随机效应,lfe实现固定效应。固定效应不会被收缩,因为目标通常是关于边际效应的推断,而不是预测。如果想拟合一个固定效应模型,不要使用'lmer'。 - generic_user

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接