You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级mlogit与R版本后出现‘More than one idx column’报错的问询

问题:mlogit v1.1-3 报错 "More than one idx column"

背景代码流程

  1. 构建初始数据框:
data <- structure(list(personID = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), 
        problem = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), choice = c("Right", 
        "Right", "Left", "Middle", "Left", "Middle", "Right", "Right","Right"), 
        valueLeft = c(42.0570675657767, 45.9309219826825, 67.9396886866177, 72.9432649788673, 49.4515911099392, 50.4063604914605, 27.930814474658, 59.6351010950862, 62.4926813609122), 
        valueMiddle = c(44.8488506631671, 46.7573345964733, 34.8353743300335, 53.0737324797719, 53.6425649799281, 22.8107239238157, 70.9399442391851, 61.5264080883177, 52.5180668579461), 
        valueRight = c(63.1719866895542, 49.6082608281623, 62.155490653361, 63.5991448059925, 35.8780394435125, 48.0016025122861, 44.7708824302011, 53.0087719413007, 46.0633500203071)), 
        row.names = c(NA, -9L), class = "data.frame")
  1. 转换为dfidx格式:
data.logit <- dfidx(data, shape = "wide", 
                    choice = "choice", 
                    drop.index = TRUE,
                    id.var = "personID"
)
  1. 生成自变量并绑定:
indepvar <- c()
for (i in 1:length(data.logit$idx$id2)) {
  ifelse(data.logit$idx$id2[i]=="Left", indepvar[i] <- 
           data.logit$valueLeft[i], 
         ifelse(data.logit$idx$id2[i]=="Middle", indepvar[i] <- 
                  data.logit$valueMiddle[i],
                ifelse(data.logit$idx$id2[i]=="Right", indepvar[i] <- 
                         data.logit$valueRight[i], ""
                )))} 
indepvar <- data.frame(indepvar)
data.logit <- cbind(data.logit, indepvar)
remove(indepvar,i)
  1. 按problem字段拆分数据框到列表:
list_menus <- list()
for (i in 1:3) {
  list_menus[[paste0("Problem_",i)]] <- 
    dplyr::filter(data.logit, problem==i)
  remove(i)
}
  1. 尝试用mlogit批量估计模型时触发报错:
list_estimates <- list()
for (i in 1:length(list_menus)) {
  list_estimates[[i]] <- 
    mlogit(formula = choice ~ 1 + indepvar,
      data = list_menus[[i]],
       drop.index = TRUE,
       id.var = "personID")
  remove(i)
}

报错信息:

Error in idx_name.dfidx(x) : More than one idx column

该问题在mlogit v1.1-1 + R v4.4.1中未出现,升级到mlogit v1.1-3 + R v4.5.1后触发。


原因分析

mlogit v1.1-3对dfidx对象的索引列检查更严格:使用dplyr::filter拆分dfidx格式的数据框时,原有的idx属性会被保留,但拆分后的子数据框中,索引列(如personID对应的id列)会出现重复或冲突,导致mlogit识别到多个索引列,触发报错。


解决方法

方法1:拆分前转换为普通数据框

在拆分前将data.logit转换为普通data.frame,避免保留dfidx的索引属性,之后对每个子数据框单独调用dfidx转换:

# 转换为普通数据框
data.logit_df <- as.data.frame(data.logit)
# 拆分数据
list_menus <- list()
for (i in 1:3) {
  list_menus[[paste0("Problem_",i)]] <- 
    dplyr::filter(data.logit_df, problem==i)
}
# 批量估计模型
list_estimates <- list()
for (name in names(list_menus)) {
  # 对每个子数据框重新转换为dfidx格式
  temp_df <- dfidx(list_menus[[name]], shape = "wide", 
                   choice = "choice", 
                   drop.index = TRUE,
                   id.var = "personID")
  # 估计模型
  list_estimates[[name]] <- mlogit(choice ~ 1 + indepvar, data = temp_df)
}

方法2:手动重置子数据框的idx属性

如果要保留dfidx格式,拆分后手动重置每个子数据框的idx属性,确保只有一个有效索引列:

list_menus <- list()
for (i in 1:3) {
  temp <- dplyr::filter(data.logit, problem==i)
  # 重置idx属性,仅保留personID作为id变量
  attr(temp, "idx") <- dfidx(temp, shape = "wide", choice = "choice", 
                            drop.index = TRUE, id.var = "personID")$idx
  list_menus[[paste0("Problem_",i)]] <- temp
}
# 批量估计模型
list_estimates <- list()
for (i in seq_along(list_menus)) {
  list_estimates[[i]] <- mlogit(choice ~ 1 + indepvar, data = list_menus[[i]])
}

可选优化:简化自变量生成逻辑

原生成indepvar的循环可以替换为向量化操作,提升效率:

library(dplyr)
data.logit$indepvar <- with(data.logit, 
  case_when(
    idx$id2 == "Left" ~ valueLeft,
    idx$id2 == "Middle" ~ valueMiddle,
    idx$id2 == "Right" ~ valueRight
  )
)

内容的提问来源于stack exchange,提问作者user_xyz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 14:41:01