Se você ainda estiver interessado em suavizar as penalidades L0, daria uma olhada na seguinte referência: "Visualização de alterações genômicas por suavização segmentada usando uma penalidade L0" - DOI: 10.1371 / journal.pone.0038230 (uma boa introdução à O Whittaker mais suave pode ser encontrado no artigo P. Eilers "Um perfeito mais suave" - DOI: 10.1021 / ac034173t). Obviamente, para atingir seu objetivo, você precisa trabalhar um pouco em torno do método.
Em princípio, você precisa de 3 ingredientes:
- O mais suave - eu usaria o mais suave de Whittaker. Além disso, usarei o aumento da matriz (ver Eilers e Marx, 1996 - "Suavização flexível com splines B e penalidades", p.101).
- Regressão quantílica - usarei o pacote R quantreg (rho = 0,5) para preguiça :-)
- Penalidade L0 - Seguirei a mencionada "Visualização de alterações genômicas por suavização segmentada usando uma penalidade L0" - DOI: 10.1371 / journal.pone.0038230
Obviamente, você precisaria também de uma maneira de selecionar a quantidade ideal de suavização. Isso é feito pelos meus olhos de carpinteiro neste exemplo. Você pode usar os critérios em DOI: 10.1371 / journal.pone.0038230 (pág. 5, mas eu não tentei no seu exemplo).
Você encontrará um pequeno código abaixo. Deixei alguns comentários como guia.
# Cross Validated example
rm(list = ls()); graphics.off(); cat("\014")
library(splines)
library(Matrix)
library(quantreg)
# The data
set.seed(20181118)
n = 400
x = 1:n
true_fct = stepfun(c(100, 200, 250), c(200, 250, 300, 250))
y = true_fct(x) + rt(length(x), df = 1)
# Prepare bases - Identity matrix (Whittaker)
# Can be changed for B-splines
B = diag(1, n, n)
# Prepare penalty - lambda parameter fix
nb = ncol(B)
D = diff(diag(1, nb, nb), diff = 1)
lambda = 1e2
# Solve standard Whittaker - for initial values
a = solve(t(B) %*% B + crossprod(D), t(B) %*% y, tol = 1e-50)
# est. loop with L0-Diff penalty as in DOI: 10.1371/journal.pone.0038230
p = 1e-6
nit = 100
beta = 1e-5
for (it in 1:nit) {
ao = a
# Penalty weights
w = (c(D %*% a) ^ 2 + beta ^ 2) ^ ((p - 2)/2)
W = diag(c(w))
# Matrix augmentation
cD = lambda * sqrt(W) %*% D
Bp = rbind(B, cD)
yp = c(y, 1:nrow(cD)*0)
# Update coefficients - rq.fit from quantreg
a = rq.fit(Bp, yp, tau = 0.5)$coef
# Check convergence and update
da = max(abs((a - ao)/ao))
cat(it, da, '\n')
if (da < 1e-6) break
}
# Fit
v = B %*% a
# Show results
plot(x, y, pch = 16, cex = 0.5)
lines(x, y, col = 8, lwd = 0.5)
lines(x, v, col = 'blue', lwd = 2)
lines(x, true_fct(x), col = 'red', lty = 2, lwd = 2)
legend("topright", legend = c("True Signal", "Smoothed signal"),
col = c("red", "blue"), lty = c(2, 1))
PS. Esta é minha primeira resposta no Cross Validated. Espero que seja útil e claro o suficiente :-)