% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/pcorr.R
\name{pcorr}
\alias{pcorr}
\alias{print.partial_corr}
\alias{summary.partial_corr}
\alias{print.summary.partial_corr}
\alias{plot.partial_corr}
\title{Partial correlation matrix (sample / ridge / OAS / graphical lasso)}
\usage{
pcorr(
  data,
  method = c("sample", "oas", "ridge", "glasso"),
  na_method = c("error", "complete"),
  ci = FALSE,
  conf_level = 0.95,
  return_cov_precision = FALSE,
  return_details = FALSE,
  return_p_value = FALSE,
  lambda = 0.001,
  output = c("matrix", "sparse", "edge_list"),
  threshold = 0,
  diag = TRUE
)

\method{print}{partial_corr}(
  x,
  digits = 3,
  show_method = TRUE,
  n = NULL,
  topn = NULL,
  max_vars = NULL,
  width = NULL,
  show_ci = NULL,
  ...
)

\method{summary}{partial_corr}(
  object,
  n = NULL,
  topn = NULL,
  max_vars = NULL,
  width = NULL,
  show_ci = NULL,
  ...
)

\method{print}{summary.partial_corr}(
  x,
  digits = 4,
  n = NULL,
  topn = NULL,
  max_vars = NULL,
  width = NULL,
  show_ci = NULL,
  ...
)

\method{plot}{partial_corr}(
  x,
  title = NULL,
  low_color = "indianred1",
  high_color = "steelblue1",
  mid_color = "white",
  value_text_size = 4,
  show_value = TRUE,
  mask_diag = TRUE,
  reorder = FALSE,
  ...
)
}
\arguments{
\item{data}{A numeric matrix or data frame with at least two numeric columns.
Non-numeric columns are ignored.}

\item{method}{Character; one of \code{"sample"}, \code{"oas"},
\code{"ridge"}, or \code{"glasso"}. Default \code{"sample"}.}

\item{na_method}{Character scalar controlling missing-data handling.
\code{"error"} rejects missing, \code{NaN}, and infinite values.
\code{"complete"} performs listwise deletion once across the retained
numeric columns and then computes the estimator on the common complete
sample. Pairwise deletion is not supported for partial correlations.}

\item{ci}{Logical (default \code{FALSE}). If \code{TRUE}, attach Fisher-z
confidence intervals for the off-diagonal partial correlations. This
option is available only for the classical \code{method = "sample"}
estimator in the ordinary low-dimensional setting.}

\item{conf_level}{Confidence level used when \code{ci = TRUE}. Default is
\code{0.95}.}

\item{return_cov_precision}{Logical; if \code{TRUE}, also return the
covariance (\code{cov}) and precision (\code{precision}) matrices used to
form the partial correlations. Requires \code{return_details = TRUE}.
Default to \code{FALSE}.}

\item{return_details}{Logical; if \code{TRUE}, return the rich
\code{"partial_corr"} list containing \code{pcor}, diagnostics, method
metadata, and any requested covariance, precision, p-value, or CI
components. If \code{FALSE} (default), \code{output = "matrix"} returns the
standard matrixCorr estimate matrix, consistent with other correlation
methods.}

\item{return_p_value}{Logical; if \code{TRUE}, compute two-sided p-values
for testing whether each sample partial correlation is zero. With the
default matrix result, p-values are stored in the inference metadata and
exposed by \code{tidy()}. With \code{return_details = TRUE}, they are also
returned as the \code{p_value} matrix. This option is available only for
\code{method = "sample"} and requires \eqn{n > p}. Default to
\code{FALSE}.}

\item{lambda}{Numeric \eqn{\ge 0}; regularisation strength. For
\code{method = "ridge"}, this is the penalty added to the covariance
diagonal. For \code{method = "glasso"}, this is the off-diagonal
precision-matrix \eqn{\ell_1} penalty. Ignored otherwise. Default
\code{1e-3}.}

\item{output}{Output representation for the computed estimates.
\itemize{
\item \code{"matrix"} (default): full dense matrix; best when you need
matrix algebra, dense heatmaps, or full compatibility with existing code.
\item \code{"sparse"}: sparse matrix from \pkg{Matrix} containing only
retained entries; best when many values are dropped by thresholding.
\item \code{"edge_list"}: long-form data frame with columns
\code{row}, \code{col}, \code{value}; convenient for filtering, joins,
and network-style workflows.
}}

\item{threshold}{Non-negative absolute-value filter for non-matrix outputs:
keep entries with \code{abs(value) >= threshold}. Use
\code{threshold > 0} when you want only stronger associations (typically
with \code{output = "sparse"} or \code{"edge_list"}). Keep
\code{threshold = 0} to retain all values. Must be \code{0} when
\code{output = "matrix"}.}

\item{diag}{Logical; whether to include diagonal entries in
\code{"sparse"} and \code{"edge_list"} outputs.}

\item{x}{An object of class \code{partial_corr}.}

\item{digits}{Integer; number of decimal places for display (default 3).}

\item{show_method}{Logical; print a one-line header with \code{method}
(and \code{lambda}/\code{rho} if available). Default \code{TRUE}.}

\item{n}{Optional row threshold for compact preview output.}

\item{topn}{Optional number of leading/trailing rows to show when truncated.}

\item{max_vars}{Optional maximum number of visible columns; \code{NULL} derives this
from console width.}

\item{width}{Optional display width; defaults to \code{getOption("width")}.}

\item{show_ci}{One of \code{"yes"} or \code{"no"}.}

\item{...}{Additional arguments passed to \code{ggplot2::theme()} or other
\pkg{ggplot2} layers.}

\item{object}{An object of class \code{partial_corr}.}

\item{title}{Plot title. By default, constructed from the estimator in
\code{x$method}.}

\item{low_color}{Colour for low (negative) values. Default
\code{"indianred1"}.}

\item{high_color}{Colour for high (positive) values. Default
\code{"steelblue1"}.}

\item{mid_color}{Colour for zero. Default \code{"white"}.}

\item{value_text_size}{Font size for cell labels. Default \code{4}.}

\item{show_value}{Logical; if \code{TRUE} (default), overlay numeric values
on the heatmap tiles.}

\item{mask_diag}{Logical; if \code{TRUE}, the diagonal is masked
(set to \code{NA}) and not labelled. Default \code{TRUE}.}

\item{reorder}{Logical; if \code{TRUE}, variables are reordered by
hierarchical clustering of \eqn{1 - |pcor|}. Default \code{FALSE}.}
}
\value{
With the default \code{return_details = FALSE}, a standard
matrixCorr correlation result: a dense \code{corr_matrix}, sparse matrix,
or \code{corr_edge_list}, depending on \code{output}. With
\code{return_details = TRUE}, an object of class \code{"partial_corr"} (a
list) with elements:
\itemize{
\item \code{pcor}: \eqn{p \times p} partial correlation matrix.
\item \code{cov} (if requested): covariance matrix used.
\item \code{precision} (if requested): precision matrix \eqn{\Theta}.
\item \code{p_value} (if requested): matrix of two-sided p-values for
the sample partial correlations.
\item \code{ci} (if requested): a list with elements \code{est},
\code{lwr.ci}, \code{upr.ci}, \code{conf.level}, and \code{ci.method}.
\item \code{diagnostics}: metadata used for inference, including the
effective complete-case sample size and number of conditioned variables.
\item \code{method}: the estimator used (\code{"oas"}, \code{"ridge"},
\code{"sample"}, or \code{"glasso"}).
\item \code{lambda}: ridge or graphical-lasso penalty
(or \code{NA_real_}).
\item \code{rho}: OAS shrinkage weight in \eqn{[0,1]} (or \code{NA_real_}).
\item \code{jitter}: diagonal jitter added (if any) to ensure positive
definiteness.
}

Invisibly returns \code{x}.

A compact summary object of class \code{summary.partial_corr}.

A \code{ggplot} object.
}
\description{
Computes Gaussian partial correlations for the numeric columns of a matrix
or data frame using a high-performance 'C++' backend. Covariance estimation
is available via the classical sample estimator, ridge regularisation, OAS
shrinkage, or graphical lasso. Optional p-values and Fisher-z confidence
intervals are available for the classical sample estimator in the ordinary
low-dimensional setting.
}
\details{
\strong{Statistical overview.} Given an \eqn{n \times p} data matrix \eqn{X}
(rows are observations, columns are variables), the routine estimates a
\emph{partial correlation} matrix via the precision (inverse covariance)
matrix. Let \eqn{\mu} be the vector of column means and
\deqn{S = (X - \mathbf{1}\mu)^\top (X - \mathbf{1}\mu)}
be the centred cross-product matrix computed without forming a centred copy
of \eqn{X}. Two conventional covariance scalings are formed:
\deqn{\hat\Sigma_{\mathrm{MLE}} = S/n, \qquad
      \hat\Sigma_{\mathrm{unb}} = S/(n-1).}

\itemize{
\item \emph{Sample:} \eqn{\Sigma = \hat\Sigma_{\mathrm{unb}}}.
\item \emph{Ridge:} \eqn{\Sigma = \hat\Sigma_{\mathrm{unb}} + \lambda I_p}
with user-supplied \eqn{\lambda \ge 0} (diagonal inflation).
\item \emph{OAS (Oracle Approximating Shrinkage):}
shrink \eqn{\hat\Sigma_{\mathrm{MLE}}} towards a scaled identity
target \eqn{\mu_I I_p}, where \eqn{\mu_I = \mathrm{tr}(\hat\Sigma_{\mathrm{MLE}})/p}.
The data-driven weight \eqn{\rho \in [0,1]} is
\deqn{\rho = \min\!\left\{1,\max\!\left(0,\;
        \frac{(1-\tfrac{2}{p})\,\mathrm{tr}(\hat\Sigma_{\mathrm{MLE}}^2)
              + \mathrm{tr}(\hat\Sigma_{\mathrm{MLE}})^2}
             {(n + 1 - \tfrac{2}{p})
              \left[\mathrm{tr}(\hat\Sigma_{\mathrm{MLE}}^2)
              - \tfrac{\mathrm{tr}(\hat\Sigma_{\mathrm{MLE}})^2}{p}\right]}
        \right)\right\},}
and
\deqn{\Sigma = (1-\rho)\,\hat\Sigma_{\mathrm{MLE}} + \rho\,\mu_I I_p.}
\item \emph{Graphical lasso:} estimate a sparse precision matrix
\eqn{\Theta} by maximising
\deqn{\log\det(\Theta) - \mathrm{tr}(\hat\Sigma_{\mathrm{MLE}}\Theta)
        - \lambda\sum_{i \ne j} |\theta_{ij}|,}
with \eqn{\lambda \ge 0}. The returned covariance matrix is
\eqn{\Sigma = \Theta^{-1}}.
}

The method then ensures positive definiteness of \eqn{\Sigma} (adding a very
small diagonal \emph{jitter} only if necessary) and computes the precision
matrix \eqn{\Theta = \Sigma^{-1}}. Partial correlations are obtained by
standardising the off-diagonals of \eqn{\Theta}:
\deqn{\mathrm{pcor}_{ij} \;=\;
      -\,\frac{\theta_{ij}}{\sqrt{\theta_{ii}\,\theta_{jj}}}, \qquad
      \mathrm{pcor}_{ii}=1.}

If \code{return_p_value = TRUE}, the function also reports the classical
two-sided test p-values for the sample partial correlations, using
\deqn{t_{ij} = \mathrm{pcor}_{ij}
  \sqrt{\frac{n - p}{1 - \mathrm{pcor}_{ij}^2}}}
with \eqn{n - p} degrees of freedom. These p-values are returned only for
\code{method = "sample"}, where they match the standard full-model partial
correlation test.

When \code{ci = TRUE}, the function reports Fisher-\eqn{z} confidence
intervals for the sample partial correlations. For a partial correlation
\eqn{r_{xy \cdot Z}} conditioning on \eqn{c} variables, the transformed
statistic is \eqn{z = \operatorname{atanh}(r_{xy \cdot Z})} with standard
error
\deqn{\operatorname{SE}(z) = \frac{1}{\sqrt{n - 3 - c}},}
where \eqn{n} is the effective complete-case sample size used for the
estimate. The two-sided normal-theory interval is formed on the transformed
scale using \code{conf_level} and then mapped back with \code{tanh()}. In
the full matrix path implemented here, each off-diagonal entry conditions on
all remaining variables, so \eqn{c = p - 2} and the classical CI requires
\eqn{n > p + 1}. This inference is only supported for
\code{method = "sample"} without positive-definiteness repair; in
unsupported or numerically singular settings, CI bounds are returned as
\code{NA} with an informative \pkg{cli} warning or the request is rejected.

\strong{Interpretation.} For Gaussian data, \eqn{\mathrm{pcor}_{ij}} equals
the correlation between residuals from regressing variable \eqn{i} and
variable \eqn{j} on all the remaining variables; equivalently, it encodes
conditional dependence in a Gaussian graphical model, where
\eqn{\mathrm{pcor}_{ij}=0} if variables \eqn{i} and \eqn{j} are
conditionally independent given the others. Partial correlations are
invariant to separate rescalings of each
variable; in particular, multiplying \eqn{\Sigma} by any positive scalar
leaves the partial correlations unchanged.

\strong{Why shrinkage/regularisation?} When \eqn{p \ge n}, the sample
covariance is singular and inversion is ill-posed. Ridge and OAS both yield
well-conditioned \eqn{\Sigma}. Ridge adds a fixed \eqn{\lambda} on the
diagonal, whereas OAS shrinks adaptively towards \eqn{\mu_I I_p} with a
weight chosen to minimise (approximately) the Frobenius risk under a
Gaussian model, often improving mean-square accuracy in high dimension.

\strong{Why glasso?} Glasso is useful when the goal is not just to
stabilise a covariance estimate, but to recover a manageable network of
direct relationships rather than a dense matrix of overall associations. In
Gaussian models, zeros in the precision matrix correspond to conditional
independences, so glasso can suppress indirect associations that are
explained by the other variables and return a smaller, more interpretable
conditional-dependence graph. This is especially practical in
high-dimensional settings, where the sample covariance may be unstable or
singular. Glasso yields a positive-definite precision estimate and supports
edge selection, graph recovery, and downstream network analysis.

\strong{Computational notes.} The implementation forms \eqn{S} using 'BLAS'
\code{syrk} when available and constructs partial correlations by traversing
only the upper triangle with 'OpenMP' parallelism. Positive definiteness is
verified via a Cholesky factorisation; if it fails, a tiny diagonal jitter is
increased geometrically up to a small cap, at which point the routine
signals an error.
}
\examples{
## Structured MVN with known partial correlations
set.seed(42)
p <- 12; n <- 1000

## Build a tri-diagonal precision (Omega) so the true partial correlations
## are sparse
phi <- 0.35
Omega <- diag(p)
for (j in 1:(p - 1)) {
  Omega[j, j + 1] <- Omega[j + 1, j] <- -phi
}
## Strict diagonal dominance
diag(Omega) <- 1 + 2 * abs(phi) + 0.05
Sigma <- solve(Omega)

## Upper Cholesky
L <- chol(Sigma)
Z <- matrix(rnorm(n * p), n, p)
X <- Z \%*\% L
colnames(X) <- sprintf("V\%02d", seq_len(p))

pc <- pcorr(X)
summary(pc)
estimate(pc)
tidy(pc)

## Fisher-z confidence intervals for sample partial correlations
pc_ci <- pcorr(X[, 1:5], ci = TRUE)
ci(pc_ci)
confint(pc_ci)

# Interactive viewing (requires shiny)
if (interactive() && requireNamespace("shiny", quietly = TRUE)) {
  view_corr_shiny(pc)
}

## True partial correlation from Omega
pcor_true <- -Omega / sqrt(diag(Omega) \%o\% diag(Omega))
diag(pcor_true) <- 1

## Quick visual check (first 5x5 block)
round(estimate(pc)[1:5, 1:5], 2)
round(pcor_true[1:5, 1:5], 2)

## Plot method
plot(pc)

## Graphical-lasso example
set.seed(100)
p <- 20; n <- 250
Theta_g <- diag(p)
Theta_g[cbind(1:5, 2:6)] <- -0.25
Theta_g[cbind(2:6, 1:5)] <- -0.25
Theta_g[cbind(8:11, 9:12)] <- -0.20
Theta_g[cbind(9:12, 8:11)] <- -0.20
diag(Theta_g) <- rowSums(abs(Theta_g)) + 0.2

Sigma_g <- solve(Theta_g)
X_g <- matrix(rnorm(n * p), n, p) \%*\% chol(Sigma_g)
colnames(X_g) <- paste0("Node", seq_len(p))

gfit_1 <- pcorr(X_g, method = "glasso", lambda = 0.02,
                return_cov_precision = TRUE, return_details = TRUE)
gfit_2 <- pcorr(X_g, method = "glasso", lambda = 0.08,
                return_cov_precision = TRUE, return_details = TRUE)

## Larger lambda gives a sparser conditional-dependence graph
edge_count <- function(M, tol = 1e-8) {
  sum(abs(M[upper.tri(M, diag = FALSE)]) > tol)
}

c(edges_lambda_002 = edge_count(gfit_1$precision),
  edges_lambda_008 = edge_count(gfit_2$precision))

## Inspect strongest estimated conditional associations
pcor_g <- gfit_1$pcor
idx <- which(upper.tri(pcor_g), arr.ind = TRUE)
ord <- order(abs(pcor_g[idx]), decreasing = TRUE)
head(data.frame(
  i = rownames(pcor_g)[idx[ord, 1]],
  j = colnames(pcor_g)[idx[ord, 2]],
  pcor = round(pcor_g[idx][ord], 2)
))

## High-dimensional case p >> n
set.seed(7)
n <- 60; p <- 120

ar_block <- function(m, rho = 0.6) rho^abs(outer(seq_len(m), seq_len(m), "-"))

## Two AR(1) blocks on the diagonal
if (requireNamespace("Matrix", quietly = TRUE)) {
  Sigma_hd <- as.matrix(Matrix::bdiag(ar_block(60, 0.6), ar_block(60, 0.6)))
} else {
  Sigma_hd <- rbind(
    cbind(ar_block(60, 0.6), matrix(0, 60, 60)),
    cbind(matrix(0, 60, 60), ar_block(60, 0.6))
  )
}

L <- chol(Sigma_hd)
X_hd <- matrix(rnorm(n * p), n, p) \%*\% L
colnames(X_hd) <- paste0("G", seq_len(p))

pc_oas   <-
 pcorr(X_hd, method = "oas",   return_cov_precision = TRUE,
       return_details = TRUE)
pc_ridge <-
 pcorr(X_hd, method = "ridge", lambda = 1e-2,
                     return_cov_precision = TRUE, return_details = TRUE)
pc_samp  <-
 pcorr(X_hd, method = "sample", return_cov_precision = TRUE,
       return_details = TRUE)
pc_glasso <-
 pcorr(X_hd, method = "glasso", lambda = 5e-3,
                     return_cov_precision = TRUE, return_details = TRUE)

## Show how much diagonal regularisation was used
c(oas_jitter = pc_oas$jitter,
  ridge_lambda = pc_ridge$lambda,
  sample_jitter = pc_samp$jitter,
  glasso_lambda = pc_glasso$lambda)

## Compare conditioning of the estimated covariance matrices
c(kappa_oas = kappa(pc_oas$cov),
  kappa_ridge = kappa(pc_ridge$cov),
  kappa_sample = kappa(pc_samp$cov))

## Simple conditional-dependence graph from partial correlations
pcor <- pc_oas$pcor
vals <- abs(pcor[upper.tri(pcor, diag = FALSE)])
thresh <- quantile(vals, 0.98)  # top 2\%
edges  <- which(abs(pcor) > thresh & upper.tri(pcor), arr.ind = TRUE)
head(data.frame(i = colnames(pcor)[edges[,1]],
                j = colnames(pcor)[edges[,2]],
                pcor = round(pcor[edges], 2)))

}
\references{
Chen, Y., Wiesel, A., & Hero, A. O. III (2011).
Robust Shrinkage Estimation of High-dimensional Covariance Matrices.
IEEE Transactions on Signal Processing.

Friedman, J., Hastie, T., & Tibshirani, R. (2007).
Sparse inverse covariance estimation with the graphical lasso.
Biostatistics.

Ledoit, O., & Wolf, M. (2004).
A well-conditioned estimator for large-dimensional covariance matrices.
Journal of Multivariate Analysis, 88(2), 365-411.

Schafer, J., & Strimmer, K. (2005).
A shrinkage approach to large-scale covariance matrix estimation and
implications for functional genomics.
Statistical Applications in Genetics and Molecular Biology, 4(1), Article 32.
}
