Copula correction exploiting between-regressor correlation, following
Haschka (2025). Every explanatory variable – endogenous and exogenous –
is first transformed to a normal score; each endogenous normal score is
then regressed, without an intercept, on the exogenous normal scores, and
the residual of that regression is added to the structural regression as
the copula control function. This is the same two-stage procedure as
2sCOPE (CopReg2sCOPE(), Yang, Qian & Xie 2025) with one difference:
the first-stage (auxiliary) regression here carries no intercept, which
is what makes the slope of P* on X* equal to the Pearson correlation
used in Haschka's derivation of rho. Without an exogenous part in
formula the first stage has nothing to project on, so the call is
redirected to CopRegPG() with a warning.
Usage
CopRegIMA(
formula,
data,
cdf = "rank.n",
ties = "max",
nboots = 199,
subset = NULL,
contrasts = NULL,
parallel = FALSE,
ncores = NULL,
verbose = interactive()
)Arguments
- formula
A two-part formula of the form
y ~ endog_1 + endog_2 + ... | exog_1 + exog_2 + .... Position decides: terms written before the|are endogenous and receive a copula correction, terms written after it are exogenous and receive none. Everythinglm()accepts is allowed: transformations, e.g.log(price); interactions, e.g.price:feat; polynomials, e.g.I(x^2); factors, e.g.as.factor(store); and-1to drop the intercept. Endogenous regressors must be numeric. Missing values are handled byna.omit. Writing an interaction or a power of an endogenous regressor before the|gives it its own copula term and produces a warning, because such a term is strongly collinear with the regressor it is built from. Without an exogenous part (no|) the call is redirected toCopRegPG().- data
A
data.framecontaining the variables referenced informula.- cdf
Character string naming the estimator of the marginal CDF used in the normal-score transformation. Haschka (2025) leaves this choice open, so the default follows 2sCOPE:
"rank.n", the rescaled ECDF of Qian, Koschmann & Xie (2025, Eq. 9). Other options are"kde.silverman"(Park & Gupta 2012),"kde.cv"(Li, Li & Racine 2017),"kde.plugin"(Polansky & Baker 2000),"ecdf.fixed"(Becker, Proksch & Ringle 2022),"ecdf.adj"(Liengaard et al. 2025), and"rank.n1"(Breitung, Mayer & Wied 2024).- ties
Character string,
"max"(default) for the counting function or"average"for midranks. Relevant here because the exogenous regressors are transformed to normal scores as well.- nboots
Number of bootstrap replicates used to compute the standard errors. Defaults to
199.- subset
An optional logical vector selecting the rows to use, as in
lm(). Defaults toNULL(use every row).- contrasts
An optional list of contrasts for factor variables, passed on to
model.matrix(). Defaults toNULL.- parallel
FALSE(default),TRUE,"multicore", or"snow"to spread the bootstrap replicates across worker processes.- ncores
Number of worker processes to use when
parallelis notFALSE.NULL(default) uses one less than the number of detected cores.- verbose
Logical; show a progress message and progress bar while the bootstrap runs. Defaults to
interactive().
Value
An object of class "copreg": a list including coefficients
and std.error (point estimates and bootstrap standard errors for the
structural and copula coefficients), vcov (the bootstrap covariance
matrix of coefficients), rho and rho.se (the endogeneity measure
corr(structural residual, copula data) for each endogenous regressor
and its bootstrap standard error), residuals and fitted.values
(structural model, copula terms excluded), residuals.augmented and
fitted.augmented (including the copula terms), boot (raw bootstrap
coefficient draws), ols.coefficients and ols.std.error (the
uncorrected OLS benchmark from the same bootstrap resamples), icon
(the resulting standard error inflation), diagnostics
(identification diagnostics), and call, method, cdf, ties.
Methods exist for print(), summary(), coef(), vcov(),
nobs(), residuals(), fitted(), predict(), confint(),
formula(), and update().
References
Haschka, R. E. (2025). Robustness of copula-correction models in causal analysis: Exploiting between-regressor correlation. IMA Journal of Management Mathematics 36(1), 161-180.
Qian, Y., A. Koschmann, and H. Xie (2025). A practical guide to endogeneity correction using copulas. Journal of Marketing.
Yang, F., Y. Qian, and H. Xie (2025). Addressing endogeneity using a two-stage copula generated regressor approach. Journal of Marketing Research 62(4), 601-623.
Examples
set.seed(1)
n <- 200
w <- rnorm(n)
x <- rnorm(n)
e <- rexp(n, rate = 1) - 1 # nonnormal endogeneity driver
z <- 0.5 * w + 0.5 * x + e # endogenous regressor
y <- 1 + 2 * z + 0.5 * x + 0.5 * e + rnorm(n, sd = 0.5)
dat <- data.frame(y = y, z = z, x = x, w = w)
fit <- CopRegIMA(y ~ z | x + w, data = dat, nboots = 25)
summary(fit)
#>
#> Copula endogeneity correction: IMA (Haschka 2025)
#>
#> Call:
#> CopRegIMA(formula = y ~ z | x + w, data = dat, nboots = 25)
#>
#> Residuals of the augmented regression (u = xi - C gamma):
#> Min 1Q Median 3Q Max
#> -1.41619 -0.43098 -0.05137 0.39325 1.37631
#>
#> Residuals of the structural model (xi = y - mu - P alpha - W beta):
#> Min 1Q Median 3Q Max
#> -1.40272 -0.42622 -0.04259 0.40404 1.31991
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) 0.95156 0.04273 22.268 < 2e-16 ***
#> z 2.51239 0.13621 18.445 < 2e-16 ***
#> x 0.23027 0.07868 2.927 0.00343 **
#> w -0.25856 0.08348 -3.097 0.00195 **
#> z_cop -0.02389 0.19240 -0.124 0.90118
#> ---
#> Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#>
#> Endogeneity: rho(P*, xi*) is the correlation between the normal score
#> of an endogenous regressor and that of the structural error, xi* = xi / sigma.
#> Estimate Std. Error z value Pr(>|z|)
#> rho(z*, xi*) -0.02696 0.20267 -0.133 0.894
#>
#> Fit, on 195 residual degrees of freedom:
#> augmented structural
#> Residual standard error 0.5520 0.5524
#> R-squared 0.9734 0.9734
#> Adjusted R-squared 0.9729 0.9728
#> sigma above is the standard error of the structural model, the one
#> entering xi* = xi / sigma.
#> Standard errors from 25 bootstrap replicates; cdf = "rank.n", ties = "max".
#> Pr(>|z|) in both tables: Wald test using the normal approximation,
#> z = Estimate / Std. Error, with the bootstrap standard error.
#> See confint(object, type = "percentile") for bootstrap percentile intervals.
#>
#> --- Identification diagnostics ------------------------------------
#>
#> Non-normality of the endogenous regressors (small p = non-normal, good):
#> AD AD p KS p
#> z 5.079 1.35e-12 0.01434
#>
#> Correlation of the copula terms with the exogenous regressors
#> (this estimator does not assume it is zero; it projects the correlation
#> out in the first stage):
#> max |corr| with p (Holm) joint R2 joint p
#> z 0.4278 w 2.774e-10 0.3369 2.674e-18
#> full matrix in summary(object)$diagnostics$exog.correlation.matrix
#>
#> Collinearity of the copula terms (omega near 0 = weakly identified):
#> corr(P, C) omega
#> z_cop 0.8238 0.1111
#>
