如何在 GLM 或 R 中的类似模型中指定/限制系数的符号

机器算法验证 r 贝叶斯 广义线性模型 预测模型
2022-03-22 01:58:24

情况:我正在努力使用广义线性模型对食品销售价格进行预测分析。我的数据集包含不同种类的食物(奶酪、蔬菜、肉类、香料等),因此在进行分析时,我将数据集完全按照这些种类进行拆分,因为它们本质上非常不同。

当前模型:数据集/模型包含诸如“生产国”之类的因素和诸如“运输距离”之类的数字变量,这些变量都在基于伽马的 GLM i R 中使用。

问题:现在总的来说,我的模型非常适合,但有时在极少数情况下,某些度量变量会得到与您预期相反的符号 (+/-),因为该模型会以某种方式捕捉其他影响。

一个例子:一个例子是香料。所有香料都具有相对较长的“运输距离”和相对较长的保质期,因此与肉类等相比对销售价格的影响非常小。所以在这种情况下,模型可能会意外地最终给“运输距离”变量一个小但负的值——这是错误的,因为这意味着食品运输的距离越长,价格就越低。

我的问题:如果我不想使用类似于 GLM 模型的模型,但我希望能够指定对某些变量/系数的限制,我应该在 R 中使用哪种模型?例如,如果我想说增加“运输距离”应该总是对销售价格产生积极影响?

想法:我听说过有关“贝叶斯 GLM”模型或使用所谓的“先验分布”的一些信息,但我不知道哪一个(如果有的话)最适合使用..?

更新 @ACD 下面的答案不是我正在寻找的。我不需要解释为什么会发生这种情况,我需要一个限制系数符号的解决方案:-)

3个回答

您可以通过将模型指定为结构方程模型并添加约束在 R 中使用 Lavaan 来执行此操作。我不确定这是否是个好主意,但可以做到。

#load library and generate some data
library(lavaan)

d <- as.data.frame(matrix(rnorm(1:3000), ncol=3, dimnames=list(NULL, c("y", "x1", "x2"))))

使用 GLM 运行它:

> summary(glm(y ~ x1 + x2, data=d))

Call:
glm(formula = y ~ x1 + x2, data = d)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-3.6385  -0.5899  -0.0224   0.6024   3.0131  

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.01855    0.03021  -0.614    0.539
x1           0.01208    0.03049   0.396    0.692
x2          -0.03676    0.03021  -1.217    0.224

(Dispersion parameter for gaussian family taken to be 0.912437)

    Null deviance: 911.2  on 999  degrees of freedom
Residual deviance: 909.7  on 997  degrees of freedom
AIC: 2751.2

然后用 lavaan 运行相同的模型,检查等价性:

> model1.syntax <- '
+ y ~ x1 + x2
+ '
> summary(sem(model1.syntax, data=d))
lavaan (0.5-14) converged normally after   1 iterations

  Number of observations                          1000

  Estimator                                         ML
  Minimum Function Test Statistic                0.000
  Degrees of freedom                                 0
  P-value (Chi-square)                           1.000

Parameter estimates:

  Information                                 Expected
  Standard Errors                             Standard

                   Estimate  Std.err  Z-value  P(>|z|)
Regressions:
  y ~
    x1                0.012    0.030    0.397    0.691
    x2               -0.037    0.030   -1.219    0.223

Variances:
    y                 0.910    0.041

然后在 lavaan 中,通过命名参数并添加约束部分来添加约束:

> model2.syntax <- '
+ y ~ b1 * x1 + b2 * x2
+ '
> 
> model2.constraints <- 
+   ' 
+     b1 > 0
+     b2 > 0
+   '
> 
> summary(sem(model=model2.syntax, constraints=model2.constraints, data=d))
lavaan (0.5-14) converged normally after   1 iterations

  Number of observations                          1000

  Estimator                                         ML
  Minimum Function Test Statistic                1.484
  Degrees of freedom                                 0
  P-value (Chi-square)                           0.000

Parameter estimates:

  Information                                 Observed
  Standard Errors                             Standard

                   Estimate  Std.err  Z-value  P(>|z|)
Regressions:
  y ~
    x1       (b1)     0.012       NA
    x2       (b2)     0.000       NA

Variances:
    y                 0.911    0.041

Constraints:                               Slack (>=0)
    b1 - 0                                       0.012
    b2 - 0                                       0.000

b2 参数不是负数,而是固定为零。

请注意,您没有得到任何标准错误 - 如果您想要它们,您必须引导。(这在 lavaan 手册中有描述)。

您知道为正的事物的负估计系数来自省略的变量偏差和/或回归变量之间的共线性。

对于预测,这不是那么成问题,只要您对新数据进行抽样以预测与您的样本相同的总体的结果(价格?)。负系数的出现是因为变量与其他因素高度相关,从而使系数估计值高度可变,或者因为它与模型中省略的重要因素相关,而负号表示该因素的影响。

但听起来你也在尝试进行推理——外生变化有多大X改变Y. 因果推理统计使用不同的方法,并且与预测统计具有不同的优先级。它在计量经济学中特别发达。基本上,您需要找到可以说服自己的策略E(β^|X,whatever)=β,这通常涉及确保感兴趣的回归量与误差项不相关,这通常是通过控制可观察量(或某些情况下的不可观察量)来实现的。但是,即使您达到了这一点,共线性仍然会给您带来高度可变的系数,但是您知道为正的事物的负号通常会带来巨大的标准误差(假设没有遗漏的变量偏差)。

编辑:如果你的模型是

price=g1(α+countryβ+γdistance+whatever+ϵ)

那么国家将与距离相关。因此,如果您在塔吉克斯坦并且从瓦努阿图获得香料,那么瓦努阿图的系数将非常高。在控制了所有这些国家影响后,距离的额外影响可能不是积极的。在这种情况下,如果您想进行推理而不是预测(并且认为您可以指定和估计一个给出因果解释的模型),那么您可以取出国家变量。

对于将来的参考,如果您不介意切换到套索类型 glm,您可以使用带有参数的 cv.glmnetlower.limits来指定哪些参数不应低于 0

它还具有从拟合中消除大量虚假相关性的良好特性:使用作为参考模型,具有 lambda = "lambda.1se" 的模型所有不真正相关的参数,基于交叉验证,将设置为 0。

根据我对具有类似问题的数据集的经验,只需切换到套索就可以修复大部分负值,显然设置 lower.limits 可以解决所有问题。