如何参数化分段回归系数以表示以下间隔的斜率(而不是斜率的变化)

How to parametrize piecewise regression coefficient to represent the slope for the following interval (instead of the change in the slope)

考虑以下数据集

Quantity <- c(25,39,45,57,70,85,89,100,110,124,137,150,177)
Sales <- c(1000,1250,2600,3000,3500,4500,5000,4700,4405,4000,3730,3400,3300)
df <- data.frame(Quantity,Sales)
df

绘制数据,观测值的分布显然是非线性的,但在 Quantity = 89 附近呈现出可能的断点(我在此处跳过该图)。因此,我建立了一个联合分段线性模型如下

df$Xbar <- ifelse(df$Quantity>89,1,0)
df$diff <- df$Quantity - 89

reg <- lm(Sales ~ Quantity + I(Xbar * (Quantity - 89)), data = df)
summary(reg)

或者干脆

df$X <- df$diff*df$Xbar

reg <- lm(Sales ~ Quantity + X, data = df)
summary(reg)   

然而,根据这个参数化,X 的系数表示斜率相对于前一个区间的变化。

如何将相关系数参数化以表示第二个区间的斜率?

我做了一些研究,但除了 stata 中的一些自动化之外,我无法找到所需的规范(请参阅此处的语音 'marginal' https://www.stata.com/manuals13/rmkspline.pdf)。

非常感谢任何帮助。谢谢!

致谢: 可行的例子是从 https://towardsdatascience.com/unraveling-spline-regression-in-r-937626bc3d96

如果你知道断点,那么模型就差不多了,应该是:

fit=lm(Sales ~ Quantity + Xbar + Quantity:Xbar,data=df)

因为如果你不引入新的截距(Xbar),它会从模型中已有的截距开始,这是行不通的。我们可以绘制它:

plot(df$Quantity,df$Sales)
newdata = data.frame(Quantity=seq(40,200,by=5))
newdata$Xbar= ifelse(newdata$Quantity>89,1,0)
lines(newdata$Quantity,predict(fit,newdata))

系数为:

summary(fit)

Call:
lm(formula = Sales ~ Quantity * Xbar, data = df)

Residuals:
   Min     1Q Median     3Q    Max 
-527.9 -132.2  -15.1  148.1  464.7 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)   -545.435    327.977  -1.663    0.131    
Quantity        59.572      5.746  10.367 2.65e-06 ***
Xbar          7227.288    585.933  12.335 6.09e-07 ***
Quantity:Xbar  -80.133      6.856 -11.688 9.64e-07 ***

第二个斜率的系数是59.572+(-80.133) = -20.561

这里的关键是使用一个逻辑变量is.right,它对于 89 右边的点为 TRUE,否则为 FALSE。

从显示的输出来看,60.88 是 89 左侧的斜率,-19.97 是右侧的斜率。这些线相交于数量 = 89,销售额 = 4817.30。

is.right <- df$Quantity > 89
fm <- lm(Sales ~ diff : is.right, df)

fm
## Call:
## lm(formula = Sales ~ diff:is.right, data = df)
##
## Coefficients:
##        (Intercept)  diff:is.rightFALSE   diff:is.rightTRUE  
##            4817.30               60.88              -19.97  

备选方案

或者,如果您想使用问题中的 Xbar,请按此方式进行。它给出与 fm.

相同的系数
fm2 <- lm(Sales ~ diff : factor(Xbar), df)

fm3 <- lm(Sales ~ I(Xbar * diff) + I((1 - Xbar) * diff), df)

用 nls 仔细检查

我们可以使用 nls 和以下公式仔细检查这些,它利用了这样一个事实,即如果我们扩展两条线,则在任何数量处使用的那条线是两条线中较小的一条。

st <- list(a = 0, b1 = 1, b2 = -1)
fm4 <- nls(Sales ~ a + pmin(b1 * (Quantity - 89), b2 * (Quantity - 89)), start = st)
fm4
## Nonlinear regression model
##   model: Sales ~ a + pmin(b1 * (Quantity - 89), b2 * (Quantity - 89))
##    data: parent.frame()
##       a      b1      b2 
## 4817.30   60.88  -19.97 
## residual sum-of-squares: 713120
##
## Number of iterations to convergence: 1 
## Achieved convergence tolerance: 2.285e-09

这也行得通:

fm5 <- nls(Sales ~ a + ifelse(Quantity > 89, b2, b1) * diff, df, start = st)

情节

这是一个情节:

plot(Sales ~ Quantity, df)
lines(fitted(fm) ~ Quantity, df)

模型矩阵

这里是线性回归的模型矩阵:

> model.matrix(fm)
   (Intercept) diff:is.rightFALSE diff:is.rightTRUE
1            1                -64                 0
2            1                -50                 0
3            1                -44                 0
4            1                -32                 0
5            1                -19                 0
6            1                 -4                 0
7            1                  0                 0
8            1                  0                11
9            1                  0                21
10           1                  0                35
11           1                  0                48
12           1                  0                61
13           1                  0                88