绘制结构主题模型:如何实现时间维度的不连续性
STM模型添加时间断点的可视化方案
现有实现代码
我正在使用R语言的stm包运行结构主题模型,模型包含faction_id与numeric_date(时间度量)的交互效应,已完成模型估计并绘制了两个派系第9号主题随时间的占比趋势图。现有代码如下:
# 拟合模型 model.fac.dat.int <- stm( documents = docs, vocab = vocab, K = 20, prevalence = ~ faction_id * s(numeric_date), max.em.its = 75, data = meta, reportevery = 50, verbose = TRUE, init.type = "Spectral" ) # 估计第9号主题的效应 est.fac.dat.int <- estimateEffect( formula = c(9) ~ faction_id * numeric_date, stmobj = model.fac.dat.int, metadata = meta, uncertainty = "None" ) # 绘制Greens派系的趋势线 plot( est.fac.dat.int, covariate = "numeric_date", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "Greens", linecol = "green", xlab = "Time", ylim = c(0, 0.1), printlegend = F ) # 添加CDU派系的趋势线 plot( est.fac.dat.int, covariate = "numeric_date", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "CDU", linecol = "red", add = T, printlegend = F )
需求与疑问
我希望在numeric_date=7000(选举日期)处的线性图中添加断点——理论上该时间点后折线会下移,当前图可能掩盖了这一效应,因此想要制作类似RDD的图。由于stm包没有专门的函数实现此场景,我考虑过使用rdd包,但不知如何与现有stm设置结合。请问是否应该分别估计numeric_date<7000和numeric_date>7000的效应,再将两段图合并?
解决方案
你提到的分时间段估计效应再合并绘图是完全可行的,同时还有一种更高效的方法:无需重新拟合STM模型,直接在estimateEffect中加入断点变量来捕捉时间断点的效应,以下是两种方法的具体实现:
方法1:分数据集估计效应并合并绘图
- 拆分元数据
# 拆分数据集为选举前和选举后 meta_pre <- subset(meta, numeric_date < 7000) meta_post <- subset(meta, numeric_date >= 7000)
- 分别估计两个时间段的效应
# 选举前第9主题的效应 est_pre <- estimateEffect( formula = c(9) ~ faction_id * numeric_date, stmobj = model.fac.dat.int, metadata = meta_pre, uncertainty = "None" ) # 选举后第9主题的效应 est_post <- estimateEffect( formula = c(9) ~ faction_id * numeric_date, stmobj = model.fac.dat.int, metadata = meta_post, uncertainty = "None" )
- 合并绘制断点图
# 先绘制选举前Greens的趋势 plot( est_pre, covariate = "numeric_date", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "Greens", linecol = "green", xlab = "Time", ylim = c(0, 0.1), xlim = range(meta$numeric_date), printlegend = F ) # 添加选举后Greens的趋势 plot( est_post, covariate = "numeric_date", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "Greens", linecol = "green", add = T, printlegend = F ) # 添加CDU选举前趋势 plot( est_pre, covariate = "numeric_date", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "CDU", linecol = "red", add = T, printlegend = F ) # 添加CDU选举后趋势 plot( est_post, covariate = "numeric_date", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "CDU", linecol = "red", add = T, printlegend = F ) # 添加垂直断点线 abline(v = 7000, lty = 2, col = "gray50")
方法2:在estimateEffect中加入断点变量(无需重新拟合模型)
通过构造断点虚拟变量及其交互项,直接在效应估计中捕捉时间断点的影响:
- 构造断点变量
meta$post_election <- as.numeric(meta$numeric_date >= 7000) # 构造日期与断点的交互项(以断点为中心调整日期) meta$date_centered <- meta$numeric_date - 7000
- 估计包含断点的效应
est_break <- estimateEffect( formula = c(9) ~ faction_id * date_centered * post_election, stmobj = model.fac.dat.int, metadata = meta, uncertainty = "None" )
- 绘制带断点的趋势图
# 绘制Greens的完整趋势(自动包含断点) plot( est_break, covariate = "date_centered", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "Greens", linecol = "green", xlab = "Time (centered at election date)", ylim = c(0, 0.1), printlegend = F ) # 添加CDU的趋势 plot( est_break, covariate = "date_centered", model = model.fac.dat.int, method = "continuous", moderator = "faction_id", moderator.value = "CDU", linecol = "red", add = T, printlegend = F ) # 添加垂直断点线(对应x=0) abline(v = 0, lty = 2, col = "gray50")
方法对比
- 方法1的优势是直观,完全对应你提出的分阶段思路,适合需要明确拆分时间段分析的场景;
- 方法2无需拆分数据集,通过模型公式直接纳入断点效应,更高效且能保持模型的整体性,同时可以直接检验断点交互项的显著性。
内容的提问来源于stack exchange,提问作者Elisa Benni
相关产品推荐
相关产品推荐

