Skip to contents

Instrument-free correction for an endogenous regressor that replaces the first-stage regression used by every other estimator in this package with a nonparametric estimate of the conditional distribution of the endogenous regressor \(P\) given the exogenous regressors \(W\), \(C = \Phi^{-1}(\hat F(P \mid W))\), using the kernel conditional CDF estimator of Li and Racine (2008) as implemented in np::npcdist().

Unlike every other estimator here, 2sCOPE-np has no cdf and no ties argument: there is no marginal CDF to choose, and supplying either through ... is an error rather than being silently ignored. It is also the only estimator in the package that tolerates discrete endogenous regressors (counts, binary treatments), because the conditional CDF smooths the regressor itself rather than requiring a continuous marginal transform. Finally, it is slow: bandwidths are chosen by cross-validation, an O(n^2) computation, and by default that selection is repeated from scratch in every bootstrap replicate.

Usage

CopReg2sCOPEnp(
  formula,
  data,
  condition = NULL,
  groups = NULL,
  heterogeneous = NULL,
  demean = NULL,
  bwmethod = c("cv.ls", "normal-reference"),
  bw.refit = TRUE,
  nboots = 199,
  subset = NULL,
  contrasts = NULL,
  parallel = FALSE,
  ncores = NULL,
  verbose = interactive(),
  ...
)

Arguments

formula

A two-part formula, y ~ endogenous | exogenous, as used throughout this package (see CopRegPG()). Endogenous regressors must be numeric but, uniquely for this estimator, may be discrete. Without an exogenous part the call is redirected to CopRegPG().

data

A data.frame containing all variables named in formula.

condition

Character vector naming which exogenous variables the conditional CDF conditions on. NULL (the default) uses all exogenous variables except polynomial and interaction terms, which the kernel estimator already accommodates without being told about them explicitly.

groups

Character vector. Instead of smoothing these variables with their own kernel, estimate the conditional CDF separately within each of their joint categories, still producing one copula coefficient per endogenous regressor. NULL (the default) smooths them like any other conditioning variable.

heterogeneous

Character vector naming variables whose joint categories may carry a different copula structure, i.e. different endogeneity (Proposition 1 of Hu, Qian & Xie 2025). The conditional CDF is then estimated separately within each category and the copula terms are parameterised against the first category as the reference group, so that the remaining coefficients test whether the endogeneity differs across groups. NULL (the default) imposes one common structure.

demean

Character vector naming variables to treat as fixed effects: their categories are removed by within-group demeaning of the endogenous regressor(s) and of the continuous conditioning variables before Stage 1, instead of being smoothed or split into cells. NULL (the default) performs no demeaning.

bwmethod

Bandwidth selection method passed to np::npcdistbw(): "cv.ls" (the default), the least-squares cross-validation of Li, Lin & Racine (2013) used by the paper, or "normal-reference", a cheaper, non-cross-validated alternative.

bw.refit

Logical. TRUE (the default) re-selects the bandwidths, cross-validation included, in every bootstrap replicate, which is the paper's own procedure and is what makes the bootstrap standard errors account for first-stage variability – and is why this estimator is slow. FALSE reuses the full-sample bandwidths throughout the bootstrap and re-estimates only the conditional CDF, which is faster but a deviation from the paper.

nboots

Number of bootstrap replicates used for the standard errors.

subset

Optional logical vector selecting a subset of observations, as in lm().

contrasts

Optional list of contrasts, passed to model.matrix().

parallel

FALSE, TRUE, "multicore" or "snow": whether and how to parallelize the bootstrap.

ncores

Number of worker processes when parallel is not FALSE; NULL uses one fewer than the number of cores detected.

verbose

Logical. Report progress and, before the bootstrap begins, the estimated total run time (Stage 1 is timed once and the elapsed time multiplied by nboots).

...

Further arguments passed on to np::npcdistbw(), e.g. ckertype, ukertype, okertype, nmulti. Passing cdf or ties here raises an error: this estimator has neither argument.

Value

An object of class "copreg", a list including:

coefficients, std.error, vcov

augmented-regression coefficient estimates and their bootstrap standard errors/covariance

rho, rho.se

the sample correlation of the structural residual with each copula term, and its bootstrap standard error

fitted.values, residuals

from the structural model, with the copula terms excluded

copula.terms, copula.data

the generated copula regressors and the underlying \(\Phi^{-1}(\hat F(P \mid W))\) values

copula.groups

when heterogeneous is used, a data frame identifying which copula column belongs to which cell

bandwidths

