首页 > 解决方案 > partykit::mob() + mlogit: `错误没有指定合适的拟合函数`

问题描述

我正在尝试使用MOB 算法mlogit::mlogit()生成的树的末端叶子来拟合条件 logit 。显然,它不能直接使用该功能(在我的尝试之下)。但是,我找到了LORET算法,但是我找不到任何带有示例的文档,所以我尝试从源代码中猜测我需要哪个函数,但不幸的是,我无法让它工作。 partykit::mob()partykit::mob()

您是否知道 (1) 我可以在哪里找到 LORET 库的示例以及 (2) 是否可以使用该partykit:mob()函数与 LORET 一起使用mlogit::mlogit?提前致谢。


示例数据

为了说明,请仔细考虑以下数据。它表示来自 5 个个人 ( id_ind ) 的数据,他们在 3 个备选方案 ( altern) 中进行选择。五个人每人选择了三遍;因此我们有 15 种选择情况 ( id_choice)。每个备选方案由两个通用属性 (x1x2) 表示,并且选择注册在y(1如果选择,0否则)。最后,z1是一个候选分区变量。

df <- read.table(header = TRUE, text = "
id_ind id_choice altern           x1          x2 y
1       1         1      1  1.586788801  0.11887832 1
2       1         1      2 -0.937965347  1.15742493 0
3       1         1      3 -0.511504401 -1.90667519 0
4       1         2      1  1.079365680 -0.37267925 0
5       1         2      2 -0.009203032  1.65150370 1
6       1         2      3  0.870474033 -0.82558651 0
7       1         3      1 -0.638604013 -0.09459502 0
8       1         3      2 -0.071679538  1.56879334 0
9       1         3      3  0.398263302  1.45735788 1
10      2         4      1  0.291413453 -0.09107974 0
11      2         4      2  1.632831160  0.92925495 0
12      2         4      3 -1.193272276  0.77092623 1
13      2         5      1  1.967624379 -0.16373709 1
14      2         5      2 -0.479859282 -0.67042130 0
15      2         5      3  1.109780885  0.60348187 0
16      2         6      1 -0.025834772 -0.44004183 0
17      2         6      2 -1.255129594  1.10928280 0
18      2         6      3  1.309493274  1.84247199 1
19      3         7      1  1.593558740 -0.08952151 0
20      3         7      2  1.778701074  1.44483791 1
21      3         7      3  0.643191170 -0.24761157 0
22      3         8      1  1.738820924 -0.96793288 0
23      3         8      2 -1.151429915 -0.08581901 0
24      3         8      3  0.606695064  1.06524268 1
25      3         9      1  0.673866953 -0.26136206 0
26      3         9      2  1.176959443  0.85005871 1
27      3         9      3 -1.568225496 -0.40002252 0
28      4        10      1  0.516456176 -1.02081089 1
29      4        10      2 -1.752854918 -1.71728381 0
30      4        10      3 -1.176101700 -1.60213536 0
31      4        11      1 -1.497779616 -1.66301234 0
32      4        11      2 -0.931117325  1.50128532 1
33      4        11      3 -0.455543630 -0.64370825 0
34      4        12      1  0.894843784 -0.69859139 0
35      4        12      2 -0.354902281  1.02834859 0
36      4        12      3  1.283785176 -1.18923098 1
37      5        13      1 -1.293772990 -0.73491317 0
38      5        13      2  0.748091387  0.07453705 1
39      5        13      3 -0.463585127  0.64802031 0
40      5        14      1 -1.946438667  1.35776140 0
41      5        14      2 -0.470448172 -0.61326604 1
42      5        14      3  1.478763383 -0.66490028 0
43      5        15      1  0.588240775  0.84448489 1
44      5        15      2  1.131731049 -1.51323232 0
45      5        15      3  0.212145247 -1.01804594 0
")
df$z1 <- rnorm(n= nrow(df),mean = 0,sd = 1)

mlogit+partykit::mob()

library(mlogit)
library(partykit)
mo <-  mlogit(formula =  y ~ x1 + x2 , 
              data =  df,
              idx  =  c("id_choice", "altern"))
# Coefficients:
#   (Intercept):2  (Intercept):3             x1             x2  
#        0.036497       0.293254       0.821173       1.062794

mlogit_function <-  function(y, x,
                             offset = NULL,
                             ...){ mlogit(y ~  x ,
                                          data =  df)}
formula <-  y ~ x1 + x2 | z1 
mob(formula = formula,
    data    = df,
    fit     = mlogit_function,
    control = mob_control(minsize = 10, 
                          alpha = 0.01))
# Error in mob(formula = formula, data = df, fit = mlogit_function, control = mob_control(minsize = 10,  
# no suitable fitting function specified

mlogit+loret::multinomtree()

此函数运行树,但这不是我想要的,因为替代 2 缺少常量。

loret::multinomtree(formula = formula,
                    data = df)
# Model-based recursive partitioning (NULL)
# Model formula:
#   y ~ x1 + x2 | z1
# 
# Fitted party:
#   [1] root: n = 45
# 1:(Intercept)          1:x1          1:x2 
# -1.1046317     0.7663315     1.0418296  
# 
# Number of inner nodes:    0
# Number of terminal nodes: 1
# Number of parameters per node: 3
# Objective function: 22.62393

mlogit+loret::clmtree()

loret::clmtree(formula = formula,
               data = df)
# Error in clm.fit.default(y = c(1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L,  : 
#                                  is.list(y) is not TRUE

标签: rmachine-learningdecision-treeparty

解决方案


我没有完整的解决方案,但希望有足够的反馈可以帮助您入门:

  • 区分具有替代特定变量(您感兴趣)的所谓“条件 logit”模型和仅具有特定主题(或特定于个人)变量的经典“多项 logit 模型”非常重要。mlogit::mlogit()可以同时适用(也适用于混合版本),但nnet::multinom()仅支持后者。

  • 为了拟合条件 logit 模型,您可以使用长格式和宽格式的数据。您以长格式指定数据,并且还有一个z1特定于替代的拆分变量。这意味着来自同一个人的数据最终可能会出现在树的不同节点中,这将是相当尴尬的。

  • 相反,最好将数据采用宽格式,以便每一行对应一个个体,然后您可以只考虑个体特定的变量进行拆分。这也将匹配提供个体特定梯度贡献的拟合对象$gradient元素的视图。mlogit(这是sandwich::estfun()提取的内容,而这又是 的基本信息partykit::mob()。)

  • 也有可能基于替代特定变量进行合理的递归分区,但我发现很难看出这会产生什么样的模型以及这些模型意味着什么。在任何情况下,您都必须编写自己的代码来estfun从提供完全分解的替代特定梯度贡献的拟合模型对象中提取 。

  • loret软件包有些未完成,并且很长一段时间没有更新。因此,我目前不建议“在生产中”使用它。此外nnet::multinom()(underlying loret::multinomtree()) 不适合您需要的模型 (如上所述) 并且ordinal::clm()(underlying loret::clmtree()) 用于完全不同的模型。

  • 我们想要构建loret但尚未完成的一个特定方面是自动检测逻辑模型中的(准)完全分离并在树中适当地处理它。

  • 您的mlogit+partykit::mob()方法不起作用,因为拟合功能没有正确的界面(因为您被正确告知)。有关vignette("mob", package = "partykit")两个受支持的接口,请参阅。

  • 要编写适当的接口,您需要确保在每个子集中拥有所需的所有变量。请注意,响应变量加上回归矩阵是不够的,但您还需要索引变量!我建议通过y变量或xpartykit::mob(). mob_control()然后你可以设置ytype = "data.frame"和。xtype = "data.frame"然后两者yx都作为data.frame对象提供,并且可以在调用 之前再次组合mlogit::mlogit()。然后必须以某种方式提供formulaandidx参数。mlogit()在下面的示例中,我对它们进行了硬编码。

基于您的示例的说明:您可以设置一个模型拟合函数my_fit(),该函数期望yx成为数据框,然后使用formula = y ~ x1 + x2idx = c("id_choice", "altern")来拟合mlogit()模型。

my_fit <- function(y, x = NULL, start = NULL, weights = NULL, offset = NULL, ...) {
  mlogit::mlogit(formula = y ~ x1 + x2, data = cbind(y, x), idx = c("id_choice", "altern"))
}

要指定树,您需要通过公式的变量传递mlogit()模型的所有必需变量:xmob()

tr <- mob(y ~ x1 + x2 + id_choice + altern | z1, data = df, fit = my_fit,
  control = mob_control(ytype = "data.frame", xtype = "data.frame"))

从表面上看,这是可行的。至少它适合根节点中所需的模型,正如您通过检查看到的那样coef(tree)。但是,它起作用的唯一原因是它甚至没有尝试进行任何分区,因为与参数数量相比,样本量被判断为太小。

但是,当您另外设置minsize = 10mob_control(),分区过程将失败。这样做的原因是拆分变量的长度为 45,但梯度/estfunmlogit()的长度仅为 15。这是长的替代特定格式与短的个体特定格式。

因此,要使事情正常进行,您必须使用宽格式的数据,然后相应地调整mob()公式和mlogit()内部调用my_fit()


推荐阅读