【问题标题】:Multiple imputation and mlogit for a multinomial regression多项回归的多重插补和 mlogit
【发布时间】:2021-10-06 04:16:48
【问题描述】:

我正在尝试使用估算数据运行多项回归。我可以用 nnet 包做到这一点,但是我想使用 mlogit。使用 mlogit 包时,我不断收到以下错误“1:nrow(data) 中的错误:长度为 0 的参数”。

所以制作数据

library(mlogit)
library(nnet)
library(tidyverse)
library(mice)

df <- data.frame(vax = sample(1:6, 500, replace = T),
                 age = runif(500, 12, 18),
                 var1 = sample(1:2, 500, replace = T),
                 var2 = sample(1:5, 500, replace = T))

# Create missing data using the mice package:
df2 <- ampute(df, prop = 0.15)
df3 <- df2$amp

df3$vax <- as.factor(df3$vax)
df3$var1 <- as.factor(df3$var1)
df3$var2 <- as.factor(df3$var2)

# Inpute missing data:
df4 <- mice(df3, m = 5, print = T, seed = 123)

它使用 nnet 的 multinom 工作:

multinomtest <- with(df4, multinom(vax ~ age + var1 + var2, data = df, model = T))
summary(pool(multinomtest))

但是当我尝试将数据重塑为 mlogit 格式时会引发错误

test <- with(df4, dfidx(data = df4, choice = "vax", shape = "wide"))

有谁知道我如何将插补数据转换为 mlogit 格式,或者甚至 mlogit 是否与鼠标或任何其他插补包兼容?

【问题讨论】:

    标签: r statistics r-mice mlogit


    【解决方案1】:

    回答

    您错误地使用了with.mids,因此两行代码都是错误的; multinom 行只是没有给出错误。如果您想对估算数据集应用多个函数,最好使用lapply

    analyses <- lapply(seq_len(df4$m), function(i) {
      data.i <- complete(df4, i)
      data.idx <- dfidx(data = data.i, choice = "vax", shape = "wide")
      mlogit(vax ~ 1 | age + var1 + var2, 
             data = data.idx, 
             reflevel = "1", 
             nests = list(type1 = c("1", "2"), type2 = c("3","4"), type3 = c("5","6")))
    })
    test <- list(call = "", call1 = df4$call, nmis = df4$nmis, analyses = analyses)
    oldClass(test) <- c("mira", "matrix")
    summary(pool(test))
    

    with.mids 的工作原理

    当您将with 应用于mids 对象(又名mice::mice 的输出)时,您实际上是在调用with.mids

    如果你使用getAnywhere(with.mids)(或只输入mice:::with.mids),你会发现它做了几件事:

    1. 它循环遍历所有估算的数据集。
    2. 它使用complete 获取一个数据集。
    3. 它以数据集作为环境运行表达式。

    第三步是问题。对于使用公式的函数(如lmglmmultinom),您可以在给定环境中使用该公式。如果变量不在当前环境中(而是在例如数据框中),您可以通过设置 data 变量来指定新环境。


    问题

    这就是你的两个问题的根源:

    • 在您的multinom 调用中,您将data 变量设置为df。因此,您实际上是在原始 df 上运行 multinom不是估算数据集!

    • 在您的dfidx 通话中,您再次直接填写data。这也是错误的。但是,将其留空也会产生错误。这是因为with.mids 不填写data 参数,而只填写环境。这对你来说还不够。


    修复multinom

    multinom 行的解决方案很简单:只是不要指定 data

    multinomtest <- with(df4, multinom(vax ~ age + var1 + var2, model = T))
    summary(pool(multinomtest))
    

    如您所见,这将产生截然不同的结果!但重要的是要意识到这是您想要获得的。


    修复 dfidx(和 mlogit)

    我们无法对with.mids 执行此操作,因为它使用估算数据集作为环境,但您希望使用修改后的数据集(在dfidx 之后)作为您的环境。因此,我们必须编写自己的代码。您可以使用任何循环函数来执行此操作,例如lapply:

    analyses <- lapply(seq_len(df4$m), function(i) {
      data.i <- complete(df4, i)
      data.idx <- dfidx(data = data.i, choice = "vax", shape = "wide")
      mlogit(vax ~ 1 | age + var1 + var2, data = data.idx, reflevel = "1", nests = list(type1 = c("1", "2"), type2 = c("3","4"), type3 = c("5","6")))
    })
    

    从那里开始,我们要做的就是创建一个看起来像mira 的对象,这样我们仍然可以使用pool

    test <- list(call = "", call1 = df4$call, nmis = df4$nmis, analyses = analyses)
    oldClass(test) <- c("mira", "matrix")
    summary(pool(test))
    

    【讨论】:

      【解决方案2】:

      提供此方法以规避 dfidx() 的错误:

      df5 <- df4$imp %>% 
        # work with a list, where each top-element is a different imputation run (imp_n)
        map(~as.list(.x)) %>%
        transpose %>%
        # for each run, impute and return the full (imputed) data set
        map(function(imp_n.x) {
          df_out <- df4$data
          df_out$vax[is.na(df_out$vax)] <- imp_n.x$vax
          df_out$age[is.na(df_out$age)] <- imp_n.x$age
          df_out$var1[is.na(df_out$var1)] <- imp_n.x$var1
          df_out$var2[is.na(df_out$var2)] <- imp_n.x$var2
          return(df_out)
        }) %>%
        # No errors with dfidx() now
        map(function(imp_n.x) {
          dfidx(data = imp_n.x, choice = "vax", shape = "wide")
        })
      

      不过,我对mlogit() 不太熟悉,所以无能为力。

      21 年 8 月 2 日更新

      正如@slamballais 在他们的回答中提到的那样,问题在于您在拟合模型时引用的数据集。我假设mldata(来自您在 cmets 部分的代码)是一个 data.frame?这可能就是您看到相同系数的原因 - 您不是指估算的数据集(我在函数中将其标识为 imp_n.x)。函数purrr::map()lapply() 非常相似,您可以将函数应用于列表的元素。因此,为了让代码正常工作,您需要将 mldata 更改为 imp_n.x

      # To fit mlogit() for each imputed data set
      df5 %>%
        map(function(imp_n.x) {
          # form as specified in the comments
          mlogit(vax ~ 1 | age + var1 + var2, 
                 data = imp_n.x, 
                 reflevel = "1", 
                 nests = list(type1 = c('1', '2'), 
                              type2 = c('3','4'), 
                              type3 = c('5','6')))
        }) 
      

      【讨论】:

      • @Czechlnk 这行得通。我可以通过在管道上继续添加我的 mlogit 公式:'%>% map(function(imp_n.x) { mlogit(vax ~ 1 | age + var1 + var2, data = mldata, reflevel = "1", nests = list(type1 = c('1', '2'), type2 = c('3','4'), type3 = c('5','6'))) })'。我唯一的问题是每个插补的输出完全相同,就像我要在未插补的数据集上运行 mlgit 一样。人们会期望系数略有不同。我不确定 map(function(imp_n.x) 到底在做什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-10
      • 2022-01-14
      • 2021-07-11
      相关资源
      最近更新 更多