the cross-validated Stage 1 bandwidths from the full sample, one row per conditioning variable (and per cell/ regressor when groups or several endogenous regressors are used)

boot, ols.coefficients, ols.std.error, icon

the bootstrap draws, the uncorrected OLS benchmark from the same resamples, and the resulting standard-error inflation

diagnostics

the identification checks reported by validity()

See CopRegPG() for the methods common to every estimator in this package (coef(), vcov(), summary(), predict(), ...).

Details

Without exogenous regressors the conditional CDF collapses to the marginal one and the estimator reduces to Park & Gupta; the call is then redirected to CopRegPG() with a warning. Otherwise the exogenous side can be handled three ways, combinable: smoothed by the kernel itself (the default), cut into cells with groups/heterogeneous, or swept out by within-group demeaning with demean. heterogeneous additionally lets the copula structure differ across the named cells (Proposition 1 of Hu, Qian & Xie 2025), parameterised against the first cell as the reference group.

References

Hu, X., Y. Qian, and H. Xie (2025). Correcting endogeneity via nonparametric copula control functions. National Bureau of Economic Research Working Paper 33607. doi:10.3386/w33607

Li, Q. and J. S. Racine (2008). Nonparametric estimation of conditional CDF and quantile functions with mixed categorical and continuous data. Journal of Business & Economic Statistics 26(4), 423-434.

Li, Q., J. Lin, and J. S. Racine (2013). Optimal bandwidth selection for nonparametric conditional distribution and quantile functions. Journal of Business & Economic Statistics 31(1), 57-65.

Hayfield, T. and J. S. Racine (2008). Nonparametric econometrics: The np package. Journal of Statistical Software 27(5), 1-32.

Examples

# \donttest{
data(sim_endog)
set.seed(1)
small <- sim_endog[sample(nrow(sim_endog), 80), ]

if (requireNamespace("np", quietly = TRUE)) {
  fit <- CopReg2sCOPEnp(y ~ z_endog | x_exog, data = small, nboots = 25)
  summary(fit)
}
#> 
#> Copula endogeneity correction: 2sCOPE-np (Hu, Qian & Xie 2025) 
#> 
#> Call:
#> CopReg2sCOPEnp(formula = y ~ z_endog | x_exog, data = small, 
#>     nboots = 25)
#> 
#> Residuals of the augmented regression (u = xi - C gamma):
#>      Min       1Q   Median       3Q      Max 
#> -2.49556 -0.77935  0.04487  0.78475  2.40727 
#> 
#> Residuals of the structural model (xi = y - mu - P alpha - W beta):
#>     Min      1Q  Median      3Q     Max 
#> -8.6144 -2.1109 -0.1758  2.1805  9.1436 
#> 
#> Coefficients:
#>             Estimate Std. Error z value Pr(>|z|)    
#> (Intercept)   1.5167     0.1988   7.629 2.37e-14 ***
#> z_endog      -1.1328     0.5271  -2.149   0.0316 *  
#> x_exog        1.5427     0.1543   9.995  < 2e-16 ***
#> z_endog_cop   3.4832     0.6632   5.252 1.50e-07 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#> 
#> Endogeneity is read off the copula terms above. The control function is
#>   E(o | p, w) = sigma_o * rho * C_p, so only the product sigma_o * rho
#>   enters the regression and rho is not separately identified; a copula
#>   coefficient of zero means no endogeneity.
#> 
#> Fit, on 76 residual degrees of freedom:
#>                         augmented structural
#> Residual standard error  1.1241    3.5374   
#> R-squared                0.8558   -0.4280   
#> Adjusted R-squared       0.8501   -0.4844   
#> Standard errors from 25 bootstrap replicates.
#> Bandwidths of the conditional CDF estimation:
#>   regressor cell variable bandwidth
#> 1   z_endog       z_endog    0.3515
#> 2   z_endog        x_exog  247.7126
#> Pr(>|z|): 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 ------------------------------------
#> 
#> Correlation of the copula terms with the exogenous regressors
#> (the conditional CDF conditions on them, so a well estimated one leaves
#>  these correlations near zero; large values point at a poorly estimated
#>  conditional CDF rather than at a violated assumption):
#>         max |corr|   with p (Holm)  joint R2 joint p
#> z_endog    0.03015 x_exog   0.7913 0.0009088  0.7907
#>  full matrix in summary(object)$diagnostics$exog.correlation.matrix
#> 
#> Collinearity of the copula terms (omega near 0 = weakly identified):
#>             corr(P, C)    omega
#> z_endog_cop     0.9986 0.002878
#> 
# }