| Title: | Microdata Infrastructure Tools for Firm-Level Microdata Research |
|---|---|
| Description: | Supports the full analysis pipeline for researchers working with firm-level microdata. Provides data tools for panel preparation (import, outlier detection, classification harmonization), analytical methods (production function estimation, capital stock measurement, markups, intensity measures, distributions, regression, clustering), and disclosure tools for tagging outputs with dominance and observation counts before aggregation and publication. Production function estimation implements methods by Ackerberg, Caves and Frazer (2015) <doi:10.3982/ECTA13408>, Levinsohn and Petrin (2003) <doi:10.1111/1467-937X.00246>, Wooldridge (2009) <doi:10.1016/j.econlet.2009.04.026>, Petrin, Poi and Levinsohn (2004) <doi:10.1177/1536867X0400400202>, and Arellano and Bond (1991) <doi:10.2307/2297968> with the "too many instruments" correction by Roodman (2009) <doi:10.1111/j.1468-0084.2008.00542.x>. Markup estimation follows De Loecker and Warzynski (2012) <doi:10.1257/aer.102.6.2437>. Cost-share production function estimation follows Basu and Fernald (1997) <doi:10.1086/262073>. Capital stock estimation via the Perpetual Inventory Method follows OECD (2009) <doi:10.1787/9789264068476-en>. |
| Authors: | Daniele Aglio [aut], Eric Bartelsman [aut], Mirja Hälbig [aut], Marco Miorandi [aut], Johanna Weiss [aut, cre], Alessandro Zona Mattioli [aut], Julián Díaz-Acosta [ctb], Alberto Ferreira [ctb], Javier Miranda [ctb], Marcelo Piemonte Ribeiro [ctb], Reetuparna Vishwanath [ctb], Chengzi Yi [ctb], European Union [fnd] (Technical Support Instrument (TSI), project ProdTool, TSI-2025-MULTIMSPROD-IBA, TSI Project Number 101261159) |
| Maintainer: | Johanna Weiss <[email protected]> |
| License: | GPL-3 |
| Version: | 0.1.1 |
| Built: | 2026-10-08 22:19:47 UTC |
| Source: | https://github.com/secretariat-compnet/mditools |
Supports the full analysis pipeline for researchers working with firm-level microdata. Provides data tools for panel preparation (import, outlier detection, classification harmonization), analytical methods (production function estimation, capital stock measurement, markups, intensity measures, distributions, regression, clustering), and disclosure tools for tagging outputs with dominance and observation counts before aggregation and publication. Production function estimation implements methods by Ackerberg, Caves and Frazer (2015) doi:10.3982/ECTA13408, Levinsohn and Petrin (2003) doi:10.1111/1467-937X.00246, Wooldridge (2009) doi:10.1016/j.econlet.2009.04.026, Petrin, Poi and Levinsohn (2004) doi:10.1177/1536867X0400400202, and Arellano and Bond (1991) doi:10.2307/2297968 with the "too many instruments" correction by Roodman (2009) doi:10.1111/j.1468-0084.2008.00542.x. Markup estimation follows De Loecker and Warzynski (2012) doi:10.1257/aer.102.6.2437. Cost-share production function estimation follows Basu and Fernald (1997) doi:10.1086/262073. Capital stock estimation via the Perpetual Inventory Method follows OECD (2009) doi:10.1787/9789264068476-en.
We thank Jorge de la Cal Medina, Ashim Dubey, Dominik Frommeyer (Statistisches Bundesamt, Destatis), Adam Haunch, Rachel Kühn (Statistisches Bundesamt, Destatis) and Elena Sponga.
Funded by the European Union under the Technical Support Instrument (TSI). This package was developed as part of the project ProdTool (TSI-2025-MULTIMSPROD-IBA, TSI Project Number: 101261159). Views and opinions expressed are however those of the author(s) only and do not necessarily reflect those of the European Union or the European Commission. Neither the European Union nor the granting authority can be held responsible for them.
Maintainer: Johanna Weiss [email protected]
Authors:
Johanna Weiss [email protected]
Daniele Aglio
Eric Bartelsman
Mirja H<U+00E4>lbig
Marco Miorandi
Alessandro Zona Mattioli
Other contributors:
Juli<U+00E1>n D<U+00ED>az-Acosta [contributor]
Alberto Ferreira [contributor]
Javier Miranda [contributor]
Marcelo Piemonte Ribeiro [contributor]
Reetuparna Vishwanath [contributor]
Chengzi Yi [contributor]
European Union (Technical Support Instrument (TSI), project ProdTool, TSI-2025-MULTIMSPROD-IBA, TSI Project Number 101261159) [funder]
Useful links:
Report bugs at https://github.com/Secretariat-CompNet/mditools/issues
Estimates a production function using the Ackerberg-Caves-Frazer (ACF) method (Ackerberg, Caves & Frazer 2015, Econometrica). Runs a two-stage GMM procedure: a first-stage OLS (with optional polynomial and time fixed effects) to recover the productivity proxy Phi, followed by GMM minimization to identify input elasticities.
tfp = (Phi or y) - X*beta depending on TFP_minuend; with
TFP_minuend = "y" this matches the y - X*beta convention of the
other estimators.
mdi_acf_prodest( DT, y, endog, exog, instr, id, time, spec = "cd", degree = 3, lower_bound_theta = 0, upper_bound_theta = 1, TFP_demeaned = TRUE, TFP_minuend = c("Phi", "y"), Omega_estimates = TRUE, time_FE = FALSE, extended_instr = FALSE )mdi_acf_prodest( DT, y, endog, exog, instr, id, time, spec = "cd", degree = 3, lower_bound_theta = 0, upper_bound_theta = 1, TFP_demeaned = TRUE, TFP_minuend = c("Phi", "y"), Omega_estimates = TRUE, time_FE = FALSE, extended_instr = FALSE )
DT |
A |
y |
Character. Name of the output variable column. |
endog |
Character vector. Names of endogenous input columns (e.g. labour). |
exog |
Character vector. Names of exogenous input columns (e.g. capital). |
instr |
Character vector. Names of instrument columns for the first stage polynomial. |
id |
Character. Name of the firm/unit identifier column. |
time |
Character. Name of the time period column. |
spec |
Character. Functional form. Only |
degree |
Integer. Degree of the polynomial used in the first stage and
the Omega law of motion. Default |
lower_bound_theta |
Numeric. Lower bound for elasticity estimates in
the GMM optimisation. Default |
upper_bound_theta |
Numeric. Upper bound for elasticity estimates in
the GMM optimisation. Default |
TFP_demeaned |
Logical. If |
TFP_minuend |
Character. Whether TFP is computed as residual from
|
Omega_estimates |
Logical. If |
time_FE |
Logical. If |
extended_instr |
Logical. If |
A data.table with one row per observation in the GMM sample,
containing:
id, time columns (using the names supplied)
tfp: total factor productivity
el_<input>: estimated input elasticity for each input
TFP_demeaned (if TFP_demeaned = TRUE): period-demeaned TFP
g_b_slopes, g_b_intercept (if Omega_estimates = TRUE)
NumObs: number of observations used in the GMM stage
convergence: optimiser convergence code (0 = converged)
library(data.table) set.seed(1) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) result <- mdi_acf_prodest( DT, y = "y", endog = "l", exog = "k", instr = "m", id = "id", time = "year", degree = 2, TFP_demeaned = FALSE )library(data.table) set.seed(1) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) result <- mdi_acf_prodest( DT, y = "y", endog = "l", exog = "k", instr = "m", id = "id", time = "year", degree = 2, TFP_demeaned = FALSE )
Aggregates variables from a sub-aggregate level to a higher aggregate level
within a data.table. Supports multiple aggregation types, including sum,
standard deviation, mean, quantiles (25%, 50%, 75%), median, count, number of
missing values, number of non-missing values, number of empty strings,
number of zeros, number of positive values, and the Herfindahl-Hirschman Index (HHI).
The function can optionally:
apply a weight column to variables before aggregation,
merge aggregated statistics back into the original dataset,
compute the number of unique firms in the input data,
and apply disclosure control criteria.
mdi_aggregate( DT, var_list, bygroups, agg_type = c("sum"), weight_col = NULL, mrg = FALSE, disclosure = TRUE, count_firms = FALSE, dom_formula = c("top_share", "residual"), domVar = "var", domNr = 2L, minNumObs = 5L )mdi_aggregate( DT, var_list, bygroups, agg_type = c("sum"), weight_col = NULL, mrg = FALSE, disclosure = TRUE, count_firms = FALSE, dom_formula = c("top_share", "residual"), domVar = "var", domNr = 2L, minNumObs = 5L )
DT |
A |
var_list |
A character vector of variable names to aggregate. |
bygroups |
A character vector of grouping variables defining the aggregation level. |
agg_type |
A character vector specifying the type(s) of aggregation to perform.
Supported types: |
weight_col |
Optional character string naming a weight column in |
mrg |
Logical. If |
disclosure |
Logical. If |
count_firms |
Logical. If |
dom_formula |
Character. Dominance formula passed to |
domVar |
Character. Name of the dominance variable passed to
|
domNr |
Integer. Number of top firms used in the dominance check,
passed to |
minNumObs |
Integer. Minimum number of observations used for the
quantile smoothing window in |
If mrg = FALSE: An aggregated data.table containing the requested statistics,
optionally with disclosure variables and number of firms.
If mrg = TRUE: The input data.table with new columns containing the
aggregated statistics.
library(data.table) DT <- data.table( firmid = rep(1:5, each = 2), year = rep(2020:2021, 5), nace = rep(c("A", "B"), 5), emp = c(10, 12, 5, 6, 20, 22, 8, 9, 15, 16), rev = c(100, 110, 50, 55, 200, 210, 80, 85, 150, 155) ) # Sum by nace mdi_aggregate(DT, "emp", "nace", "sum", disclosure = FALSE) # Multiple agg types mdi_aggregate(DT, "emp", "nace", c("sum", "mean"), disclosure = FALSE) # Merge back into original DT mdi_aggregate(DT, "emp", "nace", "sum", mrg = TRUE, disclosure = FALSE) # Count unique firms mdi_aggregate(DT, "emp", "nace", "sum", count_firms = TRUE, disclosure = FALSE)library(data.table) DT <- data.table( firmid = rep(1:5, each = 2), year = rep(2020:2021, 5), nace = rep(c("A", "B"), 5), emp = c(10, 12, 5, 6, 20, 22, 8, 9, 15, 16), rev = c(100, 110, 50, 55, 200, 210, 80, 85, 150, 155) ) # Sum by nace mdi_aggregate(DT, "emp", "nace", "sum", disclosure = FALSE) # Multiple agg types mdi_aggregate(DT, "emp", "nace", c("sum", "mean"), disclosure = FALSE) # Merge back into original DT mdi_aggregate(DT, "emp", "nace", "sum", mrg = TRUE, disclosure = FALSE) # Count unique firms mdi_aggregate(DT, "emp", "nace", "sum", count_firms = TRUE, disclosure = FALSE)
This tool clusters observations using one of the following methods:
k-means;
hierarchical clustering with Ward linkage;
hierarchical clustering with complete linkage;
hierarchical clustering with average linkage;
hierarchical clustering with single linkage;
PAM;
Gaussian mixture;
DBSCAN. The tool can optionally compute:
total within-cluster sum of squares (WSS);
average silhouette width;
bootstrap-style ARI stability;
the WSS or silhouette selection plot used to choose the number of clusters.
mdi_clustering( DT, id_vars, cluster_vars, method = c("hc_ward", "hc_complete", "hc_average", "hc_single", "kmeans", "pam", "mclust", "dbscan"), k_selection = c("fixed", "automatic"), k_fixed = NULL, automatic_by_wss = FALSE, automatic_by_silhouette = FALSE, compute_wss = TRUE, compute_silhouette = TRUE, compute_stability = FALSE, plot_selection = FALSE, k_grid = 2:25, exclude_noise = TRUE, B_boot = 200, nstart = 100, seed = 123, minPts = 4, q = 0.95, eps = NULL, G = 1:10, standardize = TRUE, na_action = c("stop", "omit"), cluster_col = "cluster", overwrite_cluster_col = FALSE, bootstrap_reselect_parameters = FALSE, verbose = TRUE )mdi_clustering( DT, id_vars, cluster_vars, method = c("hc_ward", "hc_complete", "hc_average", "hc_single", "kmeans", "pam", "mclust", "dbscan"), k_selection = c("fixed", "automatic"), k_fixed = NULL, automatic_by_wss = FALSE, automatic_by_silhouette = FALSE, compute_wss = TRUE, compute_silhouette = TRUE, compute_stability = FALSE, plot_selection = FALSE, k_grid = 2:25, exclude_noise = TRUE, B_boot = 200, nstart = 100, seed = 123, minPts = 4, q = 0.95, eps = NULL, G = 1:10, standardize = TRUE, na_action = c("stop", "omit"), cluster_col = "cluster", overwrite_cluster_col = FALSE, bootstrap_reselect_parameters = FALSE, verbose = TRUE )
DT |
A data.table or data.frame with observations to be clustered. Data frames are silently converted to data.table. |
id_vars |
Character vector with one or more id variables. |
cluster_vars |
Character vector with the numeric variables used for clustering. |
method |
Clustering method. One of |
k_selection |
Selection method for k: |
k_fixed |
Fixed number of clusters. Used only when
|
automatic_by_wss |
Logical. If |
automatic_by_silhouette |
Logical. If |
compute_wss |
Logical. If |
compute_silhouette |
Logical. If |
compute_stability |
Logical. If |
plot_selection |
Logical. If |
k_grid |
Candidate values of k for automatic selection. Default
|
exclude_noise |
Logical. Mainly relevant for DBSCAN; if |
B_boot |
Number of bootstrap repetitions. Default |
nstart |
Number of random starts for k-means. Default |
seed |
Integer seed for reproducibility. Default |
minPts |
DBSCAN |
q |
Quantile used to choose DBSCAN |
eps |
Numeric or |
G |
Candidate number of mixture components for mclust. Default |
standardize |
Logical. If |
na_action |
Character. How to handle missing values in |
cluster_col |
Character. Name of the output column for the cluster
assignment. Default |
overwrite_cluster_col |
Logical. If |
bootstrap_reselect_parameters |
Logical. Only used when
|
verbose |
Logical. If |
a list with:
data: the original input data.table with an additional clustering column, by default called "cluster".
chosen_k: final selected number of clusters, when relevant.
wss: final WSS result, if requested.
silhouette: final silhouette result, if requested.
stability: bootstrap-style ARI stability result, if requested.
selection_plot: recorded plot object, if plot_selection = TRUE.
library(data.table) set.seed(1) DT <- data.table( firmid = 1:30, x1 = c(rnorm(15, 0, 0.5), rnorm(15, 5, 0.5)), x2 = c(rnorm(15, 0, 0.5), rnorm(15, 5, 0.5)) ) result <- mdi_clustering(DT, id_vars = "firmid", cluster_vars = c("x1", "x2"), method = "kmeans", k_selection = "fixed", k_fixed = 2, compute_wss = TRUE, compute_silhouette = TRUE, compute_stability = FALSE, verbose = FALSE)library(data.table) set.seed(1) DT <- data.table( firmid = 1:30, x1 = c(rnorm(15, 0, 0.5), rnorm(15, 5, 0.5)), x2 = c(rnorm(15, 0, 0.5), rnorm(15, 5, 0.5)) ) result <- mdi_clustering(DT, id_vars = "firmid", cluster_vars = c("x1", "x2"), method = "kmeans", k_selection = "fixed", k_fixed = 2, compute_wss = TRUE, compute_silhouette = TRUE, compute_stability = FALSE, verbose = FALSE)
Implements a cost-shares approach to production function estimation:
Build firm-time input shares from expenditures in levels.
Average shares by (bygroup, time).
Compute TFP as a log-index residual using averaged shares.
Optionally demean TFP by (bygroup, time).
mdi_cs_prodest( DT, y, endog, exog, id, time, bygroup, log_values = TRUE, TFP_demeaned = TRUE )mdi_cs_prodest( DT, y, endog, exog, id, time, bygroup, log_values = TRUE, TFP_demeaned = TRUE )
DT |
A |
y |
Character scalar. Name of the output variable column. |
endog |
Character scalar. Name of the free input (expenditure) column. |
exog |
Character scalar. Name of the state input (expenditure) column. |
id |
Character scalar. Name of the entity identifier column. |
time |
Character scalar. Name of the time period column. |
bygroup |
Character scalar. Name of the grouping variable column (e.g., industry code). |
log_values |
Logical. If |
TFP_demeaned |
Logical. If |
A data.table with one row per observation (after cost-share
filtering), containing:
id, time, bygroup columns
el_<endog>, el_<exog>: averaged input elasticities
tfp: total factor productivity (log-index residual)
TFP_demeaned (if TFP_demeaned = TRUE)
NumObs: total number of observations used (matches the convention
of the other estimators in this suite)
Returns NULL if no valid observations remain after filtering.
library(data.table) set.seed(1) n <- 120 DT <- data.table( id = rep(1:30, each = 4), year = rep(2000:2003, times = 30), nace = rep(c("A", "B"), each = 60), y = log(runif(n, 5, 50)), labour = log(runif(n, 1, 10)), capital = log(runif(n, 2, 20)) ) mdi_cs_prodest(DT, y = "y", endog = "labour", exog = "capital", id = "id", time = "year", bygroup = "nace")library(data.table) set.seed(1) n <- 120 DT <- data.table( id = rep(1:30, each = 4), year = rep(2000:2003, times = 30), nace = rep(c("A", "B"), each = 60), y = log(runif(n, 5, 50)), labour = log(runif(n, 1, 10)), capital = log(runif(n, 2, 20)) ) mdi_cs_prodest(DT, y = "y", endog = "labour", exog = "capital", id = "id", time = "year", bygroup = "nace")
Computes and attaches disclosure-control variables to an aggregated dataset. The function calculates a dominance measure and the number of non-missing observations per group.
Two dominance formulas are available via dom_formula:
"top_share" (default): share of the top domNr firms in the group total.
"residual": , where and
are the two largest values. Used when the dominance criterion
is defined as the residual relative to the largest firm.
This function is normally called internally by mdi_aggregate() when
disclosure = TRUE, but can also be used standalone.
mdi_disclose_crit( DT, domVar = "var", domNr = 2, bygroups, var_list = NULL, dom_formula = c("top_share", "residual"), count_firms = FALSE, firm_col = "firmid", ent_col = "entid" )mdi_disclose_crit( DT, domVar = "var", domNr = 2, bygroups, var_list = NULL, dom_formula = c("top_share", "residual"), count_firms = FALSE, firm_col = "firmid", ent_col = "entid" )
DT |
A |
domVar |
Character. Variable used for the dominance criterion.
Use |
domNr |
Numeric. Number of top firms to consider in the dominance
criterion (e.g. top 1, 2, or 3). Default |
bygroups |
Character vector of grouping variables, as in
|
var_list |
Character vector of variables to include when
|
dom_formula |
Character. Formula used to compute the dominance share.
|
count_firms |
Logical. If |
firm_col |
Character. Column name used to count unique firms when
|
ent_col |
Character. Column name used to count unique enterprises when
|
For domVar != "var", the named column must already be present in DT.
One dominance column (domPerc) is returned and dom_formula is ignored.
For domVar = "var", separate dominance columns are created for each
variable in var_list (domPerc_<var>), using the formula specified
by dom_formula.
When count_firms = TRUE, firm_col and ent_col must be present in
DT; the function stops with an error if either is missing.
A data.table with the same grouping structure as the input, plus:
One or more domPerc_* columns: dominance share per group.
A column NumObs: number of non-missing observations per group.
NumFirms and NumEnt (only when count_firms = TRUE).
library(data.table) DT <- data.table( nace = rep(c("A", "B"), each = 5), year = rep(2020L, 10), emp = c(10, 20, 5, 15, 8, 12, 25, 6, 14, 9), firmid = 1:10, entid = c(1,1,2,2,3,4,4,5,5,6) ) # Standard top-share formula mdi_disclose_crit(DT, domVar = "var", domNr = 2L, bygroups = c("nace", "year"), var_list = "emp") # Residual formula with firm counts mdi_disclose_crit(DT, domVar = "var", domNr = 2L, bygroups = c("nace", "year"), var_list = "emp", dom_formula = "residual", count_firms = TRUE) # Single-column dominance (column must be present in DT) mdi_disclose_crit(DT, domVar = "emp", domNr = 2L, bygroups = c("nace", "year"))library(data.table) DT <- data.table( nace = rep(c("A", "B"), each = 5), year = rep(2020L, 10), emp = c(10, 20, 5, 15, 8, 12, 25, 6, 14, 9), firmid = 1:10, entid = c(1,1,2,2,3,4,4,5,5,6) ) # Standard top-share formula mdi_disclose_crit(DT, domVar = "var", domNr = 2L, bygroups = c("nace", "year"), var_list = "emp") # Residual formula with firm counts mdi_disclose_crit(DT, domVar = "var", domNr = 2L, bygroups = c("nace", "year"), var_list = "emp", dom_formula = "residual", count_firms = TRUE) # Single-column dominance (column must be present in DT) mdi_disclose_crit(DT, domVar = "emp", domNr = 2L, bygroups = c("nace", "year"))
Applies disclosure control rules to regression output tables. Rows that do not meet minimum thresholds for degrees of freedom, number of observations, or (for Germany) number of firms are flagged and sensitive regression statistics are masked.
mdi_disclose_reg_tab( DT, min_obs = 5, show_disclosed = FALSE, disc_method = c("obs_df", "firm_count") )mdi_disclose_reg_tab( DT, min_obs = 5, show_disclosed = FALSE, disc_method = c("obs_df", "firm_count") )
DT |
A |
min_obs |
Numeric. Minimum threshold used for disclosure checks.
Default |
show_disclosed |
Logical. If |
disc_method |
Character. Disclosure rule to apply. |
disc_method = "obs_df": disclosure is triggered when either
df < min_obs or NumObs < min_obs.
disc_method = "firm_count": disclosure is based on
NumFirms < min_obs or NumEnt < min_obs. Used for Germany.
The following regression statistics may be masked if disclosure applies:
"Estimate", "Std. Error", "z value", "Pr(>|z|)",
"ci.lower", "ci.upper", "R2", "AdjR2", "AIC", "BIC", "LogLik".
A list with three elements:
DT |
A |
vars |
A character string listing the disclosed coefficient names
(for use in output description). If all rows are masked, returns
|
redacted_n |
An integer count of the number of rows flagged and masked. |
library(data.table) DT <- data.table( coef = c("(Intercept)", "x1"), Estimate = c(1.2, 0.5), `Std. Error` = c(0.1, 0.05), df = c(20L, 20L), NumObs = c(25L, 25L) ) result <- mdi_disclose_reg_tab(DT, min_obs = 3L) result$DT result$redacted_nlibrary(data.table) DT <- data.table( coef = c("(Intercept)", "x1"), Estimate = c(1.2, 0.5), `Std. Error` = c(0.1, 0.05), df = c(20L, 20L), NumObs = c(25L, 25L) ) result <- mdi_disclose_reg_tab(DT, min_obs = 3L) result$DT result$redacted_n
Estimates the dynamic Cobb-Douglas production function
by first-differencing to eliminate the firm fixed effect ,
then applying one-step GMM with lagged levels of (y, l, k) as instruments
for the differenced regressors. Reference: Arellano & Bond (1991, ReStud).
Capital is treated as predetermined (chosen at t-1), so for
s >= 1 are valid instruments for . Labour is treated as
endogenous (chosen at t with knowledge of ), so
for s >= 2 are valid. Lagged output for
s >= 2 instruments . The lag depth is capped by
max_lag_Z to avoid the "too many instruments" problem (Roodman 2009).
Estimation is one-step GMM with weight matrix , where H
is block-diagonal by firm with tridiagonal blocks (2 on the diagonal, -1 on
the first off-diagonals) reflecting the MA(1) structure of
under iid . Standard errors use
the cluster-robust sandwich formula (clusters = firms).
tfp is reported in levels as tfp = y - beta_l*l - beta_k*k, matching
the convention of the other estimators (ACF/LP/OLS/WDRG). It absorbs the
firm fixed effect and the lagged-y persistence; it is NOT the productivity
innovation .
mdi_dpgmm_prodest( DT, y, endog, exog, id, time, max_lag_Z = 2, TFP_demeaned = TRUE )mdi_dpgmm_prodest( DT, y, endog, exog, id, time, max_lag_Z = 2, TFP_demeaned = TRUE )
DT |
A |
y |
Character scalar. Output variable name (in logs). |
endog |
Character scalar. Free input name (e.g. "ln_labor_cost"). |
exog |
Character scalar. State input name (e.g. "ln_capital"). |
id |
Character scalar. Firm identifier column. |
time |
Character scalar. Time identifier column. |
max_lag_Z |
Integer >= 1. Maximum lag depth for instruments. Default |
TFP_demeaned |
Logical. If |
A data.table with one row per firm-year (subset where y,
endog, exog are non-missing). Columns: id, time,
el_<endog>, el_<exog>, se_el_<endog>,
se_el_<exog>, rho, se_rho, tfp, NumObs,
the diagnostics sargan_J/sargan_df/sargan_pval and
ar1_z/ar1_pval/ar2_z/ar2_pval, and optionally
TFP_demeaned. Under iid : AR(1) should reject,
AR(2) should not; Sargan tests the overidentifying restrictions.
library(data.table) set.seed(1) n_firms <- 40; n_periods <- 6 n <- n_firms * n_periods DT <- data.table( id = rep(seq_len(n_firms), each = n_periods), year = rep(seq(2000L, length.out = n_periods), times = n_firms), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5) ) result <- mdi_dpgmm_prodest(DT, y = "y", endog = "l", exog = "k", id = "id", time = "year", TFP_demeaned = FALSE)library(data.table) set.seed(1) n_firms <- 40; n_periods <- 6 n <- n_firms * n_periods DT <- data.table( id = rep(seq_len(n_firms), each = n_periods), year = rep(seq(2000L, length.out = n_periods), times = n_firms), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5) ) result <- mdi_dpgmm_prodest(DT, y = "y", endog = "l", exog = "k", id = "id", time = "year", TFP_demeaned = FALSE)
Estimates firm-level markup following De Loecker (2012): markup is the output elasticity of an input divided by its expenditure share of revenue.
mdi_estimate_markup(DT, oe = "oe_l", rev_col = "nq", input_cost = "nm")mdi_estimate_markup(DT, oe = "oe_l", rev_col = "nq", input_cost = "nm")
DT |
A |
oe |
Character scalar. Name of the output elasticity column.
Default |
rev_col |
Character scalar. Name of the total revenue column.
Default |
input_cost |
Character scalar. Name of the input cost column.
Default |
A data.table with a single column markup.
library(data.table) DT <- data.table( oe_l = c(0.6, 0.7, 0.5), nq = c(100, 200, 150), nm = c(50, 80, 60) ) mdi_estimate_markup(DT)library(data.table) DT <- data.table( oe_l = c(0.6, 0.7, 0.5), nq = c(100, 200, 150), nm = c(50, 80, 60) ) mdi_estimate_markup(DT)
mdi_estimate_prodfun() is a wrapper that estimates Cobb-Douglas production functions
on firm-level panel data using a selectable set of estimators (methods).
It is designed for grid runs across within-method specifications (e.g., degree choices,
time fixed effects, alternative demeaning) and returns standardized outputs that can be
pooled across methods and industries.
The wrapper is typically run "by industry" (or another grouping variable) using bygroup.
Within each group, the function calls one estimator at a time and binds results into a common
panel-style output format including:
firm id and year (or generic id, time)
elasticities with standardized names el_<var>
total factor productivity proxy (tfp) and optional de-meaned version (TFP_demeaned)
book-keeping: NumObs, plus method/spec identifiers if requested
mdi_estimate_prodfun( DT, methods, y, endog, exog, instr = NULL, id, time, bygroup, acf_args = list(), lp_args = list(), wdrg_args = list(), dpgmm_args = list(), ols_args = list(), cs_args = list(), verbose = TRUE, drop_empty = TRUE, allowed_ids = NULL )mdi_estimate_prodfun( DT, methods, y, endog, exog, instr = NULL, id, time, bygroup, acf_args = list(), lp_args = list(), wdrg_args = list(), dpgmm_args = list(), ols_args = list(), cs_args = list(), verbose = TRUE, drop_empty = TRUE, allowed_ids = NULL )
DT |
A |
methods |
Character vector of methods to run. Supported: |
y |
Character scalar. Output variable name (typically log output/value added). |
endog |
Character vector. Free/endogenous input(s) (e.g., log labor cost). |
exog |
Character vector. State/exogenous input(s) (e.g., log capital). |
instr |
Character vector. Proxy/instrument variable(s) (e.g., log materials).
Required by |
id |
Character scalar. Firm identifier column. |
time |
Character scalar. Time identifier column. |
bygroup |
Character scalar. Column name of the grouping variable (e.g. industry code); estimation is performed separately for each unique value. |
acf_args, lp_args, wdrg_args, dpgmm_args, ols_args, cs_args
|
Optional lists of tuning arguments per method. See Details. |
verbose |
Logical. If |
drop_empty |
Logical. If |
allowed_ids |
Optional character vector. If non-NULL, restricts the accepted values of
|
The wrapper assumes all production-function variables are in logs unless a method explicitly
requires levels (e.g., cost shares with log_values=TRUE will exponentiate internally).
Minimal required columns in DT are: output y; free input(s) endog;
state input(s) exog; proxy/instruments instr (ACF/LP/WRDG); panel identifiers
id, time; and the grouping variable bygroup.
Each estimator performs its own NA filtering on the variables it needs; hence the effective sample can differ by method/spec.
Methods are selected via methods. The wrapper recognizes:
"acf"Ackerberg-Caves-Frazer (2015) control-function estimator (Cobb-Douglas).
First-stage polynomial in inputs and proxy to construct , then a GMM stage with
lagged inputs as instruments. Returns firm-level elasticities and a residual-based tfp.
"lp"Levinsohn-Petrin (2003) proxy estimator (Cobb-Douglas).
"wdrg"Wooldridge (2009) system-GMM estimator. Stacked two-equation GMM,
estimated linearly in the parameters (the polynomial coefficients on and
are free, separate vectors; this is more general than the
random-walk-with-drift case but does not impose the structural AR(G) restriction of a
degree-G nonlinear law of motion). Returns common elasticities, se_el_<var>,
tfp = y - X*beta, and alpha_hat as a diagnostic column.
"dpgmm"Arellano-Bond (1991) difference-GMM for the dynamic PF
.
First-differences to remove the firm fixed effect; lagged levels of (y, l, k) instrument the
differenced regressors (K predetermined, L endogenous). One-step GMM, cluster-robust SEs,
Sargan/Hansen and AR(1)/AR(2) diagnostics. Returns el_<var>, rho,
tfp = y - beta_l l - beta_k k.
"ols"Pooled OLS baseline with flexible polynomial controls (Cobb-Douglas).
tfp = y - X*beta. Use degree = 1 for the clean naive baseline.
"cs"Cost-shares (index-number) approach for Cobb-Douglas.
xxxx_args)Each method accepts an optional list of tuning arguments passed via a dedicated parameter name:
acf_args, lp_args, wdrg_args, dpgmm_args, ols_args, cs_args.
Unspecified fields fall back to method defaults.
ACF arguments (acf_args): spec, degree,
lower_bound_theta, upper_bound_theta, TFP_demeaned, TFP_minuend
("Phi"/"y"), Omega_estimates, time_FE, and extended_instr (logical,
default FALSE; if TRUE adds to the instrument set per ACF eq 28 for
overidentification).
LP arguments (lp_args): spec, degree, lower_bound_theta,
upper_bound_theta, TFP_demeaned, TFP_minuend ("y"/"Phi"),
Omega_estimates, time_FE.
Wooldridge arguments (wdrg_args): degree, tol,
TFP_demeaned, TFP_minuend ("y" only).
Dynamic panel GMM arguments (dpgmm_args): max_lag_Z (integer >= 1,
default 2; instrument lag depth), TFP_demeaned.
OLS arguments (ols_args): spec, degree, TFP_demeaned.
Cost shares arguments (cs_args): log_values, TFP_demeaned.
A data.table with one row per firm-year (or per used observation), containing
bygroup, method, id, time, el_<var>, tfp, and
method-specific extras (TFP_demeaned, rho, se_el_<var>, diagnostics),
plus NumObs.
library(data.table) set.seed(42) n <- 200 DT <- data.table( firmid = rep(1:50, each = 4), year = rep(2000:2003, 50), sector = rep(c("A", "B"), each = 100), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) mdi_estimate_prodfun( DT, methods = c("ols", "acf"), y = "y", endog = "l", exog = "k", instr = "m", id = "firmid", time = "year", bygroup = "sector" )library(data.table) set.seed(42) n <- 200 DT <- data.table( firmid = rep(1:50, each = 4), year = rep(2000:2003, 50), sector = rep(c("A", "B"), each = 100), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) mdi_estimate_prodfun( DT, methods = c("ols", "acf"), y = "y", endog = "l", exog = "k", instr = "m", id = "firmid", time = "year", bygroup = "sector" )
Aggregates variables in var_list to unique values of the hierarchical
dimensions specified in hhfile by groups. Aggregation is performed at
each level specified by hier using mdi_aggregate().
mdi_hier_apply( DT, hhfile, var_list, bygroups, hier, agg_type = "sum", weight_col = NULL, mrg = FALSE, disclosure = TRUE )mdi_hier_apply( DT, hhfile, var_list, bygroups, hier, agg_type = "sum", weight_col = NULL, mrg = FALSE, disclosure = TRUE )
DT |
A |
hhfile |
A |
var_list |
A character vector of numeric variable names in |
bygroups |
A character vector of grouping variables in |
hier |
Character. Either a single node name (e.g. |
agg_type |
Character vector of aggregation types passed to
|
weight_col |
Optional character string naming a weight column in
|
mrg |
Logical. If |
disclosure |
Logical. If |
A data.table containing the aggregated variables from var_list
at each requested hierarchy level, combined via rbindlist. A node
column identifies the aggregation level of each row.
library(data.table) hhfile <- data.table( h_0 = c("A1", "A2", "B1", "B2"), h_1 = c("A", "A", "B", "B") ) DT <- data.table( nace = c("A1", "A2", "B1", "B2"), year = rep(2020L, 4), emp = c(10L, 20L, 15L, 25L) ) mdi_hier_apply(DT, hhfile, var_list = "emp", bygroups = c("nace", "year"), hier = "h_1", disclosure = FALSE)library(data.table) hhfile <- data.table( h_0 = c("A1", "A2", "B1", "B2"), h_1 = c("A", "A", "B", "B") ) DT <- data.table( nace = c("A1", "A2", "B1", "B2"), year = rep(2020L, 4), emp = c(10L, 20L, 15L, 25L) ) mdi_hier_apply(DT, hhfile, var_list = "emp", bygroups = c("nace", "year"), hier = "h_1", disclosure = FALSE)
Reads data from various file formats into an R data.table. This function is a wrapper around multiple file-reading packages
such as fread (from data.table), haven (for Stata, SAS, SPSS), and readxl (for Excel). It supports CSV, Stata (.dta), Excel (.xlsx),
SAS (.sas7bdat), SPSS (.sav), tab-delimited text files (.txt), and tables in an Oracle relational database via RODBC.
You can also specify a list of columns to import and specify which columns should be imported as characters.
However, note that for some file formats (e.g., Stata, SAS, SPSS, Oracle), the function cannot directly import columns as characters during the import process.
In such cases, the specified columns are converted to character types after the data has been loaded.
mdi_import_data( dir, file, format, col_list = NULL, char_columns = NULL, encoding = NULL, oracle_channel = NULL, db_user = NULL )mdi_import_data( dir, file, format, col_list = NULL, char_columns = NULL, encoding = NULL, oracle_channel = NULL, db_user = NULL )
dir |
For file-based formats: the directory path where the input file is located.
For |
file |
For file-based formats: the name of the file to be imported.
For |
format |
The type of the file to be imported. Supported types include:
|
col_list |
A character vector of column names to import. If |
char_columns |
A character vector of column names to treat as
character type. For |
encoding |
Character string passed to the underlying reader (e.g.
|
oracle_channel |
Optional pre-opened RODBC connection (from
|
db_user |
Oracle database user account. Required when
|
A data.table containing the imported data.
tmp_dir <- paste0(tempdir(), "/") write.csv(data.frame(id = 1:3, emp = c(10, 20, 30)), paste0(tmp_dir, "data.csv"), row.names = FALSE) mdi_import_data(tmp_dir, "data.csv", "csv", char_columns = "id")tmp_dir <- paste0(tempdir(), "/") write.csv(data.frame(id = 1:3, emp = c(10, 20, 30)), paste0(tmp_dir, "data.csv"), row.names = FALSE) mdi_import_data(tmp_dir, "data.csv", "csv", char_columns = "id")
Reduces a set of binary adoption indicators to a single continuous intensity score using probit regressions. For each boolean indicator a probit model is fitted with continuous firm-level predictors and optional fixed effects. The predicted propensities are then combined into a single intensity score via the geometric mean.
mdi_intensity(DT, uniqdim, boollist, contlist, fe)mdi_intensity(DT, uniqdim, boollist, contlist, fe)
DT |
A data.table containing the input data. |
uniqdim |
Character vector of column names that uniquely identify each
observation (e.g. |
boollist |
Character vector of column names for binary adoption indicators (0/1). A probit propensity is estimated for each. |
contlist |
Character vector of column names for continuous firm-level predictors used in each probit model. |
fe |
Character vector of column names to include as factor fixed
effects in each probit model (e.g. |
A data.table keyed on uniqdim with one additional column
intens_probit: the geometric mean of all predicted propensities.
library(data.table) set.seed(1) n <- 100 DT <- data.table( firmid = seq_len(n), year = sample(2010:2012, n, replace = TRUE), bool1 = sample(0L:1L, n, replace = TRUE), cont1 = rnorm(n), cont2 = rnorm(n) ) mdi_intensity(DT, uniqdim = "firmid", boollist = "bool1", contlist = c("cont1", "cont2"), fe = "year")library(data.table) set.seed(1) n <- 100 DT <- data.table( firmid = seq_len(n), year = sample(2010:2012, n, replace = TRUE), bool1 = sample(0L:1L, n, replace = TRUE), cont1 = rnorm(n), cont2 = rnorm(n) ) mdi_intensity(DT, uniqdim = "firmid", boollist = "bool1", contlist = c("cont1", "cont2"), fe = "year")
Computes joint distributions for specified variables within a data table. Calculates distributional moments (deciles, quintiles, or quartiles) for one or more variables, aggregated by specified groups and potentially hierarchical structures.
mdi_jointdist( DT, hhfile, qnames, var_names, moment = c("decile", "quintile", "quartile"), bygroups, hier, agg_type, prefix = agg_type, weight_col = NULL, mrg = FALSE, disclosure = TRUE, minNumObs = 5L, domVar = "var", domNr = 2L )mdi_jointdist( DT, hhfile, qnames, var_names, moment = c("decile", "quintile", "quartile"), bygroups, hier, agg_type, prefix = agg_type, weight_col = NULL, mrg = FALSE, disclosure = TRUE, minNumObs = 5L, domVar = "var", domNr = 2L )
DT |
A |
hhfile |
A |
qnames |
Character vector. Names of variables used for calculating distributional moments. |
var_names |
Character vector. Names of the variable(s) whose aggregates are computed. |
moment |
Character scalar. Distributional moment to compute. One of
|
bygroups |
Character vector. Variables used for stratification. |
hier |
Character scalar. Hierarchical level for aggregation. |
agg_type |
Character scalar. Type of aggregation (e.g. |
prefix |
Character scalar. Prefix for naming aggregated variables.
Default is the value of |
weight_col |
Optional character scalar. Name of a weight column in
|
mrg |
Logical. Whether to merge results back with the original data
table. Default |
disclosure |
Logical. Whether to apply disclosure control. Default
|
minNumObs |
Integer. Minimum number of observations for the quantile
smoothing window in |
domVar |
Character. Dominance variable passed to |
domNr |
Integer. Number of top firms for dominance check passed to
|
A data.table with computed joint distributions including the
distributional moments for specified variables aggregated by the given
criteria.
library(data.table) DT <- data.table( nace = rep(c("A", "B"), each = 5), year = rep(2020L, 10), emp = c(10, 20, 5, 15, 8, 12, 25, 6, 14, 9) ) hhfile <- data.table(h_0 = c("A", "B"), h_1 = c("X", "X")) mdi_jointdist(DT, hhfile, qnames = "emp", var_names = "emp", moment = "quartile", bygroups = c("nace", "year"), hier = "h_1", agg_type = "sum", disclosure = FALSE)library(data.table) DT <- data.table( nace = rep(c("A", "B"), each = 5), year = rep(2020L, 10), emp = c(10, 20, 5, 15, 8, 12, 25, 6, 14, 9) ) hhfile <- data.table(h_0 = c("A", "B"), h_1 = c("X", "X")) mdi_jointdist(DT, hhfile, qnames = "emp", var_names = "emp", moment = "quartile", bygroups = c("nace", "year"), hier = "h_1", agg_type = "sum", disclosure = FALSE)
Two-stage proxy-variable estimator using an intermediate input (typically materials) to control for unobserved productivity. First stage: regress y on a flexible polynomial in (state, proxy) plus the free input, recovering Phi. Second stage: GMM on the law-of-motion residual identifying the state elasticities. Reference: Levinsohn & Petrin (2003, ReStud).
tfp = (y or Phi) - X*beta, depending on TFP_minuend. Defaults to
"y" to match the convention shared by the other estimators.
mdi_lp_prodest( DT, y, endog, exog, instr, id, time, spec = "cd", degree = 3, lower_bound_theta = 0, upper_bound_theta = 1, TFP_demeaned = TRUE, TFP_minuend = c("y", "Phi"), Omega_estimates = TRUE, time_FE = FALSE )mdi_lp_prodest( DT, y, endog, exog, instr, id, time, spec = "cd", degree = 3, lower_bound_theta = 0, upper_bound_theta = 1, TFP_demeaned = TRUE, TFP_minuend = c("y", "Phi"), Omega_estimates = TRUE, time_FE = FALSE )
DT |
A |
y |
Character. Name of the output variable column. |
endog |
Character vector. Names of endogenous input columns (e.g. labour). |
exog |
Character vector. Names of exogenous input columns (e.g. capital). |
instr |
Character vector. Names of proxy/instrument columns (e.g. materials). |
id |
Character. Name of the firm/unit identifier column. |
time |
Character. Name of the time period column. |
spec |
Character. Functional form. Only |
degree |
Integer. Polynomial degree in proxy function and law of motion. Default |
lower_bound_theta |
Numeric. Lower bound for state elasticities. Default |
upper_bound_theta |
Numeric. Upper bound for state elasticities. Default |
TFP_demeaned |
Logical. If |
TFP_minuend |
Character. |
Omega_estimates |
Logical. If |
time_FE |
Logical. If |
A data.table with one row per observation in the GMM sample,
containing:
id, time columns (using the names supplied)
tfp: total factor productivity
el_<input>: estimated input elasticities
TFP_demeaned (if TFP_demeaned = TRUE): period-demeaned TFP
g_b_slopes, g_b_intercept (if Omega_estimates = TRUE)
NumObs: number of observations used in the GMM stage
convergence: optimiser convergence code (0 = converged)
library(data.table) set.seed(1) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) result <- mdi_lp_prodest(DT, y = "y", endog = "l", exog = "k", instr = "m", id = "id", time = "year", degree = 2, TFP_demeaned = FALSE)library(data.table) set.seed(1) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) result <- mdi_lp_prodest(DT, y = "y", endog = "l", exog = "k", instr = "m", id = "id", time = "year", degree = 2, TFP_demeaned = FALSE)
Creates a harmonized concordance for a classification of interest over a
time period, starting from year-by-year concordance tables. Each row in
conc_table maps a code in year t-1 (column left) to a code in year
t (second column), along with a year column indicating which transition
the row belongs to.
Codes linked by the concordance, directly or through other codes and years, form one group, so 1:1, m:1, 1:m and m:m changes are all handled alike. Every code in a group gets the same harmonized code.
mdi_make_conc(conc_table, year_list = NULL, code_name)mdi_make_conc(conc_table, year_list = NULL, code_name)
conc_table |
A |
year_list |
Integer or numeric vector of years of interest, starting
from the first year |
code_name |
Character. Name of the classification variable, used to
label output columns (e.g. |
A data.table in long format with columns:
year — the year of the observation.
<code_name> — the original code for that year.
<code_name>_harmonized — the group's code: its smallest code
in the latest year the group still has one, with "D" appended if
that year is before the last year.
library(data.table) conc <- data.table( year = c(2011L, 2011L, 2012L, 2012L), left = c("A", "B", "A", "C"), right = c("A", "B", "A2", "C") ) mdi_make_conc(conc, 2011:2012, "pcc8")library(data.table) conc <- data.table( year = c(2011L, 2011L, 2012L, 2012L), left = c("A", "B", "A", "C"), right = c("A", "B", "A2", "C") ) mdi_make_conc(conc, 2011:2012, "pcc8")
Fits a Cobb-Douglas production function by OLS on the free and state inputs together with a degree-G polynomial in the same inputs, following the prodest-package convention. Returns TFP as the residual between output and the fitted input index, with optional period demeaning.
Intended as a naive baseline for the simultaneity-bias comparison against
the proxy-variable estimators. NOTE: at degree > 1 the reported
linear-input coefficients are partial regression coefficients conditional
on the higher-order polynomial terms, not structural elasticities. Use
degree = 1 for the clean naive-OLS baseline.
tfp = y - X*beta (same convention as ACF/LP/WDRG/dpGMM).
mdi_ols_prodest( DT, y, endog, exog, id, time, spec = "cd", degree = 3, TFP_demeaned = TRUE )mdi_ols_prodest( DT, y, endog, exog, id, time, spec = "cd", degree = 3, TFP_demeaned = TRUE )
DT |
A |
y |
Character scalar. Name of the output variable column. |
endog |
Character vector. Names of the free (endogenous) input columns (e.g. log labour). |
exog |
Character vector. Names of the state input columns (e.g. log capital). |
id |
Character scalar. Name of the firm/unit identifier column. |
time |
Character scalar. Name of the time period column. |
spec |
Character. Functional form. Only |
degree |
Integer. Polynomial degree for the input polynomial. Use 1 for
the true naive baseline. Default |
TFP_demeaned |
Logical. If |
A data.table with one row per observation in the estimation
sample, containing:
id, time columns (using the names supplied)
tfp: total factor productivity (OLS residual)
el_<endog>, el_<exog>: estimated input elasticities
TFP_demeaned (if TFP_demeaned = TRUE): period-demeaned TFP
NumObs: number of observations used
library(data.table) set.seed(3) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5) ) result <- mdi_ols_prodest(DT, y = "y", endog = "l", exog = "k", id = "id", time = "year", degree = 2, TFP_demeaned = FALSE)library(data.table) set.seed(3) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5) ) result <- mdi_ols_prodest(DT, y = "y", endog = "l", exog = "k", id = "id", time = "year", degree = 2, TFP_demeaned = FALSE)
Executes a specified outlier handling routine (trimming, winsorizing, or flagging) on a dataset for selected continuous variables. This function can trim or winsorize the data at specified quantiles or flag observations as outliers based on the fraction provided. Trimming replaces outliers with NA, winsorizing replaces outliers with the closest value within the non-outlier range, and flagging marks outliers with a flag variable.
mdi_outlier( DT, var_list, routine = c("trim", "winsorize", "flag"), fraction, both_tails = FALSE, group = NULL )mdi_outlier( DT, var_list, routine = c("trim", "winsorize", "flag"), fraction, both_tails = FALSE, group = NULL )
DT |
A |
var_list |
A character vector of continuous variable names in |
routine |
A string specifying the outlier routine to apply: |
fraction |
The fraction of data to be trimmed or winsorized; must be a numeric value between 0 and 1. |
both_tails |
Logical indicating whether to apply the routine to both tails of the distribution. If |
group |
An optional character vector naming one or more grouping variables in |
A modified copy of DT with the outlier routine applied to the specified variables. If routine = "flag", new columns named flag_<var> are added (value 1 for flagged observations, NA otherwise).
library(data.table) DT <- data.table(id = 1:10, income = c(50, 55, 45, 60, 200, 40, 45, 55, 65, 1000)) mdi_outlier(DT, "income", "trim", 0.1, both_tails = TRUE) mdi_outlier(DT, "income", "winsorize", 0.1) mdi_outlier(DT, "income", "flag", 0.1)library(data.table) DT <- data.table(id = 1:10, income = c(50, 55, 45, 60, 200, 40, 45, 55, 65, 1000)) mdi_outlier(DT, "income", "trim", 0.1, both_tails = TRUE) mdi_outlier(DT, "income", "winsorize", 0.1) mdi_outlier(DT, "income", "flag", 0.1)
Estimates capital stock based on the Perpetual Inventory Method (PIM),
as outlined in Halle & Mairesse (1995). This function is tailored for data
structured as panel data, with indexing based on a firm identifier (firmid)
and a year variable. It involves the following steps:
Reading the specified variables from the input data.table.
Depending on whether the depreciation rate is provided directly or inferred from the asset type, the function calculates the capital stock.
The output is the input data.table augmented with the new capital stock variable.
The function supports different depreciation formats and asset types, offering flexibility in estimating capital stock across various contexts.
mdi_pim_capital( DT, id = "firmid", K0 = "K0", I = "ni_tan", delta = "d_GFCF", output_name = "k_new", time = "year" )mdi_pim_capital( DT, id = "firmid", K0 = "K0", I = "ni_tan", delta = "d_GFCF", output_name = "k_new", time = "year" )
DT |
A data.table including the necessary variables. |
id |
Column name of the firm (unit) identifier. Default is |
K0 |
Column name for the real initial capital stock value. Default is
|
I |
Column name for real investment. Default is |
delta |
Column name for the depreciation rate. Default is |
output_name |
Name of the output variable for the estimated capital stock.
Default is |
time |
Name of the time variable. Default is |
A modified DT with the new capital stock variable appended.
Halle, P., & Mairesse, J. (1995). "Estimation of the Perpetual Inventory Method for Capital Stock".
library(data.table) DT <- data.table( firmid = rep(c("F1", "F2"), each = 4), year = rep(2010:2013, 2), K0 = c(100, NA, NA, NA, 200, NA, NA, NA), ni_tan = c(10, 12, 11, 13, 20, 22, 21, 23), d_GFCF = rep(0.08, 8) ) mdi_pim_capital(DT)library(data.table) DT <- data.table( firmid = rep(c("F1", "F2"), each = 4), year = rep(2010:2013, 2), K0 = c(100, NA, NA, NA, 200, NA, NA, NA), ni_tan = c(10, 12, 11, 13, 20, 22, 21, 23), d_GFCF = rep(0.08, 8) ) mdi_pim_capital(DT)
Runs regression analysis on a data.table using models from the fixest package
(feols, feglm, etc.), with automatic disclosure control applied.
Disclosure rules ensure that regressions are only reported if they meet
minimum thresholds for sample size: both the number of observations and the
residual degrees of freedom must be at least minNumObs.
When count_firms = TRUE, the number of unique firms and enterprises in the
regression sample are also computed and added to the output (NumFirms,
NumEnt). This is controlled by the caller – typically set based on the
country-specific disclosure requirements of the NSI running the code.
The function supports clustered standard errors, regression weights, instrumental variables, and optional LaTeX export of results.
mdi_regress( DT, formula, model = "feols", family = NULL, vcov = "iid", cluster = FALSE, tex = FALSE, output_name = NULL, desc_file = NULL, weights = NULL, iv = FALSE, num_firms = NULL, num_ent = NULL, count_firms = FALSE, firm_col = "firmid", ent_col = "entid", minNumObs = 5L, dirOUTPUT = NULL )mdi_regress( DT, formula, model = "feols", family = NULL, vcov = "iid", cluster = FALSE, tex = FALSE, output_name = NULL, desc_file = NULL, weights = NULL, iv = FALSE, num_firms = NULL, num_ent = NULL, count_firms = FALSE, firm_col = "firmid", ent_col = "entid", minNumObs = 5L, dirOUTPUT = NULL )
DT |
A |
formula |
A character vector of regression formulas. |
model |
Character. The regression model to use (e.g. |
family |
Family specification for GLM models (only relevant if
|
vcov |
Variance-covariance specification for standard errors.
Can be |
cluster |
Logical. If |
tex |
Logical. If |
output_name |
Character. Name of the LaTeX output file (without extension),
if |
desc_file |
Character. Name of a description file to which an entry for
the regression output is appended (if |
weights |
Optional formula specifying the weights variable to apply
in the regression (e.g. |
iv |
Logical. If |
num_firms |
Optional integer. Number of unique firms to use when
|
num_ent |
Optional integer. Number of unique enterprises to use when
|
count_firms |
Logical. If |
firm_col |
Character. Name of the column in |
ent_col |
Character. Name of the column in |
minNumObs |
Integer. Minimum observations and degrees of freedom
required for a regression to pass disclosure. Default |
dirOUTPUT |
Character. Path to the output directory (must end with
|
Regression output is only returned if both nobs >= minNumObs and
residual degrees of freedom >= minNumObs.
When count_firms = TRUE: unique firm and enterprise counts are computed
from the regression sample using firm_col and ent_col. If a column is
absent from the data, the corresponding num_firms or num_ent argument
is used instead. If neither the column nor the manual count is provided,
the function stops with an error before any regression is run.
If tex = TRUE, results are saved to <dirOUTPUT>/<output_name>.tex and an
entry is appended to <dirOUTPUT>/<desc_file>.txt.
A data.table of regression results, including:
Coefficients and standard errors
Confidence intervals (ci.lower, ci.upper)
Sample size (NumObs), residual df (df)
NumFirms and NumEnt (only when count_firms = TRUE)
Fit statistics (R2, Adj. R2, AIC, BIC, LogLik, and IV/F tests if applicable)
If disclosure criteria are not satisfied, the regression is skipped and a message is printed.
library(data.table) set.seed(1) DT <- data.table( y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100), firmid = paste0("F", sample(1:20, 100, replace = TRUE)), entid = paste0("E", sample(1:15, 100, replace = TRUE)) ) # Basic regression mdi_regress(DT, formula = "y ~ x1 + x2", minNumObs = 5L) # With firm/enterprise counts (e.g. when NSI rules require it) mdi_regress(DT, formula = "y ~ x1 + x2", minNumObs = 5L, count_firms = TRUE) # Weighted regression with clustered SEs DT[, w := runif(.N)] mdi_regress(DT, formula = "y ~ x1 + x2", weights = ~w, cluster = TRUE, vcov = "~firmid") # With LaTeX export (writes .tex file to tempdir) mdi_regress(DT, formula = "y ~ x1", tex = TRUE, output_name = "reg1", desc_file = "log", dirOUTPUT = paste0(tempdir(), "/"))library(data.table) set.seed(1) DT <- data.table( y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100), firmid = paste0("F", sample(1:20, 100, replace = TRUE)), entid = paste0("E", sample(1:15, 100, replace = TRUE)) ) # Basic regression mdi_regress(DT, formula = "y ~ x1 + x2", minNumObs = 5L) # With firm/enterprise counts (e.g. when NSI rules require it) mdi_regress(DT, formula = "y ~ x1 + x2", minNumObs = 5L, count_firms = TRUE) # Weighted regression with clustered SEs DT[, w := runif(.N)] mdi_regress(DT, formula = "y ~ x1 + x2", weights = ~w, cluster = TRUE, vcov = "~firmid") # With LaTeX export (writes .tex file to tempdir) mdi_regress(DT, formula = "y ~ x1", tex = TRUE, output_name = "reg1", desc_file = "log", dirOUTPUT = paste0(tempdir(), "/"))
Identifies pairs of classification codes between which a unit switched in a given year, and counts how often each specific switch is observed across units. The output has one row per (old code, new code, year) triple.
mdi_transition(DT, id, time, classvar)mdi_transition(DT, id, time, classvar)
DT |
A data.table containing the panel data. Modified in place by
sorting on |
id |
Character. Name of the unit identifier column (e.g. |
time |
Character. Name of the time variable column (e.g. |
classvar |
Character. Name of the classification variable column
(e.g. |
A data.table with four columns: old_code, new_code,
year_shifted, and N (count of units making that switch in that year).
library(data.table) DT <- data.table( firmid = c("A", "A", "A", "B", "B", "B"), year = c(2010L, 2011L, 2012L, 2010L, 2011L, 2012L), nace = c("C10", "C10", "C20", "D30", "D40", "D40") ) mdi_transition(DT, id = "firmid", time = "year", classvar = "nace")library(data.table) DT <- data.table( firmid = c("A", "A", "A", "B", "B", "B"), year = c(2010L, 2011L, 2012L, 2010L, 2011L, 2012L), nace = c("C10", "C10", "C20", "D30", "D40", "D40") ) mdi_transition(DT, id = "firmid", time = "year", classvar = "nace")
Implements the stacked two-equation GMM from Wooldridge (2009, Economics
Letters 104, 112-114). The system is estimated linearly in the parameters:
the polynomial coefficients on (Wooldridge eq 3.3) and on
(eq 3.4) are free, separate vectors. This is more
general than the random-walk-with-drift restriction (eq 3.10) which forces
them equal, but it does NOT impose the structural rho_g * lambda^g form
that eq (3.4) implies for a general degree-G polynomial law of motion
(G > 1, which would require nonlinear GMM and is not implemented here).
The implementation matches the standard empirical Wooldridge GMM used in
Petrin, Poi and Levinsohn (2004).
Returns elasticities common to all firms in the group, firm-year
tfp = y - X*beta (the intercept alpha_hat is reported as a
separate column for diagnostics, not subtracted), and analytical SEs.
mdi_wdrg_prodest( DT, y, endog, exog, instr, id, time, degree = 2, tol = 1e-10, TFP_demeaned = TRUE, TFP_minuend = "y" )mdi_wdrg_prodest( DT, y, endog, exog, instr, id, time, degree = 2, tol = 1e-10, TFP_demeaned = TRUE, TFP_minuend = "y" )
DT |
A |
y |
Character. Output variable name (in logs). |
endog |
Character. Free input name (e.g. labour; one variable for now). |
exog |
Character. State input name (e.g. capital; one variable for now). |
instr |
Character. Proxy variable name (e.g. materials). |
id |
Character. Firm identifier column. |
time |
Character. Time identifier column. |
degree |
Integer. Polynomial degree for c(x, m). Default |
tol |
Numeric. Linear-solver tolerance for the GMM normal equations.
Default |
TFP_demeaned |
Logical. If |
TFP_minuend |
Character. Currently only |
A data.table with one row per observation in the GMM sample,
containing id, time, tfp, alpha_hat,
el_<input>, se_el_<input>, NumObs, and optionally
TFP_demeaned.
library(data.table) set.seed(1) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) result <- mdi_wdrg_prodest(DT, y = "y", endog = "l", exog = "k", instr = "m", id = "id", time = "year", TFP_demeaned = FALSE)library(data.table) set.seed(1) n <- 200 DT <- data.table( id = rep(1:50, each = 4), year = rep(2000:2003, times = 50), y = rnorm(n, 5, 1), l = rnorm(n, 3, 0.5), k = rnorm(n, 4, 0.5), m = rnorm(n, 2, 0.5) ) result <- mdi_wdrg_prodest(DT, y = "y", endog = "l", exog = "k", instr = "m", id = "id", time = "year", TFP_demeaned = FALSE)