
The kedd package (v2.0.0) provides nonparametric kernel
smoothing tools for R: kernel
estimation of a density and of its derivatives of any order
r, kernel functions, their derivatives and convolutions, and
eight data-driven bandwidth selectors. Results are S4 objects with
ggplot2 graphics; the \(O(n^2)\)
criteria run in C++ (Rcpp) with OpenMP.
Authors: Arsalane Chouaib Guidoum (author, maintainer) and Amel Henider (author), with Iago Giné-Vázquez (contributor) — see Authors.
| Kernel | Formula | Support | r max |
|---|---|---|---|
| Gaussian | \(K(x) = \frac{1}{\sqrt{2\pi}} e^{-x^2/2}\) | \((-\infty, +\infty)\) | any |
| Epanechnikov | \(K(x) = \frac{3}{4}(1-x^2)\) | \([-1, 1]\) | 2 |
| Uniform | \(K(x) = \frac{1}{2}\) | \([-1, 1]\) | 0 |
| Triangular | \(K(x) = 1-\lvert x\rvert\) | \([-1, 1]\) | 1 |
| Biweight | \(K(x) = \frac{15}{16}(1-x^2)^2\) | \([-1, 1]\) | 4 |
| Triweight | \(K(x) = \frac{35}{32}(1-x^2)^3\) | \([-1, 1]\) | 6 |
| Tricube | \(K(x) = \frac{70}{81}(1-\lvert x\rvert^3)^3\) | \([-1, 1]\) | 9 |
| Cosine | \(K(x) = \frac{\pi}{4}\cos\left(\frac{\pi x}{2}\right)\) | \([-1, 1]\) | any |
| Silverman | \(K(x) = \frac{1}{2}e^{-\lvert x\rvert/\sqrt{2}}\sin\left(\frac{\lvert x\rvert}{\sqrt{2}}+\frac{\pi}{4}\right)\) | \((-\infty, +\infty)\) | any |
| Logistic | \(K(x) = \frac{e^{-x}}{(1+e^{-x})^2} = \frac{1}{4}\mathrm{sech}^2(x/2)\) | \((-\infty, +\infty)\) | 20 |
| Pow(s,t) | \(K(x) = c_{s,t}(1-\lvert x\rvert^s)^t\), \(c_{s,t} = \frac{s}{2B(1/s,\,t+1)}\) | \([-1, 1]\) | \(\min(st, 16)\) |
Kernels with support \([-1, 1]\) are
zero outside it. “r max” is the highest derivative order with \(K^{(r)} \ne 0\) (kernel.fun(),
kernel.conv(), dkde()); for Pow(s,t) it is
\(\min(st, 16)\) when \(s\) and \(t\) are integers and 16 otherwise. The
selectors have lower limits, given in Maximum derivative order.
The power family is passed as kernel = "pow(s,t)" (or
kernel.pow(s, t)) and contains uniform
pow(s,0), triangular pow(1,1), Epanechnikov
pow(2,1), biweight pow(2,2), triweight
pow(2,3) and tricube pow(3,3). Any \(s > 0\), \(t
\ge 0\) is allowed; derivatives up to order 16 are computed
exactly and the constants \(\mu_2(K)\),
\(\mu_4(K)\), \(R(K)\) come from Beta functions. Logistic
derivatives are available up to order 20.
| Function | Method | Derivative order r | Reference |
|---|---|---|---|
h.amise |
Asymptotic MISE rule (normal reference) | 0, 1, 2, … (max: see below) | Wand & Jones (1995) |
h.ucv |
Unbiased (least-squares) Cross-Validation | 0, 1, 2, … (max: see below) | Rudemo (1982), Bowman (1984) |
h.bcv |
Biased Cross-Validation (BCV1, BCV2) | 0, 1, 2, … (max: see below) | Scott & Terrell (1987) |
h.ccv |
Complete Cross-Validation | 0, 1, 2, … (max: see below) | Jones & Kappenman (1991) |
h.mcv |
Modified Cross-Validation | 0, 1, 2, … (max: see below) | Stute (1992) |
h.tcv |
Trimmed Cross-Validation | 0, 1, 2, … (max: see below) | Feluch & Koronacki (1992) |
h.scv |
Smoothed Cross-Validation (Gaussian kernel) | 0, 1, 2, … (no limit) | Hall, Marron & Park (1992) |
h.mlcv |
Maximum-Likelihood Cross-Validation | 0 only | Habbema et al. (1974), Duin (1976) |
With the Gaussian and Silverman kernels every order r is allowed; with the other kernels r is limited, as given in the table Maximum derivative order r below.
All selectors return an S4 object of class bandwidth;
the search interval is [0.01 * hos, 2 * hos] by default,
hos being the over-smoothing bandwidth.
Highest deriv.order for each kernel. Above it,
kernel.fun(), kernel.conv() and
dkde() return zero, and the selectors return
h = NA with a warning (the criterion is not finite); “—”
means not available even at \(r =
0\).
| Kernel | kernel.fun,
kernel.conv, dkde |
h.ucv, h.bcv,
h.tcv, h.amise |
h.mcv |
h.ccv |
|---|---|---|---|---|
| Gaussian, Silverman | any | any | any | any |
| cosine | any | 1 | 0 | — |
| logistic | 20 | 8 | 8 | 8 |
| Epanechnikov | 2 | 1 | 0 | — |
| uniform | 0 | 0 | — | — |
| triangular | 1 | 0 | — | — |
| biweight | 4 | 2 | 1 | 0 |
| triweight | 6 | 3 | 2 | 1 |
| tricube | 9 | 3 | 2 | 1 |
| pow(s,t) | \(\min(st, 16)\) | \(\min(r^\ast, 6)\) | \(\min(r^\ast-1, 6)\) | \(\min(r^\ast-2, 6)\) |
For Pow(s,t), \(r^\ast\) is the
largest integer \(r < t + \frac12\),
with \(2r \le st\) when \(s\) and \(t\) are integers and \(r < s + \frac12\) when \(s\) is not an even integer (so
pow(3,3) and tricube both give 3, 2, 1).
Examples: pow(2,3) 6, 3, 2, 1; pow(2,8) 16, 6,
6, 6; pow(1.5,2.5) 16, 1, 0, —. h.scv
(Gaussian kernel) has no limit and h.mlcv is for \(r = 0\) only. The same table is in
?kedd (section Maximum derivative order).
kernel.fun() — evaluate \(K^{(r)}(x)\) → S4 class kfun
with show() and plot()kernel.conv() — evaluate \((K^{(r)} * K^{(r)})(x)\) → S4 class
kconvkernel.pow(s, t) — name of a Pow(s,t) kernel, usable in
every functiondkde() — kernel density (or derivative) estimate → S4
class dkdebandwidth
with show() and plot()lines(bw) returns a layer:
plot(bw1)$plot + lines(bw2)# Development version 2.0.0 from GitHub
# install.packages("remotes")
remotes::install_github("ac-guidoum/kedd", build_vignettes = TRUE)
# Version 2.0.0 from the source tarball
install.packages("kedd_2.0.0.tar.gz", repos = NULL, type = "source")
# or from the source directory
devtools::install("path/to/kedd_2.0.0")
# Released version on CRAN
install.packages("kedd")Version 2.0.0 compiles C++ code: on Windows this needs Rtools.
library(kedd)
x <- rnorm(500)
# Kernel density estimate (bandwidth chosen by UCV when h is missing)
d <- dkde(data = x, kernel = "gaussian")
plot(d)
# First derivative with its own bandwidth
h1 <- h.scv(x, deriv.order = 1)
plot(dkde(data = x, h = h1@h, deriv.order = 1))
# Bandwidth selectors
h.ucv(x) # unbiased CV
h.bcv(x) # biased CV
h.scv(x) # smoothed CV (Gaussian kernel)
# Kernel function evaluation
kf <- kernel.fun(kernel = "epanechnikov", deriv.order = 1L)
plot(kf)
# Logistic and Pow(s,t) kernels
h.ucv(x, kernel = "logistic")
h.bcv(x, kernel = kernel.pow(2, 4)) # same as kernel = "pow(2,4)"
plot(kernel.fun(kernel = "pow(1.5,2.5)", deriv.order = 1L))
# Overlay two CV curves (ggplot2)
p <- plot(h.ucv(x))
p$plot + lines(h.bcv(x))Five samples of size 200 from the Marron & Wand (1992) normal
mixtures, with known true densities (see ?"kedd-data"):
| Dataset | Marron & Wand density |
|---|---|
kurtotic |
#4 kurtotic unimodal: \(\frac23 N(0,1) + \frac13 N(0, 0.1^2)\) |
outlier |
#5 outlier: \(\frac1{10} N(0,1) + \frac9{10} N(0, 0.1^2)\) |
bimodal |
#7 separated bimodal: \(\frac12 N(-1.5, 0.5^2) + \frac12 N(1.5, 0.5^2)\) |
trimodal |
#9 trimodal: \(\frac9{20} N(-1.2, 0.6^2) + \frac9{20} N(1.2, 0.6^2) + \frac1{10} N(0, 0.25^2)\) |
claw |
#10 claw: \(\frac12 N(0,1) + \sum_{l=0}^{4}\frac1{10} N(l/2-1, 0.1^2)\) |
h.mcv(claw)
plot(dkde(data = bimodal, h = h.ucv(bimodal, deriv.order = 1)@h, deriv.order = 1))A two-page summary of the package is available in cheatsheet/kedd-cheatsheet.pdf
(source: cheatsheet/kedd-cheatsheet.html).
vignette("kedd", package = "kedd") # theory, kernels, estimators, selectors, examples
demo(package = "kedd") # list of demos
demo("kedd", package = "kedd") # quick tour
demo("kernels", package = "kedd") # kernels, derivatives, convolutions, Pow(s,t)
demo("bandwidths", package = "kedd") # all selectors compared on a bimodal sampleThe testthat suite (≈1,460 expectations) covers every
selector × kernel, the nthreads behaviour, the content of
every ggplot2 figure (plot(), lines()), the
datasets and input validation. It checks every kernel constant (\(\mu_2\), \(\mu_4\), \(R(K^{(r)})\)), convolution and derivative,
for every kernel and every implemented order, against numerical
integration, and checks Pow(s,t) against the named kernels it
generalises (identical kernels, convolutions and bandwidths).
Line coverage measured with covr
(tests only): 99.5 % overall.
| File | Coverage | File | Coverage |
|---|---|---|---|
src/kedd.cpp |
99.6 % | R/h.mcv.R |
100 % |
R/bandwidth-class.R |
100 % | R/h.mlcv.R |
100 % |
R/dkde.R |
98.9 % | R/h.scv.R |
100 % |
R/h.amise.R |
100 % | R/h.tcv.R |
100 % |
R/h.bcv.R |
100 % | R/h.ucv.R |
100 % |
R/h.ccv.R |
100 % | R/kernel.fun.R |
98.4 % |
R/utils.R |
98.3 % |
cv <- covr::package_coverage("path/to/kedd_2.0.0", type = "tests")
covr::percent_coverage(cv) # 99.5
covr::report(cv) # line-by-line HTML report
source("data-raw/benchmark.R") # execution time of every functionCRAN downloads of kedd from the RStudio/Posit CRAN
mirror, obtained with cranlogs
(daily counts since 2014) and cross-checked with dlstats
(monthly counts; identical on the 69 months both cover, Jan 2021 – Sep
2026).
| Statistic (as of 29 Oct 2026) | Value |
|---|---|
| Total downloads (Aug 2014 – Oct 2026) | 64,271 |
| Last month | 387 |
| Last week | 54 |
| Monthly mean / median | 437 / 309 |
| Best month | Sep 2025 (1,776) |
| Year | 2014* | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026* |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Downloads | 1,285 | 3,872 | 2,818 | 2,918 | 3,856 | 7,657 | 12,813 | 10,566 | 4,844 | 743 | 3,462 | 6,260 | 3,177 |
* partial years (from Aug 2014; to 29 Oct 2026). The badges above are live; the figures in this section are a snapshot.
library(cranlogs)
sum(cran_downloads("kedd", from = "2014-08-01", to = Sys.Date() - 1)$count) # total
cran_downloads("kedd", when = "last-month")
library(dlstats)
x <- cran_stats("kedd") # monthly downloads
plot_cran_stats("kedd")The figure and the numbers are regenerated with
source("data-raw/downloads.R").
| Name | Role | Contact |
|---|---|---|
| Arsalane Chouaib Guidoum | author, maintainer | acguidoum@univ-tam.dz · ORCID 0000-0003-3781-2160 |
| Amel Henider | author | amel.henider@univ-tam.dz |
| Iago Giné-Vázquez | contributor | iago.gin-vaz@protonmail.com · ORCID 0000-0002-6725-2638 |
Source code: https://github.com/ac-guidoum/kedd · bug reports and suggestions: https://github.com/ac-guidoum/kedd/issues.
To cite the package (citation("kedd")):
Guidoum, A. C. (2020). Kernel estimator and bandwidth selection for density and its derivatives: the kedd package. arXiv:2012.06102. https://doi.org/10.48550/arXiv.2012.06102