多项回归的多重插补和 mlogit
Multiple imputation and mlogit for a multinomial regression
我正在尝试 运行 使用估算数据进行多项式回归。我可以用 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 的多项式工作:
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 是否与鼠标或任何其他插补包兼容?
提供此作为避免错误的方法 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
(来自评论部分的代码)是 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')))
})
回答
您使用的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
),您会发现它会做一些事情:
- 它遍历所有估算的数据集。
- 它使用
complete
得到一个数据集。
- 它以数据集作为环境运行表达式。
第三步是问题。对于使用公式(如 lm
、glm
和 multinom
)的函数,您可以在给定环境中使用该公式。如果变量不在当前环境中(而是在例如数据框中),您可以通过设置 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))
我正在尝试 运行 使用估算数据进行多项式回归。我可以用 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 的多项式工作:
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 是否与鼠标或任何其他插补包兼容?
提供此作为避免错误的方法 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
(来自评论部分的代码)是 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')))
})
回答
您使用的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
),您会发现它会做一些事情:
- 它遍历所有估算的数据集。
- 它使用
complete
得到一个数据集。 - 它以数据集作为环境运行表达式。
第三步是问题。对于使用公式(如 lm
、glm
和 multinom
)的函数,您可以在给定环境中使用该公式。如果变量不在当前环境中(而是在例如数据框中),您可以通过设置 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))