已知断点的分段线性回归中斜率的标准误差

机器算法验证 r 回归 标准错误 分段线性
2022-03-23 12:09:29

情况

我有一个数据集,其中一个依赖和一个自变量我想拟合一个连续分段线性回归,其中个已知/固定断点发生在断点是已知的,没有不确定性,所以我不想估计它们。然后我拟合 这是一个例子yxk(a1,a2,,ak)

yi=β0+β1xi+β2max(xia1,0)+β3max(xia2,0)++βk+1max(xiak,0)+ϵi
R

set.seed(123)
x <- c(1:10, 13:22)
y <- numeric(20)
y[1:10] <- 20:11 + rnorm(10, 0, 1.5)
y[11:20] <- seq(11, 15, len=10) + rnorm(10, 0, 2)

假设断点出现在k19.6

mod <- lm(y~x+I(pmax(x-9.6, 0)))
summary(mod)

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)          21.7057     1.1726  18.511 1.06e-12 ***
x                    -1.1003     0.1788  -6.155 1.06e-05 ***
I(pmax(x - 9.6, 0))   1.3760     0.2688   5.120 8.54e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

两个段的截距和斜率分别为:第一个为 ,第二个分别为21.71.18.50.27

断点


问题

  1. 如何轻松计算每个段的截距和斜率?是否可以对模型进行重新参数化以在一次计算中执行此操作?
  2. 如何计算每个段的每个斜率的标准误差?
  3. 如何测试两个相邻的斜率是否相同(即断点是否可以省略)?
2个回答
  1. 如何轻松计算每个段的截距和斜率?

通过简单地将所有系数相加到当前位置来计算每个段的斜率。处的斜率估计x=151.1003+1.3760=0.2757

截距有点困难,但它是系数的线性组合(涉及结)。

在您的示例中,第二行在处与第一行相交,因此红点位于第一行的由于第二条线通过斜率,因此其截距为当然,您可以将这些步骤放在一起,它可以简化为第二段的截距 =x=9.621.70571.1003×9.6=11.1428(9.6,11.428)0.275711.14280.2757×9.6=8.496β0β2k1=21.70571.3760×9.6

可以重新参数化模型以在一次计算中执行此操作吗?

嗯,是的,但一般来说,从模型中计算它可能更容易。

2.如何计算每个段的每个斜率的标准误差?

由于估计是回归系数的线性组合,其中由 1 和 0 组成,因此方差为 标准误差是方差和协方差项之和的平方根。aβ^aaVar(β^)a

例如,在您的示例中,第二段斜率的标准误差为:

Sb <- vcov(mod)[2:3,2:3]
sqrt(sum(Sb))

或者以矩阵形式:

Sb <- vcov(mod)
a <- matrix(c(0,1,1),nr=3)
sqrt(t(a) %*% Sb %*% a)

3、如何测试相邻的两个斜率是否相同(即断点是否可以省略)?

这是通过查看该段表中的系数来测试的。看到这一行:

I(pmax(x - 9.6, 0))   1.3760     0.2688   5.120 8.54e-05 ***

这就是9.6 处的斜率变化。如果该变化不同于 0,则两个斜率不同。因此,第二段与第一段具有相同斜率的测试的 p 值正好位于该线的末尾。

我的天真方法,它回答了问题 1:

mod2 <- lm(y~I((x<9.6)*x)+as.numeric((x<9.6))+
             I((x>=9.6)*x)+as.numeric((x>=9.6))-1)
summary(mod2)

#                        Estimate Std. Error t value Pr(>|t|)    
# I((x < 9.6) * x)        -1.1040     0.2328  -4.743 0.000221 ***
# as.numeric((x < 9.6))   21.7188     1.3099  16.580 1.69e-11 ***
# I((x >= 9.6) * x)        0.2731     0.1560   1.751 0.099144 .  
# as.numeric((x >= 9.6))   8.5442     2.6790   3.189 0.005704 ** 

但是我不确定统计数据(特别是自由度)是否正确完成,如果你这样做的话。