% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/crp_cluster.R
\name{crp_cluster}
\alias{crp_cluster}
\title{Cluster electrodes by their canonical \verb{CRP} response shape}
\usage{
crp_cluster(
  crp_list,
  paired = TRUE,
  time_window = c(0, NA),
  n_clusters = NULL,
  initial_rank = NULL,
  zeta_threshold = 1,
  null_class = TRUE,
  nmf_max_iters = 10000,
  nmf_tol = c(1e-04, 1e-08),
  verbose = TRUE
)
}
\arguments{
\item{crp_list}{a named list of \code{ravetools_crp} objects (one per
electrode) from \code{\link{crp}}; list names are used as electrode labels.
Time axes need not match - the common overlapping domain is used (an error is
raised if the domains do not overlap). See \sQuote{Details}.}

\item{paired}{logical; \code{TRUE} (the default) builds the trial-level
\verb{BPC} t-statistic similarity and requires the single trials in
\code{.data$V}; \code{FALSE} uses the cosine similarity of the \code{C_full}
curves. See \sQuote{Details}.}

\item{time_window}{numeric \code{c(lo, hi)} analysis window, clipped into the
common domain; an \code{NA} extends to that domain edge. Defaults to
\code{c(0, NA)} (stimulus onset to the end of the domain).}

\item{n_clusters}{integer or \code{NULL}; if given, fixes the number of
clusters and skips the automatic selection (which otherwise uses
\code{zeta_threshold}).}

\item{initial_rank}{integer or \code{NULL}; the starting \verb{NMF} rank for
automatic selection. \code{NULL} uses \code{min(length(crp_list) - 1L, 10L)}.}

\item{zeta_threshold}{numeric \eqn{> 0}; rank-selection cutoff on \eqn{\zeta}
(see \sQuote{Details}); smaller values give fewer clusters. Defaults to
\code{1}, matching the \verb{BPC} reference.}

\item{null_class}{logical; if \code{TRUE} (the default) electrodes whose
winner-take-all loading falls below \eqn{1/(2\sqrt{N})} are left unassigned
(\code{NA}); if \code{FALSE} every electrode is forced into a cluster. See
\sQuote{Details}.}

\item{nmf_max_iters, nmf_tol}{passed to \code{\link{naive_nmf}}.}

\item{verbose}{logical; whether to report progress.}
}
\value{
A named list of class \code{ravetools_crp_cluster}:
\describe{
\item{\code{clusters}}{Integer vector, the cluster index assigned to each
  electrode (winner-take-all over the row-normalized \verb{NMF} loadings).
  When \code{null_class = TRUE}, electrodes whose top loading falls below
  \eqn{1/(2\sqrt{N})} are left unassigned (\code{NA}).}
\item{\code{basis_curves}}{Numeric matrix, time \eqn{\times} number of
  clusters; column \eqn{q} is the basis profile curve \eqn{B_q(t)} for
  cluster \eqn{q}, the first linear-kernel \verb{PCA} component of its member
  \code{C_full} curves, sign-oriented to the cluster mean.}
\item{\code{basis_times}}{Numeric vector, the time axis for
  \code{basis_curves} (the common overlapping time axis, restricted to
  \code{time_window}).}
\item{\code{similarity}}{Numeric matrix, the electrode-by-electrode
  similarity \eqn{\Xi} that was factorized (non-negative, scaled to a maximum
  of one).}
\item{\code{nmf}}{The \code{\link{naive_nmf}} result for the selected rank.}
\item{\code{n_clusters}}{Integer, the number of clusters found.}
\item{\code{domain}}{Numeric \code{c(lo, hi)}, the overlapping time domain
  shared by all electrodes.}
\item{\code{paired},\code{time_window}}{The settings used; \code{time_window}
  is the effective window after clipping into \code{domain}.}
}
}
\description{
Groups recording electrodes by the \emph{shape} of their canonical evoked
response. Each electrode is summarized by \code{\link{crp}} into one
amplitude-normalized canonical shape; an electrode-by-electrode similarity
matrix is factorized with \code{\link{naive_nmf}} to find clusters that share
a response shape, and a representative basis profile curve is extracted per
cluster. This applies the basis-profile-curve (\verb{BPC}) approach
\emph{across electrodes} rather than across stimulation sites; see
\sQuote{References}.
}
\details{
\enumerate{
\item \strong{Common window.} Electrodes may have different time axes
  (\code{\link{crp}} drops \code{NA} samples); the overlapping time domain is
  used, \code{time_window} is clipped into it, and each electrode is subset on
  the fly with no interpolation.
\item \strong{Similarity.} With \code{paired = TRUE} each entry is the
  one-sample t-statistic, across an electrode pair's common trials, of the
  per-trial \verb{CCEP} cross-projection of the \eqn{1/\alpha}-rescaled
  responses; negatives are zeroed, the matrix made symmetric and scaled to a
  maximum of one. With \code{paired = FALSE} it is the cosine cross-projection
  of the \code{C_full} curves.
\item \strong{Rank selection.} \code{\link{naive_nmf}} factorizes the
  similarity at rank \eqn{Q} (from \code{initial_rank}); each rank is re-run a
  few times and the lowest-error fit kept. \eqn{Q} is reduced while
  \eqn{\zeta} - the sum of the upper off-diagonal of the row-normalized
  \eqn{HH^\top} - exceeds \code{zeta_threshold}.
\item \strong{Assignment.} Each electrode takes its winner-take-all cluster
  over the normalized \verb{NMF} loadings; with \code{null_class}, loadings
  below \eqn{1/(2\sqrt{N})} are left unassigned.
\item \strong{Basis curves.} Per cluster, the first linear kernel \verb{PCA}
  component of its members' \code{C_full} curves (as in \code{\link{crp}}).
}
}
\examples{
# Four response shapes; shapes 3 and 4 differ only in amplitude, so they
# cluster together once shapes are amplitude-normalized.
\donttest{

n_time <- 300L
tt <- seq(-0.2, 1, length.out = n_time)
shapes <- list(
  exp(-((tt - 0.08) / 0.03)^2) - 0.5 * exp(-((tt - 0.18) / 0.04)^2),
  exp(-((tt - 0.38) / 0.03)^2) - 0.5 * exp(-((tt - 0.50) / 0.04)^2),
  exp(-((tt - 0.70) / 0.04)^2),
  exp(-((tt - 0.70) / 0.04)^2) * 2
)

# 4 electrodes per shape, each parameterized with crp()
crp_list <- list()
for (g in seq_along(shapes)) {
  for (e in seq_len(4L)) {
    V <- outer(shapes[[g]], runif(15L, 0.5, 1.5)) +
      matrix(rnorm(n_time * 15L, sd = 0.15), n_time, 15L)
    crp_list[[sprintf("elec_\%d_\%d", g, e)]] <-
      crp(V, tt, remove_artifacts = FALSE)
  }
}

res <- crp_cluster(crp_list, verbose = TRUE)
res$n_clusters
table(res$clusters)
plot(res)

}

}
\references{
The \verb{BPC} method is described in \doi{10.1371/journal.pcbi.1008710}; the
underlying \verb{CRP} method in \doi{10.1371/journal.pcbi.1011105}.
}
\seealso{
\code{\link{crp}}, \code{\link{naive_nmf}}
}
