はじめに
{modelsummary}はRで回帰分析などのモデルの結果を整形して出力するためのパッケージで、使用されている方も多いと思います。 \(\LaTeX\) 形式で出力することも可能で、そのまま貼り付けられる形式で出力されている方もいれば、ベーシックな出力だけしておいて後から \(\LaTeX\) 側で整形する方もいらっしゃると思います。
本ページではなるべく \(\LaTeX\) 側で苦労しなくて済むように、{modelsummary} の出力を整える方法について紹介します。
\(\LaTeX\) 形式で出力するためには、tinytable::theme_latex() を適用する必要があります。途中の例で都度記載はしていませんが、セクション 6 を参照してください。
基本的な使い方
{fixest}を用いてDIDの分析モデルを推定し、その結果を{modelsummary}で整形して出力する例を示します。 ここでは本ページの表示のためにmarkdown形式で出力しますが、後ほど \(\LaTeX\) 形式での出力も紹介します。
library(fixest)
library(modelsummary)
# データの準備
data("base_did")
# 交差項の作成
df <- base_did |>
dplyr::mutate(
treat_post = treat * post,
# 共変量を適当に追加
cov1 = rnorm(dplyr::n(), 0, 1),
cov2 = rnorm(dplyr::n(), 0, 1)
)
# モデルの推定
model <- feols(y ~ treat_post | id + period, data = df)
# 結果を表示
modelsummary(model)| (1) | |
|---|---|
| treat_post | 4.993 |
| (0.613) | |
| Num.Obs. | 1080 |
| R2 | 0.307 |
| R2 Adj. | 0.222 |
| R2 Within | 0.065 |
| R2 Within Adj. | 0.064 |
| AIC | 6666.2 |
| BIC | 7254.4 |
| RMSE | 4.75 |
| FE: id | X |
| FE: period | X |
分析結果に対してmodelsummary()を使うことで、簡単に結果を表示することができますが、このまま添付することはないと思いますので、一連の流れで整形していきます1。
変数のラベルを書き換える
単一の変数のラベルの書き換え
表 1 では変数名がデータフレーム内のtreat_postのまま表示されています。まずはここを書き換えます。
modelsummary(model, coef_rename = "Treat × Post")| (1) | |
|---|---|
| Treat × Post | 4.993 |
| (0.613) | |
| Num.Obs. | 1080 |
| R2 | 0.307 |
| R2 Adj. | 0.222 |
| R2 Within | 0.065 |
| R2 Within Adj. | 0.064 |
| AIC | 6666.2 |
| BIC | 7254.4 |
| RMSE | 4.75 |
| FE: id | X |
| FE: period | X |
ポイント: - coef_rename 引数を使うことで、特定の変数のラベルを簡単に変更できます。
多数の変数のラベルの書き換え
複数の変数を書き換える場合には、coef_renameを使う方法とcoef_mapを使う方法があります。
model_cov <- feols(y ~ treat_post + cov1 + cov2 | id + period, data = df)
modelsummary(
model_cov,
coef_rename = c(
"treat_post" = "Treat × Post",
"cov1" = "Covariate 1"
)
)| (1) | |
|---|---|
| Treat × Post | 4.994 |
| (0.613) | |
| Covariate 1 | -0.006 |
| (0.159) | |
| cov2 | -0.096 |
| (0.163) | |
| Num.Obs. | 1080 |
| R2 | 0.307 |
| R2 Adj. | 0.221 |
| R2 Within | 0.065 |
| R2 Within Adj. | 0.062 |
| AIC | 6669.8 |
| BIC | 7268.0 |
| RMSE | 4.75 |
| FE: id | X |
| FE: period | X |
ポイント:
- 複数の変数のラベルを変更する場合も、
coef_renameを使うことで簡単に変更できます。 - 特に指定しなかった変数(
cov2)は元の変数名のまま表示されます。
modelsummary(
model_cov,
coef_map = c(
"treat_post" = "Treat × Post",
"cov1" = "Covariate 1"
)
)coef_mapで変更
| (1) | |
|---|---|
| Treat × Post | 4.994 |
| (0.613) | |
| Covariate 1 | -0.006 |
| (0.159) | |
| Num.Obs. | 1080 |
| R2 | 0.307 |
| R2 Adj. | 0.221 |
| R2 Within | 0.065 |
| R2 Within Adj. | 0.062 |
| AIC | 6669.8 |
| BIC | 7268.0 |
| RMSE | 4.75 |
| FE: id | X |
| FE: period | X |
ポイント:
coef_mapを使うことで、複数の変数のラベルを一括で変更できます。coef_renameと異なり、coef_mapでは指定しなかった変数は表示されません。
変数が多くなる場合には事前にラベルの対応表を作成しておき、それをcoef_mapに渡すと便利です。
cm <- c(
"treat_post" = "Treat × Post",
"cov1" = "Covariate 1",
"cov2" = "Covariate 2"
)
modelsummary(
model_cov,
coef_map = cm
)| (1) | |
|---|---|
| Treat × Post | 4.994 |
| (0.613) | |
| Covariate 1 | -0.006 |
| (0.159) | |
| Covariate 2 | -0.096 |
| (0.163) | |
| Num.Obs. | 1080 |
| R2 | 0.307 |
| R2 Adj. | 0.221 |
| R2 Within | 0.065 |
| R2 Within Adj. | 0.062 |
| AIC | 6669.8 |
| BIC | 7268.0 |
| RMSE | 4.75 |
| FE: id | X |
| FE: period | X |
統計量を整える
次に、モデルの出力に含まれる統計量を整える方法について紹介します。観測数とか決定係数などの統計量を絞り込んだりラベルを変更することができます。
前提として、どのような統計量があるのかを確認するためには、コンソールでgof_mapを実行してください。ここでは長いので、先頭の部分だけを表示します。
head(gof_map) raw clean fmt omit
1 nobs Num.Obs. 0 FALSE
2 nimp Num.Imp. 0 FALSE
3 nclusters Num.Clust. 0 FALSE
4 nblocks Num.Blocks 0 FALSE
5 r.squared R2 3 FALSE
6 r2 R2 3 FALSE
raw, clean, fmt, omitの4列があります。 raw列が元の統計量名を示しており、clean列が表示される名前、fmt列が小数点以下の桁数、omit列が出力から除外するかどうかを示しています。
表示する統計量を絞り込む
上記の表を見ていただけばわかる通り、デフォルトではNum.Obs., R2, R2 Adj., R2 Within, R2 Within Adj., AIC, BIC, RMSE, 固定効果が表示されています。
modelsummary(
model_cov,
gof_omit = "R2 Adj.|R2 Within|R2 Within Adj.|AIC|BIC|RMSE"
)| (1) | |
|---|---|
| treat_post | 4.994 |
| (0.613) | |
| cov1 | -0.006 |
| (0.159) | |
| cov2 | -0.096 |
| (0.163) | |
| Num.Obs. | 1080 |
| R2 | 0.307 |
| FE: id | X |
| FE: period | X |
ポイント:
gof_omit引数を使うことで、特定の統計量を出力から除外することができます。gof_mapで確認したうちのclean列の名前をgof_omitで指定することで、除外する統計量を選ぶことができます。|で区切ることで、複数の統計量をまとめて除外することができます。
統計量のラベルを書き換える
例えばR2を \(R^2\) とするように、統計量のラベルを変更するにはgof_map引数を使用します。
gm <- tibble::tribble(
~raw , ~clean , ~fmt ,
"nobs" , "Observations" , 0 ,
"r.squared" , "R\u00B2" , 3 ,
"FE: id" , "ID Fixed Effects" , 0 ,
"FE: period" , "Period Fixed Effects" , 0
)
modelsummary(model_cov, gof_map = gm)| (1) | |
|---|---|
| treat_post | 4.994 |
| (0.613) | |
| cov1 | -0.006 |
| (0.159) | |
| cov2 | -0.096 |
| (0.163) | |
| Observations | 1080 |
| R² | 0.307 |
| ID Fixed Effects | X |
| Period Fixed Effects | X |
ポイント:
gof_map引数を使うことで、統計量のラベルを自由に変更することができます。raw列に元の統計量名、clean列に表示したい名前、fmt列に小数点以下の桁数を指定します。\u00B2は上付きの2を表しており、\(R^2\) のように表示されます。- 固定効果は
FE: idやFE: periodの形で指定します。
tribble()は、行ごとにデータを入力できる関数です。列名を~で指定し、その後に各行のデータを入力していきます。tibble()が通常の列ごとにデータを入力するのに対して、tribble()は行ごとにデータを入力できる点が特徴です。以下の例では同じデータフレームができます。
tibble::tribble(
~raw , ~clean , ~fmt ,
"nobs" , "Observations" , 0 ,
"r.squared" , "R\u00B2" , 3
)# A tibble: 2 × 3
raw clean fmt
<chr> <chr> <dbl>
1 nobs Observations 0
2 r.squared R² 3
tibble::tibble(
raw = c("nobs", "r.squared"),
clean = c("Observations", "R\u00B2"),
fmt = c(0, 3)
)# A tibble: 2 × 3
raw clean fmt
<chr> <chr> <dbl>
1 nobs Observations 0
2 r.squared R² 3
数値にカンマ区切りを入れる
観測数などそれなりの大きな数値にはカンマ区切りを入れる場合は以下のようにします。
modelsummary(
model_cov,
fmt = fmt_statistic(
"estimate" = 3,
"std.error" = 3,
"nobs" = \(x) prettyNum(x, big.mark = ",")
),
gof_map = gm
)| (1) | |
|---|---|
| treat_post | 4.994 |
| (0.613) | |
| cov1 | -0.006 |
| (0.159) | |
| cov2 | -0.096 |
| (0.163) | |
| Observations | 1,080 |
| R² | 0.307 |
| ID Fixed Effects | X |
| Period Fixed Effects | X |
表に行を追加する
例えば回帰において重みづけを行った場合など、既存の統計量に加えて新たな行を追加したいことがあります。その場合はmodelsummary()内でadd_rowsを使用します。
まずは追加したい行のデータフレームを作成します。データフレームは再びtribble()を使って行ごとに入力します。
rows <- tibble::tribble(
~term , ~col1 ,
"Weight" , "X"
)
modelsummary(model_cov, coef_map = cm, gof_map = gm, add_rows = rows)| (1) | |
|---|---|
| Treat × Post | 4.994 |
| (0.613) | |
| Covariate 1 | -0.006 |
| (0.159) | |
| Covariate 2 | -0.096 |
| (0.163) | |
| Observations | 1080 |
| R² | 0.307 |
| ID Fixed Effects | X |
| Period Fixed Effects | X |
| Weight | X |
作成したadd_rowsをmodelsummary()のadd_rows引数に渡すことで、表に新たな行を追加しました。 デフォルトでは作成した行は一番下に挿入されます。位置を変更したい場合には、attr()関数を使ってadd_rowsのposition属性を設定します。
attr(rows, "position") <- 9
modelsummary(model_cov, coef_map = cm, gof_map = gm, add_rows = rows)| (1) | |
|---|---|
| Treat × Post | 4.994 |
| (0.613) | |
| Covariate 1 | -0.006 |
| (0.159) | |
| Covariate 2 | -0.096 |
| (0.163) | |
| Observations | 1080 |
| R² | 0.307 |
| Weight | X |
| ID Fixed Effects | X |
| Period Fixed Effects | X |
Treat × Postから数えて9行目に追加しました。標準誤差の行も数える点に注意してください。
固定効果の行の”X”を”Yes”に書き換える
例えば固定効果が含まれるモデルでは固定効果を表す行にXが表示されていました。 場合によっては、XをYesに書き換えたいこともありますが、これは{fixest}パッケージの仕様に依存しているため、設定を書き換える必要があります。
glance_custom.fixest <- function(x, ...) {
out <- data.frame(row.names = "firstrow")
for (n in x$fixef_vars) {
out[[paste("FE:", n)]] <- "Yes"
}
out
}上記をコピペしてそのまま使用していただければ、固定効果を表す行のXがYesに置き換わります(もちろん任意の文字列に変更可能です)。
modelsummary(model_cov, coef_map = cm, gof_map = gm)| (1) | |
|---|---|
| Treat × Post | 4.994 |
| (0.613) | |
| Covariate 1 | -0.006 |
| (0.159) | |
| Covariate 2 | -0.096 |
| (0.163) | |
| Observations | 1080 |
| R² | 0.307 |
| ID Fixed Effects | Yes |
| Period Fixed Effects | Yes |
複数のモデルを並べて表示する
基本の複数モデル表示
複数のモデルを並べて表示するには、分析結果をリスト形式で格納し、modelsummary()に渡します。
models <- list(
"Model 1" = feols(y ~ treat_post | id + period, data = df),
"Model 2" = feols(y ~ treat_post + cov1 + cov2 | id + period, data = df)
)
cm <- c(
"treat_post" = "Treat × Post",
"cov1" = "Covariate 1",
"cov2" = "Covariate 2"
)
gm <- tibble::tribble(
~raw , ~clean , ~fmt ,
"nobs" , "Observations" , 0 ,
"r.squared" , "R\u00B2" , 3 ,
"FE: id" , "ID Fixed Effects" , 0 ,
"FE: period" , "Period Fixed Effects" , 0
)
modelsummary(models, coef_map = cm, gof_map = gm)| Model 1 | Model 2 | |
|---|---|---|
| Treat × Post | 4.993 | 4.994 |
| (0.613) | (0.613) | |
| Covariate 1 | -0.006 | |
| (0.159) | ||
| Covariate 2 | -0.096 | |
| (0.163) | ||
| Observations | 1080 | 1080 |
| R² | 0.307 | 0.307 |
| ID Fixed Effects | X | X |
| Period Fixed Effects | X | X |
ポイント:
- リストの中で各分析に名前を付けることで、表の列見出しとして表示されます。
coef_mapを使っているので、含まれる変数はすべて記載しておくようにしましょう。- 例えば
cmに”cov2”を含めていない場合、Model 2に”cov2”が含まれていても表には表示されません2。 - 一部だけ指定して表示を変え、他はそのままにしたい場合には
coef_renameを使用してください。
- 例えば
表 10 の場合、「Model 1」や「Model 2」といったモデル名が表の列見出しとして表示され、これは短いので改行をする必要性はないと思います。
一方、モデルごとにアウトカム変数が異なり、そのアウトカム変数を列見出しとして表示したい場合などにはモデルのラベルが長くなることもあると思います。
\(\LaTeX\) 出力の場合は、長いモデル名を改行して表示するために、\\を使って改行を指定することができます。ただし、Rでは\がエスケープ文字として扱われるため、"\\\\"のように二重にする必要があります。また、ラベルを{ }で囲んでください3。
models <- list(
"{Without\\\\Covariates}" = feols(y ~ treat_post | id + period, data = df),
"{With\\\\Covariates}" = feols(
y ~ treat_post + cov1 + cov2 | id + period,
data = df
)
)modelsummary(models)だけ実行するとモデル名は{Without\\Covariates}や{With\\Covariates}のように表示されますが、次に説明する方法を使うことで、正しく改行されたモデル名として表示されます。
列をグルーピングする
列をグルーピングすることで、関連するモデルをまとめて表示することができます。例えば、アウトカム変数ごとにモデルをグループ化する場合などに有用です。 ここでは{tinytable}パッケージのgroup_tt()を使うことで、列をグルーピングすることができます。
library(tinytable)
models <- list(
"Model 1" = feols(y ~ treat_post | id + period, data = df),
"Model 2" = feols(y ~ treat_post + cov1 | id + period, data = df),
"Model 3" = feols(y ~ treat_post + cov2 | id + period, data = df),
"Model 4" = feols(y ~ treat_post + cov1 + cov2 | id + period, data = df)
)
cm <- c(
"treat_post" = "Treat × Post",
"cov1" = "Covariate 1",
"cov2" = "Covariate 2"
)
gm <- tibble::tribble(
~raw , ~clean , ~fmt ,
"nobs" , "Observations" , 0 ,
"r.squared" , "R\u00B2" , 3 ,
"FE: id" , "ID Fixed Effects" , 0 ,
"FE: period" , "Period Fixed Effects" , 0
)
modelsummary(models, coef_map = cm, gof_map = gm) |>
group_tt(j = list("Group 1" = 2:3, "Group 2" = 4:5))| Group 1 | Group 2 | |||
|---|---|---|---|---|
| Model 1 | Model 2 | Model 3 | Model 4 | |
| Treat × Post | 4.993 | 4.994 | 4.994 | 4.994 |
| (0.613) | (0.613) | (0.613) | (0.613) | |
| Covariate 1 | -0.005 | -0.006 | ||
| (0.158) | (0.159) | |||
| Covariate 2 | -0.096 | -0.096 | ||
| (0.163) | (0.163) | |||
| Observations | 1080 | 1080 | 1080 | 1080 |
| R² | 0.307 | 0.307 | 0.307 | 0.307 |
| ID Fixed Effects | X | X | X | X |
| Period Fixed Effects | X | X | X | X |
ポイント:
group_tt()のj引数を使うことで、列をグルーピングすることができます。jで指定する列番号は、2から始まることに注意してください。- 1は行ラベルの列であるためです。
2:3は、2列目と3列目をグループ化することを意味します。
LaTeX形式で出力する
modelsummary()で出力された表は、{tinytable}パッケージと互換性を持ちます4。
ここまでのコードでは、RStudio/VS Codeなどの環境では表示することができましたが、このままでは.texファイルとして保存することができません。
そこで{tinytable}のtheme_latex()とsave_tt()を使うことで、modelsummary()の結果を \(\LaTeX\) 形式で出力することができます。
modelsummary(models, coef_map = cm, gof_map = gm) |>
theme_latex() |>
save_tt("modelsummary.tex", overwrite = TRUE)overwrite = TRUEとすることで、既存のファイルが存在する場合でも上書き保存されます。
上記のコードを実行すると、modelsummary.texとして出力され、\(\LaTeX\) で利用可能な形式の表が得られます。
\begin{table}
\centering
\begin{tblr}[ %% tabularray outer open
] %% tabularray outer close
{ %% tabularray inner open
colspec={Q[]Q[]Q[]},
hline{2}={1-3}{solid, black, 0.05em},
hline{8}={1-3}{solid, black, 0.05em},
hline{1}={1-3}{solid, black, 0.08em},
hline{12}={1-3}{solid, black, 0.08em},
column{2-3}={}{halign=c},
column{1}={}{halign=l},
} %% tabularray inner close
& Model 1 & Model 2 \\
Treat × Post & 4.993 & 4.982 \\
& (0.613) & (0.613) \\
Covariate 1 & & 0.221 \\
& & (0.157) \\
Covariate 2 & & 0.207 \\
& & (0.163) \\
Observations & 1080 & 1080 \\
R² & 0.307 & 0.309 \\
ID Fixed Effects & X & X \\
Period Fixed Effects & X & X \\
\end{tblr}
\end{table}\(\TeX\) ファイルのプリアンブルに何を書いているかにもよりますが、未記載の場合にはtabularrayパッケージを読み込んでおく必要がありますのでご注意ください(\usepackage{tabularray})。
まとめ
今回は{modelsummary}を使って分析結果の表を作成し、体裁の整え方や \(\LaTeX\) 形式での出力方法について説明しました。
個人的にはRでTeXの出力までできるとかなり楽だと思うので、Rの結果から転記されていた方はぜひ使ってみてください!