This version: 2024-11-05
did
パッケージに付属しているデータを用いて、DiD(difference-in-differences)の実装を解説するものである。fixest
パッケージfixest
パッケージdid
パッケージinstall.packages(c("tidyverse", "did", "fixest", "panelView", "modelsummary", "rio"))
静学
\[ Y_{i t}= \underbrace{\color{green}{\theta_{t}}}_{時間FE}+ \underbrace{\color{red}{\eta_{i}}}_{個体FE}+ \color{blue}{\alpha} \underbrace{D_{i t}}_{処置}+ v_{i t} \qquad (1) \]
動学
\[ Y_{i t}= \underbrace{\color{green}{\theta_{t}}}_{時間FE}+ \underbrace{\color{red}{\eta_{i}}}_{個体FE}+ \sum_{e=-(\mathcal{T}-1)}^{-2} \color{blue}{\beta_{e}} \color{purple}{D_{i t}^{e}} + \sum_{e=0}^{\mathcal{T}-1} \color{blue}{\beta_{e}} \color{purple}{D_{i t}^{e}} + v_{i t} \]
\[ Y_{i t}= \underbrace{\color{green}{\theta_{t}}}_{時間FE}+ \underbrace{\color{red}{\eta_{i}}}_{個体FE}+ \sum_{g \in \overline{\mathcal{G}}} \sum_{e \neq-1} \color{blue}{\delta_{g e}^{S A} } \underbrace{\mathbf{1}\left\{G_{i}=g\right\} }_{グループ} \underbrace{\mathbf{1}\{g+e=t\}}_{相対時間} + v_{i t} \qquad (7) \]
Step1. グループ時間別平均処置効果
\[ \color{green}{A T T(g, t)}=\mathbb{E}\left[Y_{t}(g)-Y_{t}(0) \mid G=g\right] \] ここで、\(g\)は、\(g\)時点で初めて処置を受けた処置群を示す。
\[ \color{green}{A T T(g, t)}= \mathbb{E}\left[\left(\frac{1\{G=g\}}{p_{g}} - \frac{\frac{p_{g}(X) U}{p_{g}\left(1-p_{g}(X)\right)}} {\mathbb{E}\left[\frac{p_{g}(X) U}{p_{g}\left(1-p_{g}(X)\right)}\right]}\right) \left(Y_{t}-Y_{g-1}-m_{g t}^{n t}(X)\right)\right] \]
Step 2. イベント・スタディ・パラメータ
\[ \color{blue}{A T T^{E S}(e)}=\sum_{g \in \mathcal{G}} \underbrace{w^{E S}(g, e)}_{ウェイト} \underbrace{\color{green}{A T T(g, g+e)}}_{グループ時間別平均処置効果} \] ここで、\(e=t-g\)である。
library(tidyverse)
library(did)
data(mpdta)
rio::export(mpdta, "mpdta.csv")
このデータは、did
パッケージに付属しているものである。Callaway
and Sant’Anna
(2021)によるデータセットであり、米国の最低賃金の引き上げが若年労働者の雇用に与える影響を検証するために作成されたものである。
人工的なデータセットである。
Callaway and Sant’Anna (2021)論文のデータそのものは公開されておらず、このデータセットと年次が違うなど論文の結果を再現することはできない。
含まれている変数は以下の通りである。
year: 年次。2003年から2007年までの5年間。
countyreal: 郡のID
lpop: 郡の人口 - 共変量
lemp: 郡の若年雇用者数- アウトカム変数
first.treat: 最初の介入の年次
treat: 処置群ダミー
barplot(table(mpdta$year))
first.treat
は、最初の介入の年次を示す変数である。0は、処置がないことを示す。barplot(table(mpdta$first.treat))
modelsummary
パッケージのdatasummary
で記述統計の確認を行う。# `modelsummary`で記述統計の確認を行う。
modelsummary::datasummary(
year + countyreal +
lpop + lemp + treat
+ first.treat
~ (mean + sd + min + max + length),
data = mpdta)
mean | sd | min | max | length | |
---|---|---|---|---|---|
year | 2005.00 | 1.41 | 2003.00 | 2007.00 | 2500.00 |
countyreal | 32211.04 | 13736.02 | 8001.00 | 55137.00 | 2500.00 |
lpop | 3.31 | 1.28 | 0.07 | 7.70 | 2500.00 |
lemp | 5.77 | 1.51 | 1.10 | 10.44 | 2500.00 |
treat | 0.38 | 0.49 | 0.00 | 1.00 | 2500.00 |
first.treat | 766.47 | 975.10 | 0.00 | 2007.00 | 2500.00 |
# 比較群 versus 処置群
modelsummary::datasummary_balance(~treat,
data = mpdta)
Mean | Std. Dev. | Mean | Std. Dev. | |
---|---|---|---|---|
year | 2005.0 | 1.4 | 2005.0 | 1.4 |
countyreal | 33573.4 | 14383.2 | 30007.1 | 12310.8 |
lpop | 3.2 | 1.3 | 3.5 | 1.2 |
lemp | 5.6 | 1.5 | 6.0 | 1.5 |
first.treat | 0.0 | 0.0 | 2006.5 | 0.9 |
panelView
panelView
パッケージで処置状態の推移を可視化する。パッケージ名では、V
は大文字だが、関数名では、v
は小文字であることに注意が必要である。# 時変処置状態ダミー
mpdta$treatit <- ifelse(mpdta$year >= mpdta$first.treat, 1, 0)
# `panelView`でデータを確認する。
panelView::panelview(1 ~ treatit ,
data = as.data.frame(mpdta),
by.timing = TRUE,
background = "white",
color = c("grey","pink"),
index = c("countyreal", "year")
)
## Specified colors in the order of: Under Control, Under Treatment.
# event timeを作成する。
mpdta$event_time = mpdta$year - mpdta$first.treat
mpdta$event_time[mpdta$treat==0] = 10000
fixest
package2元固定効果モデル(TWFE model)で推定を行う。
i(event_time, ref = c(-1, 10000))
構文を用いて、相対時間変数event_time
を指定している。
ref
に処置前年(-1)とnever-treated
(10000)を指定している。lemp
は、アウトカム変数(各郡の若年雇用)である。| countyreal + year
は、郡固定効果と年次ダミーを指定している。# TWFEモデルに基づいて、ATTを推定する。
twfe = fixest::feols(lemp ~
i(event_time, ref = c(-1, 10000))
| countyreal + year,
data = mpdta)
fixest::etable(twfe)
## twfe
## Dependent Var.: lemp
##
## event_time = -4 0.0035 (0.0228)
## event_time = -3 0.0246 (0.0177)
## event_time = -2 0.0233. (0.0134)
## event_time = 0 -0.0181. (0.0110)
## event_time = 1 -0.0435* (0.0176)
## event_time = 2 -0.1318*** (0.0288)
## event_time = 3 -0.0922** (0.0323)
## Fixed-Effects: -------------------
## countyreal Yes
## year Yes
## _______________ ___________________
## S.E.: Clustered by: countyreal
## Observations 2,500
## R2 0.99326
## Within R2 0.01034
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# イベント・スタディ・プロットを作成する。
fixest::iplot(twfe,
ylim = c(-0.25, 0.1),
main = "TWFE")
fixest
packagefixest
パッケージのsunab
関数を使用して、相対時間ごとのATTを推定する。lemp
は、アウトカム変数(各郡の若年雇用)である。sunab(first.treat, event_time)
は、処置タイミングfirst.treat
と相対時間event_time
を指定している。| countyreal + year
は、郡固定効果と年次ダミーを指定している。# Sun and Abraham (2021)に基づいて、ATTを推定する。
sa = fixest::feols(lemp ~
sunab(first.treat, event_time)
| countyreal + year,
data = mpdta)
fixest::etable(sa)
## sa
## Dependent Var.: lemp
##
## event_time = -4 0.0033 (0.0246)
## event_time = -3 0.0250 (0.0181)
## event_time = -2 0.0248. (0.0143)
## event_time = 0 -0.0199. (0.0119)
## event_time = 1 -0.0510** (0.0169)
## event_time = 2 -0.1373*** (0.0366)
## event_time = 3 -0.1008** (0.0345)
## Fixed-Effects: -------------------
## countyreal Yes
## year Yes
## _______________ ___________________
## S.E.: Clustered by: countyreal
## Observations 2,499
## R2 0.99327
## Within R2 0.01246
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
fixest
パッケージのiplotを利用して、イベント・スタディ・プロットを作成する。# イベント・スタディ・プロットを作成する。
fixest::iplot(list(twfe, sa),
ylim = c(-0.25, 0.1),
main = "TWFE and Sun & Abraham")
# 凡例追加
legend("bottomleft",
col = c("1", "2"),
pch = c(20, 17),
legend = c("TWFE",
"Sun & Abraham (2020)")
)
did
packagedid
; Stata
csdid
)は、デフォルトでは、プレ期間は\(r\)と\(r+1\)の短期差分(short
difference)の比較で係数を推定する。ポスト期間は\(r=-1\)をベースラインとする。プレ期間とポスト期間で、基準年が変わってしまうため、プレの係数とポストの係数の単純な比較は誤解を招く。did
では、base_period = "universal"
を指定することで、プレ期間もポスト期間も\(r=-1\)を基準とする長期差分(long
difference)を用いた比較が得られる。Stata
csdid
では、long2
オプションにより、全期間\(r=-1\)をベースラインにできる。 。# Callaway and Sant'Anna (2021)に基づいて、ATTを推定する。
cs <- did::att_gt(yname = "lemp", # 結果変数
gname = "first.treat", # 処置タイミング
idname = "countyreal", # ユニットID
tname = "year", # 時間変数
xformla = ~1, # モデル
bstrap = TRUE, # ブートストラップSEを計算
biters = 1000, # ブートストラップの反復回数
base_period = "universal", # ベースライン期間
data = mpdta, # データ
est_method = "reg", # or "dr" (doubly robust)
control_group = "nevertreated" # or "notyettreated"
)
summary(cs)
##
## Call:
## did::att_gt(yname = "lemp", tname = "year", idname = "countyreal",
## gname = "first.treat", xformla = ~1, data = mpdta, control_group = "nevertreated",
## bstrap = TRUE, biters = 1000, est_method = "reg", base_period = "universal")
##
## Reference: Callaway, Brantly and Pedro H.C. Sant'Anna. "Difference-in-Differences with Multiple Time Periods." Journal of Econometrics, Vol. 225, No. 2, pp. 200-230, 2021. <https://doi.org/10.1016/j.jeconom.2020.12.001>, <https://arxiv.org/abs/1803.09015>
##
## Group-Time Average Treatment Effects:
## Group Time ATT(g,t) Std. Error [95% Simult. Conf. Band]
## 2004 2003 0.0000 NA NA NA
## 2004 2004 -0.0105 0.0246 -0.0771 0.0561
## 2004 2005 -0.0704 0.0316 -0.1563 0.0154
## 2004 2006 -0.1373 0.0408 -0.2480 -0.0265 *
## 2004 2007 -0.1008 0.0350 -0.1957 -0.0059 *
## 2006 2003 -0.0038 0.0320 -0.0905 0.0830
## 2006 2004 0.0028 0.0198 -0.0510 0.0565
## 2006 2005 0.0000 NA NA NA
## 2006 2006 -0.0046 0.0175 -0.0520 0.0428
## 2006 2007 -0.0412 0.0194 -0.0938 0.0113
## 2007 2003 0.0033 0.0238 -0.0611 0.0678
## 2007 2004 0.0338 0.0212 -0.0237 0.0913
## 2007 2005 0.0311 0.0165 -0.0138 0.0760
## 2007 2006 0.0000 NA NA NA
## 2007 2007 -0.0261 0.0169 -0.0720 0.0199
## ---
## Signif. codes: `*' confidence band does not cover 0
##
## P-value for pre-test of parallel trends assumption: 0.16812
## Control Group: Never Treated, Anticipation Periods: 0
## Estimation Method: Outcome Regression
cses <- did::aggte(cs, type = "dynamic")
# cses[["att.egt"]]、cses[["att.egt"]]、cses[["se.egt"]]を表示
summary(cses)
##
## Call:
## did::aggte(MP = cs, type = "dynamic")
##
## Reference: Callaway, Brantly and Pedro H.C. Sant'Anna. "Difference-in-Differences with Multiple Time Periods." Journal of Econometrics, Vol. 225, No. 2, pp. 200-230, 2021. <https://doi.org/10.1016/j.jeconom.2020.12.001>, <https://arxiv.org/abs/1803.09015>
##
##
## Overall summary of ATT's based on event-study/dynamic aggregation:
## ATT Std. Error [ 95% Conf. Int.]
## -0.0772 0.0216 -0.1195 -0.035 *
##
##
## Dynamic Effects:
## Event time Estimate Std. Error [95% Simult. Conf. Band]
## -4 0.0033 0.0246 -0.0571 0.0637
## -3 0.0250 0.0177 -0.0184 0.0684
## -2 0.0245 0.0149 -0.0123 0.0612
## -1 0.0000 NA NA NA
## 0 -0.0199 0.0117 -0.0486 0.0087
## 1 -0.0510 0.0178 -0.0948 -0.0071 *
## 2 -0.1373 0.0404 -0.2365 -0.0381 *
## 3 -0.1008 0.0342 -0.1850 -0.0166 *
## ---
## Signif. codes: `*' confidence band does not cover 0
##
## Control Group: Never Treated, Anticipation Periods: 0
## Estimation Method: Outcome Regression
# イベントスタディプロットを作成する。
did::ggdid(cses)
xformla = ~ lpop
として、共変量を追加する。est_method = "dr"
として、doubly robust推定を行う。# Callaway and Sant'Anna (2021)に基づいて、ATTを推定する。
cs2 <- did::att_gt(yname = "lemp", # 結果変数
gname = "first.treat", # 処置タイミング
idname = "countyreal", # ユニットID
tname = "year", # 時間変数
xformla = ~ lpop, # モデル
bstrap = TRUE, # ブートストラップSEを計算
biters = 1000, # ブートストラップの反復回数
base_period = "universal", # ベースライン期間
data = mpdta, # データ
est_method = "dr", # or "reg" (doubly robust)
control_group = "nevertreated" # or "notyettreated"
)
summary(cs2)
##
## Call:
## did::att_gt(yname = "lemp", tname = "year", idname = "countyreal",
## gname = "first.treat", xformla = ~lpop, data = mpdta, control_group = "nevertreated",
## bstrap = TRUE, biters = 1000, est_method = "dr", base_period = "universal")
##
## Reference: Callaway, Brantly and Pedro H.C. Sant'Anna. "Difference-in-Differences with Multiple Time Periods." Journal of Econometrics, Vol. 225, No. 2, pp. 200-230, 2021. <https://doi.org/10.1016/j.jeconom.2020.12.001>, <https://arxiv.org/abs/1803.09015>
##
## Group-Time Average Treatment Effects:
## Group Time ATT(g,t) Std. Error [95% Simult. Conf. Band]
## 2004 2003 0.0000 NA NA NA
## 2004 2004 -0.0145 0.0229 -0.0742 0.0451
## 2004 2005 -0.0764 0.0307 -0.1562 0.0033
## 2004 2006 -0.1404 0.0375 -0.2379 -0.0430 *
## 2004 2007 -0.1069 0.0332 -0.1932 -0.0206 *
## 2006 2003 0.0067 0.0306 -0.0729 0.0862
## 2006 2004 0.0062 0.0194 -0.0442 0.0566
## 2006 2005 0.0000 NA NA NA
## 2006 2006 0.0010 0.0196 -0.0501 0.0520
## 2006 2007 -0.0413 0.0198 -0.0927 0.0101
## 2007 2003 0.0063 0.0245 -0.0574 0.0700
## 2007 2004 0.0330 0.0210 -0.0215 0.0876
## 2007 2005 0.0284 0.0175 -0.0171 0.0740
## 2007 2006 0.0000 NA NA NA
## 2007 2007 -0.0288 0.0161 -0.0707 0.0131
## ---
## Signif. codes: `*' confidence band does not cover 0
##
## P-value for pre-test of parallel trends assumption: 0.23267
## Control Group: Never Treated, Anticipation Periods: 0
## Estimation Method: Doubly Robust
cses2 <- did::aggte(cs2, type = "dynamic")
summary(cses2)
##
## Call:
## did::aggte(MP = cs2, type = "dynamic")
##
## Reference: Callaway, Brantly and Pedro H.C. Sant'Anna. "Difference-in-Differences with Multiple Time Periods." Journal of Econometrics, Vol. 225, No. 2, pp. 200-230, 2021. <https://doi.org/10.1016/j.jeconom.2020.12.001>, <https://arxiv.org/abs/1803.09015>
##
##
## Overall summary of ATT's based on event-study/dynamic aggregation:
## ATT Std. Error [ 95% Conf. Int.]
## -0.0804 0.0189 -0.1174 -0.0433 *
##
##
## Dynamic Effects:
## Event time Estimate Std. Error [95% Simult. Conf. Band]
## -4 0.0063 0.0247 -0.0536 0.0661
## -3 0.0269 0.0175 -0.0155 0.0692
## -2 0.0232 0.0154 -0.0139 0.0604
## -1 0.0000 NA NA NA
## 0 -0.0211 0.0114 -0.0487 0.0066
## 1 -0.0530 0.0165 -0.0928 -0.0132 *
## 2 -0.1404 0.0380 -0.2323 -0.0486 *
## 3 -0.1069 0.0360 -0.1940 -0.0198 *
## ---
## Signif. codes: `*' confidence band does not cover 0
##
## Control Group: Never Treated, Anticipation Periods: 0
## Estimation Method: Doubly Robust
did::ggdid(cses2)
renv
パッケージを使用して、プロジェクトごとにパッケージのバージョン情報を保存することができる。# 現時点での分析環境を保存
renv::init()
# renv.lockファイルとrenvフォルダー更新
renv::snapshot()
## - The lockfile is already up to date.
# Rのバージョン確認
sessionInfo()
## R version 4.4.1 (2024-06-14)
## Platform: aarch64-apple-darwin20
## Running under: macOS Sonoma 14.6.1
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: Asia/Tokyo
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices datasets utils methods base
##
## other attached packages:
## [1] did_2.1.2 lubridate_1.9.3 forcats_1.0.0 stringr_1.5.1
## [5] dplyr_1.1.4 purrr_1.0.2 readr_2.1.5 tidyr_1.3.1
## [9] tibble_3.2.1 ggplot2_3.5.1 tidyverse_2.0.0
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.1 viridisLite_0.4.2 farver_2.1.2
## [4] R.utils_2.12.3 fastmap_1.2.0 DRDID_1.1.0
## [7] fixest_0.12.1 digest_0.6.37 parglm_0.1.7
## [10] timechange_0.3.0 lifecycle_1.0.4 dreamerr_1.4.0
## [13] magrittr_2.0.3 compiler_4.4.1 rlang_1.1.4
## [16] sass_0.4.9 tools_4.4.1 utf8_1.2.4
## [19] yaml_2.3.10 data.table_1.16.0 knitr_1.48
## [22] ggsignif_0.6.4 labeling_0.4.3 xml2_1.3.6
## [25] abind_1.4-8 withr_3.0.1 numDeriv_2016.8-1.1
## [28] R.oo_1.26.0 grid_4.4.1 fansi_1.0.6
## [31] ggpubr_0.6.0 colorspace_2.1-1 BMisc_1.4.6
## [34] scales_1.3.0 insight_0.20.4 cli_3.6.3
## [37] rmarkdown_2.28 generics_0.1.3 bigmemory.sri_0.1.8
## [40] rstudioapi_0.16.0 tzdb_0.4.0 cachem_1.1.0
## [43] fastglm_0.0.3 stringmagic_1.1.2 vctrs_0.6.5
## [46] Matrix_1.7-0 sandwich_3.1-1 jsonlite_1.8.9
## [49] carData_3.0-5 car_3.1-3 hms_1.1.3
## [52] rstatix_0.7.2 Formula_1.2-5 systemfonts_1.1.0
## [55] trust_0.1-8 jquerylib_0.1.4 rio_1.2.3
## [58] bigmemory_4.6.4 glue_1.8.0 modelsummary_1.4.3
## [61] stringi_1.8.4 gtable_0.3.5 tables_0.9.31
## [64] munsell_0.5.1 pillar_1.9.0 htmltools_0.5.8.1
## [67] R6_2.5.1 panelView_1.1.18 evaluate_1.0.0
## [70] kableExtra_1.4.0 lattice_0.22-6 highr_0.11
## [73] R.methodsS3_1.8.2 backports_1.5.0 broom_1.0.7
## [76] renv_1.0.3 bslib_0.8.0 uuid_1.2-1
## [79] Rcpp_1.0.13 svglite_2.1.3 gridExtra_2.3
## [82] nlme_3.1-164 checkmate_2.3.2 xfun_0.47
## [85] zoo_1.8-12 pkgconfig_2.0.3
# パッケージのバージョン確認: tidyverse, did, fixest, panelView, modelsummary, rio
packageVersion("tidyverse")
## [1] '2.0.0'
packageVersion("did")
## [1] '2.1.2'
packageVersion("fixest")
## [1] '0.12.1'
packageVersion("panelView")
## [1] '1.1.18'
packageVersion("modelsummary")
## [1] '1.4.3'
packageVersion("rio")
## [1] '1.2.3'