GAM模型中客户个体需求价格弹性(PED)估计及代码问题求助
问题解答与建模建议
1. mfx$dydx 是否为需求价格弹性(PED)?
不是,因为你当前的模型设定和理论模型不匹配:
- 你的理论模型是:$\ln D = \ln P + \ln P \cdot \sum_{i=1}^{20} f(X_i)$,因此 $PED = \frac{\partial \ln D}{\partial \ln P} = 1 + \sum_{i=1}^{20} f(X_i)$
- 但你实际拟合的模型缺少了
log.R(即$\ln P$)的主效应项,仅包含了by=log.R的样条交互项。此时模型形式为:$\ln D = \alpha + \ln P \cdot \sum s(X_i)$,对$\ln P$求导得到的是$\sum s(X_i)$,并非理论中的$1 + \sum f(X_i)$。
如果要让dydx对应PED,必须修正模型,加入log.R的主效应:
model <- gam(log.Y ~ log.R + s(A, by=log.R) + s(B, by=log.R) + s(C, by=log.R) + s(D, by=log.R), data = mydata, method = "REML")
修正后,marginaleffects返回的dydx列就是理论定义的PED。
2. 新数据报错的解决方法
报错原因是marginaleffects需要模型中的所有自变量才能计算边际效应,而你的newdat缺少了log.R变量。但注意:你的PED计算不依赖log.R的具体取值(因为$PED = 1 + \sum f(X_i)$,仅由客户个体变量$X_i$决定),因此只需给新数据补充任意合理的log.R值即可,比如训练数据的均值:
# 补充log.R为训练数据的均值 newdat <- data.frame(A = 750, B = 500, C = 398, D = 740, log.R = mean(mydata$log.R)) # 重新计算边际效应(即PED) mfx_new <- marginaleffects(model, variables = "log.R", eps = 1e-5, newdata = newdat)
此时mfx_new$dydx就是该新客户的PED估计值。
3. 替代建模与计算思路
用gratia包直接计算导数
gratia的derivatives()函数可以更直接地计算模型的导数,适配你的需求:
library(gratia) # 计算训练数据中每个样本的PED ped_train <- derivatives(model, var = "log.R", data = mydata) # derivative列即为PED # 计算新客户的PED ped_new <- derivatives(model, var = "log.R", data = newdat)
重新参数化模型(等价形式)
你可以将模型重新表述为$\ln D = PED \cdot \ln P$,其中$PED = 1 + s(A) + s(B) + s(C) + s(D)$,对应R代码:
model <- gam(log.Y ~ 0 + log.R:(1 + s(A) + s(B) + s(C) + s(D)), data = mydata, method = "REML")
这个模型和之前修正后的模型完全等价,计算PED时同样可以用derivatives()或marginaleffects(),结果一致。
注意事项
- 确保所有客户个体变量$X_i$的样条设置合理(比如选择合适的自由度),避免过拟合或欠拟合。
- 可以通过绘制$X_i$与PED的关系图(用gratia的
draw()函数),验证弹性是否随个体变量变化符合业务逻辑。
内容的提问来源于stack exchange,提问作者Hitalo Pinheiro
相关产品推荐
相关产品推荐

