stargazer
package.There are three ways to set up math notation:
\[ Y_i = \hat{\alpha} + \hat \beta X_i + \varepsilon_i \]
\begin{equation}… \end{equation}. Use
equation* to remove any labeling, and align /
align* to set up multiple-line formulas.For example:
\begin{align*}
H_0 &: \beta_1 = 0 \\
H_A &: \beta_1 \neq 0
\end{align*}
You can mix regular text and math in R Markdown. This is very useful when you are explaining your models and hypotheses.
stargazerLoad the package via:
library(stargazer)
##
## Please cite as:
## Hlavac, Marek (2022). stargazer: Well-Formatted Regression and Summary Statistics Tables.
## R package version 5.2.3. https://CRAN.R-project.org/package=stargazer
We will use the iris dataset for illustration.
data(iris)
iris <- iris %>%
filter(Species != "setosa") %>%
mutate(Species = ifelse(Species == "virginica", 1, 0))
head(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 7.0 3.2 4.7 1.4 0
## 2 6.4 3.2 4.5 1.5 0
## 3 6.9 3.1 4.9 1.5 0
## 4 5.5 2.3 4.0 1.3 0
## 5 6.5 2.8 4.6 1.5 0
## 6 5.7 2.8 4.5 1.3 0
We can compute regression results:
fit1 <- lm(Sepal.Length ~ Sepal.Width + Species, data = iris)
fit1
##
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Species, data = iris)
##
## Coefficients:
## (Intercept) Sepal.Width Species
## 3.4879 0.8838 0.4717
And use stargazer to produce a nicely formatted
regression table:
stargazer(fit1,
type = "text", # Try: "latex" and "html"
title = "Regression Results",
dep.var.labels = c("Sepal Length"),
covariate.labels = c("Sepal Width", "Virginica", "Intercept"),
digits = 3,
out.header = FALSE
)
##
## Regression Results
## ===============================================
## Dependent variable:
## ---------------------------
## Sepal Length
## -----------------------------------------------
## Sepal Width 0.884***
## (0.162)
##
## Virginica 0.472***
## (0.107)
##
## Intercept 3.488***
## (0.453)
##
## -----------------------------------------------
## Observations 100
## R2 0.423
## Adjusted R2 0.411
## Residual Std. Error 0.509 (df = 97)
## F Statistic 35.484*** (df = 2; 97)
## ===============================================
## Note: *p<0.1; **p<0.05; ***p<0.01
type = "text" prints a plain-text table in your console
/ knitted output.type = "html" produces HTML code (good for HTML
documents or websites).type = "latex" produces LaTeX code (good for papers and
problem sets written in LaTeX).In LaTeX notation, our model is:
\[ \text{SepalLength}_i = \hat\alpha + \hat{\beta}_1 \text{SepalWidth}_i + \hat{\beta}_2 \text{Virginica}_i + \hat{\varepsilon}_i \]
stargazer can show more than one model at a time. This
is useful when you want to compare specifications.
# set results = 'asis' in chunk options
fit2 <- lm(Sepal.Length ~ Sepal.Width + Petal.Length + Species, data = iris)
fit3 <- lm(Sepal.Length ~ Sepal.Width + Species + Sepal.Width * Species, data = iris) # interaction
stargazer(fit1, fit2, fit3,
type = "text",
title = "Sepal Length: Model Comparison",
dep.var.labels = c("Sepal Length"),
column.labels = c("Baseline", "Add Petal Length", "Interaction"),
covariate.labels = c("Sepal Width",
"Petal Length",
"Virginica",
"Sepal Width : Virginica",
"Intercept"),
digits = 3,
align = TRUE,
no.space = FALSE
)
##
## Sepal Length: Model Comparison
## =============================================================================================
## Dependent variable:
## ---------------------------------------------------------------------
## Sepal Length
## Baseline Add Petal Length Interaction
## (1) (2) (3)
## ---------------------------------------------------------------------------------------------
## Sepal Width 0.884*** 0.231* 0.865***
## (0.162) (0.119) (0.233)
##
## Petal Length 0.858***
## (0.074)
##
## Virginica 0.472*** -0.503*** 0.367
## (0.107) (0.109) (0.938)
##
## Sepal Width : Virginica 0.036
## (0.325)
##
## Intercept 3.488*** 1.642*** 3.540***
## (0.453) (0.333) (0.649)
##
## ---------------------------------------------------------------------------------------------
## Observations 100 100 100
## R2 0.423 0.761 0.423
## Adjusted R2 0.411 0.753 0.405
## Residual Std. Error 0.509 (df = 97) 0.329 (df = 96) 0.511 (df = 96)
## F Statistic 35.484*** (df = 2; 97) 101.704*** (df = 3; 96) 23.419*** (df = 3; 96)
## =============================================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
Note:
column.labels names each column (model).covariate.labels lets you replace variable names with
more readable labels.align = TRUE makes the columns line up nicely in the
text output.no.space = TRUE removes extra blank lines below the
table.It is often helpful to add notes below your table:
stargazer(fit1, fit2,
type = "html",
title = "Sepal Length: Alternative Specifications",
dep.var.labels = "Sepal Length",
column.labels = c("Baseline", "Add Petal Length"),
covariate.labels = c("Sepal Width",
"Virginica",
"Petal Length"),
digits = 3,
add.lines = list(
c("Controls", "No", "Yes")
),
notes = "Robust standard errors not used here; this is for illustration only.",
notes.align = "l"
)
| Dependent variable: | ||
| Sepal Length | ||
| Baseline | Add Petal Length | |
| (1) | (2) | |
| Sepal Width | 0.884*** | 0.231* |
| (0.162) | (0.119) | |
| Virginica | 0.858*** | |
| (0.074) | ||
| Petal Length | 0.472*** | -0.503*** |
| (0.107) | (0.109) | |
| Constant | 3.488*** | 1.642*** |
| (0.453) | (0.333) | |
| Controls | No | Yes |
| Observations | 100 | 100 |
| R2 | 0.423 | 0.761 |
| Adjusted R2 | 0.411 | 0.753 |
| Residual Std. Error | 0.509 (df = 97) | 0.329 (df = 96) |
| F Statistic | 35.484*** (df = 2; 97) | 101.704*** (df = 3; 96) |
| Note: | p<0.1; p<0.05; p<0.01 | |
| Robust standard errors not used here; this is for illustration only. | ||
add.lines lets you add extra rows (e.g., “Controls”,
“Fixed Effects”, etc.).notes and notes.align let you include
additional information about the model.If you want to use the table in another document (for example, a
LaTeX paper), you can save the output to a file with the
out argument:
stargazer(fit1,
type = "latex",
title = "Regression Results",
dep.var.labels = "Sepal Length",
covariate.labels = c("Sepal Width", "Virginica"),
digits = 3,
out = "regression_table.tex"
)
##
## % Table created by stargazer v.5.2.3 by Marek Hlavac, Social Policy Institute. E-mail: marek.hlavac at gmail.com
## % Date and time: Mon, Jan 05, 2026 - 11:30:57 AM
## \begin{table}[!htbp] \centering
## \caption{Regression Results}
## \label{}
## \begin{tabular}{@{\extracolsep{5pt}}lc}
## \\[-1.8ex]\hline
## \hline \\[-1.8ex]
## & \multicolumn{1}{c}{\textit{Dependent variable:}} \\
## \cline{2-2}
## \\[-1.8ex] & Sepal Length \\
## \hline \\[-1.8ex]
## Sepal Width & 0.884$^{***}$ \\
## & (0.162) \\
## & \\
## Virginica & 0.472$^{***}$ \\
## & (0.107) \\
## & \\
## Constant & 3.488$^{***}$ \\
## & (0.453) \\
## & \\
## \hline \\[-1.8ex]
## Observations & 100 \\
## R$^{2}$ & 0.423 \\
## Adjusted R$^{2}$ & 0.411 \\
## Residual Std. Error & 0.509 (df = 97) \\
## F Statistic & 35.484$^{***}$ (df = 2; 97) \\
## \hline
## \hline \\[-1.8ex]
## \textit{Note:} & \multicolumn{1}{r}{$^{*}$p$<$0.1; $^{**}$p$<$0.05; $^{***}$p$<$0.01} \\
## \end{tabular}
## \end{table}
This will create a file named regression_table.tex in
your working directory.
We can also present t-test and z-test results. Here we will compare the mean sepal length of virginica and versicolor.
fit2 <- t.test(iris$Sepal.Length[iris$Species == 1],
iris$Sepal.Length[iris$Species == 0],
alternative = "two.sided",
var.equal = FALSE,
conf.level = 0.95)
fit2
##
## Welch Two Sample t-test
##
## data: iris$Sepal.Length[iris$Species == 1] and iris$Sepal.Length[iris$Species == 0]
## t = 5.6292, df = 94.025, p-value = 1.866e-07
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 0.4220269 0.8819731
## sample estimates:
## mean of x mean of y
## 6.588 5.936
The raw t.test output is not in a table format yet. We
can extract the pieces and put them into a small table using a
matrix:
tt_df <- matrix(c("Virginica", "Versicolor",
fit2$estimate[2], fit2$estimate[1],
"T Statistic:", as.numeric(fit2$statistic),
"p-value:", fit2$p.value),
nrow = 4, ncol = 2, byrow = TRUE)
tt_df
## [,1] [,2]
## [1,] "Virginica" "Versicolor"
## [2,] "5.936" "6.588"
## [3,] "T Statistic:" "5.62916525971982"
## [4,] "p-value:" "1.866144387377e-07"
Now use stargazer to present that table:
stargazer(tt_df,
type = "latex",
summary = FALSE,
title = "T-test: Virginica vs. Versicolor Sepal Length",
digits = 3
)
##
## % Table created by stargazer v.5.2.3 by Marek Hlavac, Social Policy Institute. E-mail: marek.hlavac at gmail.com
## % Date and time: Mon, Jan 05, 2026 - 11:30:58 AM
## \begin{table}[!htbp] \centering
## \caption{T-test: Virginica vs. Versicolor Sepal Length}
## \label{}
## \begin{tabular}{@{\extracolsep{5pt}} cc}
## \\[-1.8ex]\hline
## \hline \\[-1.8ex]
## Virginica & Versicolor \\
## 5.936 & 6.588 \\
## T Statistic: & 5.62916525971982 \\
## p-value: & 1.866144387377e-07 \\
## \hline \\[-1.8ex]
## \end{tabular}
## \end{table}
Here:
You could also set type = "text" if you prefer a
text-only table inside your R Markdown document.
Sometimes you might want a cleaner summary table that includes the
group means, standard deviations, and sample sizes. You can build this
table as a small data frame and then feed it into
stargazer.
t_summary <- iris %>%
mutate(Species = ifelse(Species == 1, "Virginica", "Versicolor")) %>%
group_by(Species) %>%
summarize(
mean_sepal_length = mean(Sepal.Length),
sd_sepal_length = sd(Sepal.Length),
n = n(),
.groups = "drop"
)
t_summary
## # A tibble: 2 × 4
## Species mean_sepal_length sd_sepal_length n
## <chr> <dbl> <dbl> <int>
## 1 Versicolor 5.94 0.516 50
## 2 Virginica 6.59 0.636 50
Now present this summary:
stargazer(t_summary,
type = "html",
summary = FALSE,
title = "Summary Statistics: Sepal Length by Species",
digits = 3,
rownames = FALSE
)
| Species | mean_sepal_length | sd_sepal_length | n |
| Versicolor | 5.936 | 0.516171147063863 | 50 |
| Virginica | 6.588 | 0.635879593274432 | 50 |
You can then describe your t-test results in the text using math notation, for example:
\[ H_0: \mu_{\text{Virginica}} = \mu_{\text{Versicolor}} \quad\text{vs.}\quad H_A: \mu_{\text{Virginica}} \neq \mu_{\text{Versicolor}}. \]
Create your own regression table using stargazer.
Fit the following two models:
Sepal.Length on
Petal.Length.Sepal.Length on
Petal.Length and Species (using the 0/1
indicator we created).Use stargazer to display both models in a single
table.
Customize:
Write 2–3 sentences interpreting the coefficient on
Petal.Length. Use inline math notation for the hypotheses
about that coefficient.
Now practice presenting a t-test result.
Form two groups based on sepal width:
Sepal.Width above the median.Sepal.Width at or below the median.Run a two-sample t-test comparing mean Sepal.Length
across these two groups.
Create a small table with:
Display your table using stargazer and write a short
paragraph interpreting the result. Be explicit about:
Before you knit your R Markdown document, check that:
tidyverse,
stargazer) are loaded.stargazer look reasonable (variables
and models are labeled clearly).Once everything looks good, knit your document to HTML and review the output as you would present it in a problem set or short paper.