# Import necessary libraries
import numpy as np
import pandas as pd
import pyfixest as pf
import statsmodels.formula.api as smf
import maketables as mt
# Load sample dataset
df = pd.read_csv("../data/salaries.csv")
# Estimate regressions for examples
est1 = pf.feols("logwage ~ age", data=df)
est2 = pf.feols("logwage ~ age + female", data=df)
est3 = pf.feols("logwage ~ age + female | worker_type", data=df)
est4 = pf.feols("logwage ~ age + female | worker_type + occupation", data=df)Regression tables with ETable
Regression tables are generated with ETable(). ETable inherits from the MTable base class, which provides all the core output functionality. This means that ETable can generate tables in multiple formats (HTML/GT, docx, LaTeX).
Let us load a sample dataset and run some regressions (here using PyFixest but you can also use statsmodels):
Basic Usage
The simplest way to create to simply call ETable() with a list of models:
mt.ETable([est1, est2, est3, est4])| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
You can also estimate and display multiple regressions with one line of code using the (py)fixest stepwise notation:
mt.ETable(pf.feols("logwage+wage~csw(age, female, age:female)", data=df))| logwage | wage | |||||
|---|---|---|---|---|---|---|
| (1) | (2) | (3) | (4) | (5) | (6) | |
| coef | ||||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.007*** (0.001) |
327.776*** (59.676) |
340.031*** (59.661) |
422.053*** (83.182) |
| female | -0.057** (0.023) |
0.051 (0.086) |
-4128.632*** (1323.781) |
2759.371 (5045.686) |
||
| age × female | -0.003 (0.002) |
-168.821 (119.337) |
||||
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
10.697*** (0.059) |
49378.541*** (2521.411) |
50913.384*** (2563.005) |
47628.477*** (3457.930) |
| stats | ||||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.019 | 0.017 | 0.022 | 0.023 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||||
Keep and drop variables
For example, we can only keep the variables that we’d like, which keeps all variables that fit the provided regex match.
mt.ETable([est1, est2, est3, est4], keep="age")| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
We can use the exact_match argument to select a specific set of variables:
mt.ETable([est1, est2, est3, est4], keep=["age", "female"], exact_match=True)| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
We can also easily drop variables via the drop argument:
mt.ETable([est1, est2, est3, est4], drop=["age"])| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
Specify displayed model statistics
The user can specify the model statistics to be displayed and their order by passing a list of strings to model_stats. Names of the statistics must match the model’s respective attribute names such as “r2”, “adj_r2”, “N”, “r2_within” (see the respective function reference for attributes and omit the leading “_“). The type of standard error estimated can be shown by adding”se_type” to the list. When passing an empty list no model statistics are displayed.
mt.ETable([est1, est2, est3, est4], model_stats=['N','r2','r2_within'])| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Within R2 | - | - | 0.017 | 0.015 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
Model statistics can also be relabeled by passing a dictionary model_stats_labels.
mt.ETable([est1, est2, est3, est4], model_stats=['N','r2'], model_stats_labels={"N": "Number of observations", "r2": "R squared"})| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Number of observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R squared | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
Hide fixed effects
We can hide the rows showing the relevant fixed effects by setting show_fe=False (for instance when the set of fixed effects is the same for all models and you want to describe this in the text or table notes rather than displaying it in the table).
mt.ETable([est1, est2, est3, est4], model_stats=['r2','N'], show_fe=False)| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| stats | ||||
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
Formatting coefficients and standard errors
By default coefficients and standard errors are reported. But we can also ask to output p-values or t-values via the coef_fmt function argument. This parameter accepts a template string that defines the layout and formatting of each coefficient cell. The coef_fmt parameter uses special tokens to represent different elements:
b- The coefficient estimate (beta)se- The standard error
t- The t-statisticp- The p-value\n- Line break (creates a new line in the cell)- Literal text - Any other characters (like parentheses, brackets, spaces) appear as-is
For example, "b \n (se)" creates a two-line cell with the coefficient on the first line and the standard error in parentheses on the second line. You can control the format of numbers in two ways: The digits parameter provides a simple way to set decimal places for all elements when you’re using basic tokens without format specifiers. But you can also add :format after a token (e.g., b:.3f, se:.2e) to specify the exact formatting you want. Here are some common format specifiers:
.3f- 3 decimal places (e.g., 1.234).2e- Scientific notation with 2 decimals (e.g., 1.23e-02)
,.0f- Comma separators, no decimals (e.g., 1,234),.2f- Comma separators with 2 decimals (e.g., 1,234.56):d- Integer formatting (e.g., 1234)
# Show standard errors and p-values
mt.ETable([est1, est2, est3, est4], coef_fmt="b \n (se) \n [p]", digits=4)| logwage | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| age | 0.0052*** (0.0010) [0.0000] |
0.0053*** (0.0010) [0.0000] |
0.0051 (0.0009) [0.1170] |
0.0051 (0.0008) [0.1001] |
| female | -0.0572** (0.0225) [0.0112] |
-0.0570 (0.0409) [0.3967] |
-0.0181 (0.0414) [0.7375] |
|
| Intercept | 10.7272*** (0.0429) [0.0000] |
10.7485*** (0.0436) [0.0000] |
||
| fe | ||||
| occupation | - | - | - | x |
| worker_type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) [p-value] | ||||
# Example: Show coefficients with 2 and standard errors with 3 decimal places
mt.ETable([est1, est2, est3], coef_fmt="b:.2f \n (se:.3f)")| logwage | |||
|---|---|---|---|
| (1) | (2) | (3) | |
| coef | |||
| age | 0.01*** (0.001) |
0.01*** (0.001) |
0.01 (0.001) |
| female | -0.06** (0.023) |
-0.06 (0.041) |
|
| Intercept | 10.73*** (0.043) |
10.75*** (0.044) |
|
| fe | |||
| worker_type | - | - | x |
| stats | |||
| Observations | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | |||
# Scientific notation for small coefficients
mt.ETable([est1, est2, est3], coef_fmt="b:.2e \n (se:.2e)")| logwage | |||
|---|---|---|---|
| (1) | (2) | (3) | |
| coef | |||
| age | 5.16e-03*** (1.01e-03) |
5.33e-03*** (1.02e-03) |
5.08e-03 (9.44e-04) |
| female | -5.72e-02** (2.25e-02) |
-5.70e-02 (4.09e-02) |
|
| Intercept | 1.07e+01*** (4.29e-02) |
1.07e+01*** (4.36e-02) |
|
| fe | |||
| worker_type | - | - | x |
| stats | |||
| Observations | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | |||
Rename variables
You can also rename variables if you want to have a more readable output. Just pass a dictionary to the labels argument. Note that interaction terms will also be relabeled using the specified labels for the interacted variables (if you want to manually relabel an interaction term differently, add it to the dictionary).
labels = {
"logwage": "ln(Wage)",
"wage": "Wage",
"age": "Age",
"female": "Female",
"tenure": "Years of Tenure",
"occupation": "Occupation",
"worker_type": "Worker Type",
"education": "Education Level"
}
mt.ETable([est1, est2, est3, est4], labels=labels)| ln(Wage) | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| Occupation | - | - | - | x |
| Worker Type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
If you want to label the rows indicating the inclusion of fixed effects not with the variable label but with a custom label, you can pass on a separate dictionary to the felabels argument.
mt.ETable(
[est1, est2, est3, est4],
labels=labels,
felabels={"occupation": "Occupation Fixed Effects", "worker_type": "Worker Type Fixed Effects"},
)| ln(Wage) | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057** (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| Occupation Fixed Effects | - | - | - | x |
| Worker Type Fixed Effects | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Significance levels: * p < 0.1, ** p < 0.05, *** p < 0.01. Format of coefficient cell: Coefficient (Std. Error) | ||||
Setting defaults
You can set default options for ETable by changing the class attributes. For example, to change the default model statistics, always use the same labels, digits, and significance levels, you can do the following:
# Set default options for all future ETable calls
mt.ETable.DEFAULT_MODEL_STATS = ["N","r2","r2_within"]
mt.ETable.DEFAULT_COEF_FMT = "b:.3f \n (se:.3f)"
mt.ETable.DEFAULT_SIGNIF_CODE = [0.001, 0.01, 0.05]You can also set default labels. Importantly, default labels are a class attribute of MTable. The reason is that they then also apply to other table types such as (so far) DTable for descriptive statistics.
# Note: Default labels are set as class attribute of MTable
mt.MTable.DEFAULT_LABELS = labelsmt.ETable([est1, est2, est3, est4])| ln(Wage) | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057* (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| Occupation | - | - | - | x |
| Worker Type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Within R2 | - | - | 0.017 | 0.015 |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | ||||
Rename categorical variables
Via the cat_template argument, you can rename categorical variables via a specified template {variable}={value}. This works when either the variable is categorial in the DataFrame, or the C() or i() operators are used in the regresson formula. ´
est5 = pf.feols("logwage ~ age + female + education", data = df)
mt.ETable([est5], cat_template = "{variable}: {value}")| ln(Wage) | |
|---|---|
| (1) | |
| coef | |
| Age | 0.005*** (0.001) |
| Female | -0.042* (0.020) |
| Education Level: High School | -0.302*** (0.027) |
| Education Level: Master's | 0.219*** (0.031) |
| Education Level: PhD | 0.373*** (0.055) |
| Education Level: Some College | -0.199*** (0.028) |
| Intercept | 10.815*** (0.042) |
| stats | |
| Observations | 1,800 |
| R2 | 0.191 |
| Within R2 | - |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | |
But you can also remove the variable name and only keep the levels (categories) by specifying cat_template=“{value}”. Note that the labeling of categories also works in interaction terms:
est6 = pf.feols("logwage ~ age + female + education", data = df)
est7 = pf.feols("logwage ~ age + female + education*age", data = df)
mt.ETable([est6, est7], cat_template="{value}")| ln(Wage) | ||
|---|---|---|
| (1) | (2) | |
| coef | ||
| Age | 0.005*** (0.001) |
0.006*** (0.002) |
| Female | -0.042* (0.020) |
-0.041* (0.021) |
| High School | -0.302*** (0.027) |
-0.348*** (0.103) |
| Master's | 0.219*** (0.031) |
0.285* (0.117) |
| PhD | 0.373*** (0.055) |
0.413 (0.218) |
| Some College | -0.199*** (0.028) |
-0.128 (0.108) |
| High School × Age | 0.001 (0.002) |
|
| Master's × Age | -0.002 (0.003) |
|
| PhD × Age | -0.001 (0.005) |
|
| Some College × Age | -0.002 (0.003) |
|
| Intercept | 10.815*** (0.042) |
10.799*** (0.067) |
| stats | ||
| Observations | 1,800 | 1,800 |
| R2 | 0.191 | 0.191 |
| Within R2 | - | - |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | ||
Custom model headlines
You can also add custom headers for each model by passing a list of strings to the model_headers argument.
mt.ETable(
[est1, est2, est3, est4],
model_heads=["OLS", "OLS", "Fixed Effects", "Fixed Effects"],
)| ln(Wage) | ||||
|---|---|---|---|---|
| OLS | Fixed Effects | |||
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057* (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| Occupation | - | - | - | x |
| Worker Type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Within R2 | - | - | 0.017 | 0.015 |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | ||||
Or change the ordering of headlines having headlines first and then dependent variables using the head_order argument. “hd” stands for headlines then dependent variables, “dh” for dependent variables then headlines. Assigning “d” or “h” can be used to only show dependent variables or only headlines. When head_order=“” only model numbers are shown.
mod1 = pf.feols("logwage ~ age + female", data=df)
mod2 = pf.feols("wage ~ age + female", data=df)
mod3 = pf.feols("logwage ~ age + female | worker_type + occupation", data=df)
mod4 = pf.feols("wage ~ age + female | worker_type + occupation", data=df)
mt.ETable([mod1, mod2, mod3, mod4],
model_heads=["OLS", "OLS", "Fixed Effects", "Fixed Effects"],
head_order="hd")
| OLS | Fixed Effects | |||
|---|---|---|---|---|
| ln(Wage) | Wage | ln(Wage) | Wage | |
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
340.031*** (59.661) |
0.005 (0.001) |
329.914* (12.715) |
| Female | -0.057* (0.023) |
-4128.632** (1323.781) |
-0.018 (0.041) |
-1763.573 (2133.279) |
| Intercept | 10.748*** (0.044) |
50913.384*** (2563.005) |
||
| fe | ||||
| Occupation | - | - | x | x |
| Worker Type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.018 | 0.022 | 0.095 | 0.1 |
| Within R2 | - | - | 0.015 | 0.019 |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | ||||
Remove the dependent variables from the headers:
mt.ETable(
[est1, est2, est3, est4],
head_order="",
)| (1) | (2) | (3) | (4) | |
|---|---|---|---|---|
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057* (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| Occupation | - | - | - | x |
| Worker Type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Within R2 | - | - | 0.017 | 0.015 |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | ||||
Further custom model information
You can add further custom model statistics/information to the bottom of the table by using the custom_stats argument to which you pass a dictionary with the name of the row and lists of values. The length of the lists must be equal to the number of models.
mt.ETable(
[est1, est2, est3, est4],
show_fe=False,
custom_model_stats={
"Fixed Effects": ["No", "No", "Worker Type", "Worker Type & Occupation"],
"Data Type": ["Cross-section", "Cross-section", "Cross-section", "Cross-section"],
},
)| ln(Wage) | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057* (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| stats | ||||
| Fixed Effects | No | No | Worker Type | Worker Type & Occupation |
| Data Type | Cross-section | Cross-section | Cross-section | Cross-section |
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Within R2 | - | - | 0.017 | 0.015 |
| Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error) | ||||
Custom table notes
You can replace the default table notes with your own notes using the notes argument.
mynotes = "This table shows wage regressions using a simulated dataset of 1,800 workers. The dependent variable is log wage. Models progressively add controls and fixed effects."
mt.ETable(
[est1, est2, est3, est4],
notes=mynotes,
)| ln(Wage) | ||||
|---|---|---|---|---|
| (1) | (2) | (3) | (4) | |
| coef | ||||
| Age | 0.005*** (0.001) |
0.005*** (0.001) |
0.005 (0.001) |
0.005 (0.001) |
| Female | -0.057* (0.023) |
-0.057 (0.041) |
-0.018 (0.041) |
|
| Intercept | 10.727*** (0.043) |
10.748*** (0.044) |
||
| fe | ||||
| Occupation | - | - | - | x |
| Worker Type | - | - | x | x |
| stats | ||||
| Observations | 1,800 | 1,800 | 1,800 | 1,800 |
| R2 | 0.014 | 0.018 | 0.082 | 0.095 |
| Within R2 | - | - | 0.017 | 0.015 |
| This table shows wage regressions using a simulated dataset of 1,800 workers. The dependent variable is log wage. Models progressively add controls and fixed effects. | ||||