代码之家  ›  专栏  ›  技术社区  ›  jay.sf

如何在逻辑中得到分类变量的边际效应?

  •  1
  • jay.sf  · 技术社区  · 7 年前

    我想计算 "mlogit" 解释变量为类别(因子)的对象。而数字数据 effects() 抛出一些东西,如果有分类数据,它不会。

    为了简单起见,我在下面给出了一个双变量的例子。

    数值变项

    # with mlogit
    library(mlogit)
    ml.dat <- mlogit.data(df3, choice="y", shape="wide")
    fit.mnl <- mlogit(y ~ 1 | x, data=ml.dat)
    
    head(effects(fit.mnl, covariate="x", data=ml.dat))
    #         FALSE       TRUE
    # 1 -0.01534581 0.01534581
    # 2 -0.01534581 0.01534581
    # 3 -0.20629452 0.20629452
    # 4 -0.06903946 0.06903946
    # 5 -0.24174312 0.24174312
    # 6 -0.39306240 0.39306240
    
    # with glm
    fit.glm <- glm(y ~ x, df3, family = binomial)
    
    head(effects(fit.glm))
    # (Intercept)           x                                                 
    #  -0.2992979  -4.8449254   2.3394989   0.2020127   0.4616640   1.0499595 
    

    因子变量

    # transform to factor
    df3F <- within(df3, x <- factor(x))
    class(df3F$x) == "factor"
    # [1] TRUE
    

    同时 glm() 还是扔东西,

    # with glm
    fit.glmF <- glm(y ~ x, df3F, family = binomial)
    
    head(effects(fit.glmF))
    # (Intercept)           x2           x3           x4           x5           x6 
    # 0.115076511 -0.002568206 -0.002568206 -0.003145397 -0.003631992 -0.006290794
    

    这个 mlogit() 方法

    # with mlogit
    ml.datF <- mlogit.data(df3F, choice="y", shape="wide")
    fit.mnlF <- mlogit(y ~ 1 | x, data=ml.datF)
    
    head(effects(fit.mnlF, covariate="x", data=ml.datF))
    

    投掷这个 错误 :

    Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : 
      contrasts can be applied only to factors with 2 or more levels
    In addition: Warning message:
    In Ops.factor(data[, covariate], eps) :
    
     Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : 
      contrasts can be applied only to factors with 2 or more levels 
    

    我怎么解决这个问题?

    我已经试图操纵 effects.mlogit() 具有 this answer 但这无助于解决我的问题。

    注: 这个问题与 this solution ,我想将其应用于分类解释变量。


    编辑

    (在将给定的解决方案应用于与上述问题相关的基础问题时演示该问题。请参阅评论。

    # new example ----
    library(mlogit)
    ml.d <- mlogit.data(df1, choice="y", shape="wide")
    ml.fit <- mlogit(y ~ 1 | factor(x), reflevel="1", data=ml.d)
    
    AME.fun2 <- function(betas) {
      aux <- model.matrix(y ~ x, df1)[, -1]
      ml.datF <- mlogit.data(data.frame(y=df1$y, aux), 
                             choice="y", shape="wide")
      frml <- mFormula(formula(paste("y ~ 1 |", paste(colnames(aux), 
                                                      collapse=" + "))))
      fit.mnlF <- mlogit(frml, data=ml.datF)
      fit.mnlF$coefficients <- betas  # probably?
      colMeans(effects(fit.mnlF, covariate="x2", data=ml.datF))  # first co-factor?
    }
    
    (AME.mnl <- AME.fun2(ml.fit$coefficients))
    
    require(numDeriv)
    grad <- jacobian(AME.fun2, ml.fit$coef)
    (AME.mnl.se <- matrix(sqrt(diag(grad %*% vcov(ml.fit) %*% t(grad))), 
                          nrow=3, byrow=TRUE))
    AME.mnl / AME.mnl.se
    #  doesn't work yet though...
    
    # probably "true" values, obtained from Stata:
    # # ame
    #         1      2      3      4      5
    # 1.     NA     NA     NA     NA     NA   
    # 2. -0.400  0.121 0.0971  0.113 0.0686   
    # 3. -0.500 -0.179 0.0390  0.166 0.474 
    #
    # # z-values
    #        1     2     3     4     5
    # 1.    NA    NA    NA    NA    NA
    # 2. -3.86  1.25  1.08  1.36  0.99
    # 3. -5.29 -2.47  0.37  1.49  4.06   
    

    数据

    df3 <- structure(list(x = c(11, 11, 7, 10, 9, 8, 9, 6, 9, 9, 8, 9, 11, 
    7, 8, 11, 12, 5, 8, 8, 11, 6, 13, 12, 5, 8, 7, 11, 8, 10, 9, 
    10, 7, 9, 2, 10, 3, 6, 11, 9, 7, 8, 4, 12, 8, 12, 11, 9, 12, 
    9, 7, 7, 7, 10, 4, 10, 9, 6, 7, 8, 9, 13, 10, 8, 10, 6, 7, 10, 
    9, 6, 4, 6, 6, 8, 6, 9, 3, 7, 8, 2, 8, 6, 7, 9, 10, 8, 6, 5, 
    5, 7, 9, 1, 6, 11, 11, 9, 7, 8, 9, 9), y = c(TRUE, TRUE, TRUE, 
    TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, 
    TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, 
    TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, 
    TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, 
    TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, 
    TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, 
    FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 
    FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, 
    FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, 
    TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE
    )), class = "data.frame", row.names = c(NA, -100L))
    
    > summary(df3)
           x             y          
     Min.   : 1.00   Mode :logical  
     1st Qu.: 7.00   FALSE:48       
     Median : 8.00   TRUE :52       
     Mean   : 8.08                  
     3rd Qu.:10.00                  
     Max.   :13.00  
    
    df1 <- structure(list(y = c(5, 4, 2, 2, 2, 3, 5, 4, 1, 1, 2, 4, 1, 4, 
    5, 5, 2, 3, 3, 5, 5, 3, 2, 4, 5, 1, 3, 3, 4, 3, 5, 2, 4, 4, 5, 
    5, 5, 2, 1, 5, 1, 3, 1, 4, 1, 2, 2, 4, 3, 1, 4, 3, 1, 1, 5, 2, 
    5, 4, 2, 2, 4, 2, 3, 5, 4, 1, 2, 2, 3, 5, 2, 5, 3, 3, 3, 1, 3, 
    1, 1, 4, 3, 4, 5, 2, 1, 1, 3, 1, 5, 4, 4, 2, 5, 3, 4, 4, 3, 1, 
    5, 2), x = structure(c(2L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 
    2L, 1L, 1L, 2L, 2L, 3L, 2L, 2L, 2L, 2L, 3L, 2L, 2L, 3L, 3L, 2L, 
    3L, 2L, 2L, 2L, 3L, 2L, 1L, 3L, 2L, 3L, 3L, 1L, 1L, 3L, 2L, 2L, 
    1L, 2L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 1L, 2L, 2L, 3L, 2L, 
    2L, 2L, 3L, 2L, 3L, 1L, 2L, 1L, 2L, 2L, 1L, 3L, 2L, 2L, 1L, 2L, 
    2L, 1L, 3L, 1L, 1L, 2L, 2L, 3L, 3L, 2L, 2L, 1L, 1L, 1L, 3L, 2L, 
    3L, 2L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 2L), .Label = c("1", "2", 
    "3"), class = "factor")), row.names = c(NA, -100L), class = "data.frame")
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Julius Vainora    7 年前

    有点期待 effects 不适用于因子,因为否则输出将包含另一个维度,使结果有些复杂,并且非常合理,就像下面的解决方案一样,人们可能只希望对某个因子级别而不是所有级别产生效果。此外,正如我下面解释的,分类变量的边际效应并不是唯一定义的,因此这将是 影响 .

    一个自然的解决方法是手动将因子变量转换为一系列虚拟变量,如

    aux <- model.matrix(y ~ x, df3F)[, -1]
    head(aux)
    #   x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13
    # 1  0  0  0  0  0  0  0  0   0   1   0   0
    # 2  0  0  0  0  0  0  0  0   0   1   0   0
    # 3  0  0  0  0  0  1  0  0   0   0   0   0
    # 4  0  0  0  0  0  0  0  0   1   0   0   0
    # 5  0  0  0  0  0  0  0  1   0   0   0   0
    # 6  0  0  0  0  0  0  1  0   0   0   0   0
    

    所以数据就是

    ml.datF <- mlogit.data(data.frame(y = df3F$y, aux), choice = "y", shape = "wide")
    

    我们还需要用

    frml <- mFormula(formula(paste("y ~ 1 |", paste(colnames(aux), collapse = " + "))))
    

    到现在为止,一直都还不错。现在如果我们运行

    fit.mnlF <- mlogit(frml, data = ml.datF)
    head(effects(fit.mnlF, covariate = "x2", data = ml.datF))
    #           FALSE         TRUE
    # 1 -1.618544e-15 0.000000e+00
    # 2 -1.618544e-15 0.000000e+00
    # 3 -7.220891e-08 7.221446e-08
    # 4 -1.618544e-15 0.000000e+00
    # 5 -5.881129e-08 5.880851e-08
    # 6 -8.293366e-08 8.293366e-08
    

    那么结果就不正确了。什么 影响 这是它看到的吗 x2 作为一个 连续的 变量,并计算这些情况的通常边际效应。也就是说,如果系数与 X2 是b2,我们的型号是f(x,b2)。 影响 计算f相对于b2的导数,并在每个观测向量x处进行评估。 . 这是错误的,因为 X2 只取值0和1,而不是0或1左右的值,这是取导数所假定的(极限的概念)!例如,考虑您的其他数据集 df1 . 在这种情况下,我们错误地得到

    colMeans(effects(fit.mnlF, covariate = "x2", data = ml.datF))
    #           1           2           3           4           5 
    # -0.25258378  0.07364406  0.05336283  0.07893391  0.04664298
    

    下面是另一种方法(使用导数近似法)来得到这个错误的结果:

    temp <- ml.datF
    temp$x2 <- temp$x2 + 0.0001
    colMeans(predict(fit.mnlF, newdata = temp, type = "probabilities") - 
                 predict(fit.mnlF, newdata = ml.datF, type = "probabilities")) / 0.0001
    #           1           2           3           4           5 
    # -0.25257597  0.07364089  0.05336032  0.07893273  0.04664202 
    

    而不是使用 影响 我用手工计算了错误的边际效应 predict 两次:结果是平均值(拟合概率,其中X2new=X2old+0.0001-拟合概率,其中X2new=X2old)/0.0001。也就是说,我们通过移动观察预测概率的变化 X2 上升0.0001,即从0到0.0001或从1到0.0001。这两个都没有道理。当然,我们不应该期望 影响 自从 X2 数据中是数字。

    那么问题是如何计算右(平均)边际效应。正如我所说,分类变量的边际效应并不是唯一定义的。假设x i是指我是否有工作,y i是指他们是否有车。所以,至少要考虑以下六件事。

    1. 从x_i=0到x_i=1对y_i=1概率的影响。
    2. 从x_i=0到x_i(观察值)时。
    3. 从XII I到1。

    现在,当我们对平均边际效应感兴趣时,我们可能只想对那些1-3的变化有影响的个体进行平均。也就是说,

    1. 如果观测值不是1,则从x_i=0到x_i=1。
    2. 如果观测值不是0,则从x_i=0到x_i。
    3. 如果观测值不是1,则从x_i到1。

    根据您的结果,Stata使用选项5,因此我将复制相同的结果,但实现任何其他选项都很简单,我建议您考虑在特定应用程序中哪些选项比较有趣。

    AME.fun2 <- function(betas) {
      aux <- model.matrix(y ~ x, df1)[, -1]
      ml.datF <- mlogit.data(data.frame(y = df1$y, aux), choice="y", shape="wide")
      frml <- mFormula(formula(paste("y ~ 1 |", paste(colnames(aux), collapse=" + "))))
      fit.mnlF <- mlogit(frml, data = ml.datF)
      fit.mnlF$coefficients <- betas
      aux <- ml.datF # Auxiliary dataset
      aux$x3 <- 0 # Going from 0 to the observed x_i
      idx <- unique(aux[aux$x3 != ml.datF$x3, "chid"]) # Where does it make a change?
      actual <- predict(fit.mnlF, newdata = ml.datF)
      counterfactual <- predict(fit.mnlF, newdata = aux)
      colMeans(actual[idx, ] - counterfactual[idx, ])
    }
    (AME.mnl <- AME.fun2(ml.fit$coefficients))
    #           1           2           3           4           5 
    # -0.50000000 -0.17857142  0.03896104  0.16558441  0.47402597 
    
    require(numDeriv)
    grad <- jacobian(AME.fun2, ml.fit$coef)
    AME.mnl.se <- matrix(sqrt(diag(grad %*% vcov(ml.fit) %*% t(grad))), nrow = 1, byrow = TRUE)
    AME.mnl / AME.mnl.se
    #           [,1]      [,2]    [,3]     [,4]     [,5]
    # [1,] -5.291503 -2.467176 0.36922 1.485058 4.058994