La regressione della cresta è inutile in dimensioni elevate (


50

Considera un buon vecchio problema di regressione con predittori e dimensione del campione . La solita saggezza è che lo stimatore OLS si sovraccaricherà e sarà generalmente sovraperformato dallo stimatore della regressione della cresta:È standard utilizzare la convalida incrociata per trovare un parametro di regolarizzazione ottimale . Qui uso un CV di 10 volte. Aggiornamento di chiarimento: quando , per "stimatore OLS" capisco "stimatore OLS a norma minima" dato dapβ = ( X X + λ I ) - 1 X y . λ n < p β OLS = ( X X ) + X Y = X + Y .n

β^=(XX+λI)1Xy.
λn<p
β^OLS=(XX)+Xy=X+y.

Ho un set di dati con e . Tutti i predittori sono standardizzati e ce ne sono alcuni che (da soli) possono fare un buon lavoro nel predire . Se seleziono casualmente un piccolo ish, diciamo , numero di predittori, ottengo una curva CV ragionevole: grandi valori di producono zero R al quadrato, piccoli valori di danno negativo al R-quadrato (perché di overfitting) e c'è un massimo nel mezzo. Per la curva è simile. Tuttavia, per molto più grande di quello, ad esempio , non ottengo alcun massimo: gli altipiani della curva, il che significa che OLS conn=80p>1000yλ λ p = 100 > n p p = 1000 λ 0p=50<nλλp=100>npp=1000λ0 comporta bene come la regressione della cresta con ottimale .λ

inserisci qui la descrizione dell'immagine

Come è possibile e cosa dice del mio set di dati? Mi sto perdendo qualcosa di ovvio o è davvero controintuitivo? Come può esserci una differenza qualitativa tra e dato che entrambi sono maggiori di ?p = 1000 np=100p=1000n

In quali condizioni la soluzione OLS a norma minima per non si adatta?n<p


Aggiornamento: c'era qualche incredulità nei commenti, quindi ecco un esempio riproducibile usando glmnet. Uso Python ma gli utenti R adattano facilmente il codice.

%matplotlib notebook

import numpy as np
import pylab as plt
import seaborn as sns; sns.set()

import glmnet_python    # from https://web.stanford.edu/~hastie/glmnet_python/
from cvglmnet import cvglmnet; from cvglmnetPlot import cvglmnetPlot

# 80x1112 data table; first column is y, rest is X. All variables are standardized
mydata = np.loadtxt('../q328630.txt')   # file is here https://pastebin.com/raw/p1cCCYBR
y = mydata[:,:1]
X = mydata[:,1:]

# select p here (try 1000 and 100)
p = 1000

# randomly selecting p variables out of 1111
np.random.seed(42)
X = X[:, np.random.permutation(X.shape[1])[:p]]

fit = cvglmnet(x = X.copy(), y = y.copy(), alpha = 0, standardize = False, intr = False, 
               lambdau=np.array([.0001, .001, .01, .1, 1, 10, 100, 1000, 10000, 100000]))
cvglmnetPlot(fit)
plt.gcf().set_size_inches(6,3)
plt.tight_layout()

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


2
@DJohnson Non scherzo. Solito CV 10 volte, il che significa che ogni set di allenamento ha n = 72 e ogni set di test ha n = 8.
ameba dice di reintegrare Monica il

2
Questo è tutt'altro che un normale CV. Dato che come ci si potrebbe aspettare qualcosa di simile a un risultato rilevabile?
Mike Hunter,

3
@DJohnson Non capisco perché stai dicendo che è tutt'altro che normale. Questo è il CV di 10 volte.
ameba dice di reintegrare Monica il

2
@ seanv507 Capisco. Bene, suggerisco di definire "soluzione con lambda = 0" come "soluzione di minima norma con lambda = 0". Immagino che la mia domanda possa essere riformulata nel modo seguente: In quali condizioni la soluzione OLS a norma minima con n <p overfit vs. non overfit?
ameba dice di reintegrare Monica il

3
@amoeba: grazie per questa domanda. Finora è stato estremamente istruttivo e interessante.
usεr11852 dice Reinstate Monic il

Risposte:


23

Una regolarizzazione naturale avviene a causa della presenza di molti piccoli componenti nel PCA teorico dix . Questi piccoli componenti vengono implicitamente utilizzati per adattarsi al rumore utilizzando coefficienti di dimensioni ridotte. Quando si utilizza OLS a norma minima, si adatta il rumore con molti piccoli componenti indipendenti e questo ha un effetto regolarizzante equivalente alla regolarizzazione di Ridge. Questa regolarizzazione è spesso troppo forte ed è possibile compensarla usando "anti-regolarizzazione" nota come Ridge negativo . In tal caso, verrà visualizzato il minimo della curva MSE per valori negativi di .λ

Per PCA teorico intendo:

Sia una distribuzione normale multivariata. Esiste un'isometria lineare come dove è diagonale: i componenti di sono indipendenti. si ottiene semplicemente diagonalizzando .xN(0,Σ)u = f ( x ) N ( 0 , D ) D u D Σfu=f(x)N(0,D)DuDΣ

Ora il modello può essere scritto (un'isometria lineare preserva il punto prodotto). Se scrivi , il modello può essere scritto . Inoltrequindi metodi di adattamento come Ridge o OLS a norma minima sono perfettamente isomorfi: lo stimatore di è l'immagine per dello stimatore di .y=β.x+ϵy=f(β).f(x)+ϵγ=f(β)y=γ.u+ϵy = γ . u + ϵ f y = β . x + ϵβ=γy=γ.u+ϵfy=β.x+ϵ

Il PCA teorico trasforma predittori non indipendenti in predittori indipendenti. È solo vagamente correlato alla PCA empirica in cui si utilizza la matrice di covarianza empirica (che differisce molto da quella teorica con piccole dimensioni del campione). La PCA teorica non è praticamente calcolabile, ma qui viene utilizzata solo per interpretare il modello in uno spazio predittore ortogonale.

Vediamo cosa succede quando aggiungiamo molti predittori indipendenti di piccola varianza a un modello:

Teorema

La regolarizzazione della cresta con coefficiente è equivalente (quando ) a:p λp

  • aggiungendo falsi predittori indipendenti (centrati e distribuiti in modo identico) ciascuno con varianzaλpλp
  • adattando il modello arricchito con lo stimatore OLS a norma minima
  • mantenendo solo i parametri per i veri predittori

(schizzo di) Prova

Dimostreremo che le funzioni di costo sono asintoticamente uguali. Dividiamo il modello in predittori reali e falsi: . La funzione di costo di Ridge (per i veri predittori) può essere scritta:y=βx+βx+ϵ

costλ=β2+1λyXβ2

Quando si utilizza la norma minima OLS, la risposta è adattata perfettamente: il termine di errore è 0. La funzione di costo riguarda solo la norma dei parametri. Può essere suddiviso in parametri veri e falsi:

costλ,p=β2+inf{β2Xβ=yXβ}

Nella giusta espressione, la soluzione della norma minima è data da:

β=X+(yXβ)

Ora usando SVD per :X

X=UΣV

X+=VΣ+U

Vediamo che la norma di dipende essenzialmente dai valori singolari di che sono i reciproci dei valori singolari di . La versione normalizzata di è . Ho esaminato la letteratura e sono noti valori singolari di grandi matrici casuali. Per e abbastanza grandi, i valori singolari minimo e massimo sono approssimati di (vedi teorema 1.1 ):X + X X βX+XXpnsminsmaxp/λXpnsminsmax

smax(

smin(p/λX)p(1n/p)
smax(p/λX)p(1+n/p)

Poiché, per grande , tende verso 0, possiamo solo dire che tutti i valori singolari sono approssimati di . Così:pn/pp

β1λyXβ

Finalmente:

costλ,pβ2+1λyXβ2=costλ

Nota : non importa se si mantengono i coefficienti dei falsi predittori nel modello. La varianza introdotta da è . Quindi aumenti il ​​tuo MSE di un fattore che tende comunque verso 1. In qualche modo non è necessario trattare i falsi predittori in modo diverso rispetto a quelli reali.λβx1+n/pλpβ21pyXβ2npMSE(β)1+n/p

Ora, torniamo ai dati di @ amoeba. Dopo aver applicato il PCA teorico a (assunto come normale), viene trasformato da un'isometria lineare in una variabile cui componenti sono indipendenti e ordinati in ordine decrescente di varianza. Il problema è equivalente al problema trasformato .x u y = β x + ϵ y = γ u + ϵxxuy=βx+ϵy=γu+ϵ

Ora immagina che la varianza dei componenti assomigli a:

inserisci qui la descrizione dell'immagine

Considera molte degli ultimi componenti, chiama la somma della loro varianza . Ognuno di essi ha una varianza approssimativamente uguale a e sono indipendenti. Interpretano il ruolo dei falsi predittori nel teorema.λ λ / ppλλ/p

Questo fatto è più chiaro nel modello di @ jonny: solo il primo componente del PCA teorico è correlato a (è proporzionale ) e presenta un'enorme varianza. Tutti gli altri componenti (proporzionali a ) hanno una varianza relativamente piccola (scrivi la matrice di covarianza e diagonalizzandola per vederlo) e svolgono il ruolo di falsi predittori. Ho calcolato che la regolarizzazione qui corrisponde (approssimativamente) alla precedente su mentre il vero . Questo decisamente si restringe. Ciò è visibile dal fatto che l'MSE finale è molto più grande dell'MSE ideale. L'effetto di regolarizzazione è troppo forte.¯ x x i - ¯ x N ( 0 , 1yx¯xix¯γ1γ 2 1 =1N(0,1p2)γ1γ12=1p

A volte è possibile migliorare questa regolarizzazione naturale da parte di Ridge. Per prima cosa a volte hai bisogno di nel teorema veramente grande (1000, 10000 ...) per competere seriamente con Ridge e la finezza di è come un'imprecisione. Ma mostra anche che Ridge è un'ulteriore regolarizzazione rispetto a una regolarizzazione implicita naturalmente esistente e può quindi avere solo un effetto molto piccolo. A volte questa regolarizzazione naturale è già troppo forte e Ridge potrebbe non essere nemmeno un miglioramento. Più di questo, è meglio usare l'anti-regolarizzazione: Ridge con coefficiente negativo. Questo mostra MSE per il modello di @ jonny ( ), usando :p p = 1000 λ Rppp=1000λR

inserisci qui la descrizione dell'immagine


2
+1 Molto bello, grazie per averlo scritto. Penso che sia importante chiarire che quando dici "regolarizzazione" intendi la regolarizzazione (ovvero la cresta). Si potrebbe sperare che al netto lazo o elastico può comportarsi meglio e in effetti questo è ciò che la gente sta usando in situazioni. Nessuno usa la cresta pura in una tale impostazione e il consiglio standard è di usare regolarizzazioni che impongono la scarsità; quindi il comportamento della cresta pura potrebbe avere solo un interesse accademico. Tuttavia, è piuttosto sorprendente che sembriamo scoprirlo qui. Perché questo non è noto ?? n pL2np
ameba dice di reintegrare Monica il

1
scarsamente codificato in modo proporzionale a . Scusa se non ho tempo per qualcosa di appropriato. Il mio obiettivo principale era il comportamento dell'OLS a norma minima, per vedere che differisce dal tuo esempio e che "una regolarizzazione non troppo negativa" su 40 primati era violentemente migliore. σ 2λσ2
Benoit Sanchez,

3
Penso di aver capito il mistero: la regolarizzazione della cresta con coefficiente equivale alla OLS min-norma che aggiunge falsi predittori ciascuno con varianza (asintoticamente per grandi dimensioni ). Nei tuoi dati e nel modello di Johny succede senza fare nulla grazie ai componenti con varianza più bassa da PCA. Ora ho bisogno di tempo per trovare un modo per spiegarlo chiaramente ...p λ / p pλpλ/pp
Benoit Sanchez,

1
Ho chiarito un piccolo punto: i coefficienti dei falsi predittori non aumentano molto l'errore (vedi nota alla fine della prova). È importante perché nei tuoi dati / jonny sono inevitabilmente conservati.
Benoit Sanchez,

3
Ho provato Ridge negativo. Non ci posso credere ma funziona !!! (e non solo sul modello di Jonny ...)
Benoit Sanchez,

16

Grazie a tutti per l'ottima discussione in corso. Il nocciolo della questione sembra essere che l' OLS a norma minima sta effettivamente eseguendo un restringimento simile alla regressione della cresta. Questo sembra accadere ogni volta che . Ironia della sorte, l' aggiunta di predittori di puro rumore può persino essere usata come una forma molto strana o regolarizzazione.pn


Parte I. Dimostrazione con dati artificiali e CV analitico

@Jonny (+1) ha trovato un esempio artificiale molto semplice che qui mi adatterò leggermente. di dimensioni sono generate in modo tale che tutte le variabili sono gaussiane con varianza unitaria e la correlazione tra ciascun predittore e la risposta è . Riparerò .n × p y ρ ρ = .2Xn×pyρρ=.2

Userò un CV lasciato in sospeso perché esiste un'espressione analitica per l'errore al quadrato: è noto come PRESS , "somma prevista dei quadrati". dove sono residui e è il matrice cappello in termini di SVD . Ciò consente di replicare i risultati di @ Jonny senza utilizzare e senza eseguire effettivamente la convalida incrociata (sto pianificando il rapporto tra PRESS e la somma dei quadrati di ):

PRESS=i(ei1Hii)2,
ei
e=yy^=yHy,
H
H=X(XX+λI)1X=US2S2+λU
X=USVglmnety

inserisci qui la descrizione dell'immagine

Questo approccio analitico consente di calcolare il limite a . Inserire semplicemente nella formula PRESS non funziona: quando e , i residui sono tutti zero e la matrice del cappello è la matrice dell'identità con quelli sulla diagonale, il che significa che le frazioni nella PRESS l'equazione non è definita. Ma se calcoliamo il limite in , allora corrisponderà alla soluzione OLS di minima norma con .λ0λ=0n<pλ=0λ0λ=0

Il trucco è fare l'espansione di Taylor della matrice cappello quando : Qui ho introdotto la matrice Gram .λ0

H=U11+λ/S2UU(1λ/S2)U=IλUS2U=IλG1.
G=XX=US2U

Abbiamo quasi finito:Lambda è stata cancellata, quindi qui abbiamo il valore limite. L'ho tracciato con un grosso punto nero sulla figura sopra (sui pannelli in cui ), e si abbina perfettamente.

PRESS=i(λ[G1y]iλGii1)2=i([G1y]iGii1)2.
p>n

Aggiornamento del 21 febbraio. La formula sopra è esatta, ma possiamo ottenere alcune informazioni facendo ulteriori approssimazioni. Sembra che abbia valori approssimativamente uguali sulla diagonale anche se ha valori molto disuguali (probabilmente perché mescola abbastanza bene tutti gli autovalori). Quindi per ogni abbiamo quel dove le parentesi angolari indicano la media. Usando questa approssimazione, possiamo riscrivere:Questa approssimazione è mostrata nella figura sopra con cerchi aperti rossi.G1SUiGii1S2

PRESSS2S2Uy2.

Se sarà maggiore o minore di dipende dai valori singolari . In questa simulazione è correlato al primo PC di quindi è grande e tutti gli altri termini sono piccoli. (Nei miei dati reali, è anche ben previsto dai PC principali.) Ora, nel caso , se le colonne di sono sufficientemente casuali, allora tutti i valori singolari saranno piuttosto vicini l'uno all'altro (righe approssimative ortogonale). Il termine "principale"y2=Uy2SyXU1yypnXU1yverrà moltiplicato per un fattore inferiore a 1. I termini verso la fine verranno moltiplicati per fattori maggiori di 1 ma non molto maggiori. Nel complesso la norma diminuisce. Al contrario, nel caso , ci saranno alcuni valori singolari molto piccoli. Dopo l'inversione diventeranno grandi fattori che aumenteranno la norma generale.pn

[Questo argomento è molto ondulato; Spero che possa essere reso più preciso.]

Come controllo di integrità, se cambio l'ordine dei valori singolari per S = diag(flipud(diag(S)));allora l'MSE previsto è superiore a ovunque sul 2 ° e 3 ° pannello.1

figure('Position', [100 100 1000 300])
ps = [10, 100, 1000];

for pnum = 1:length(ps)
    rng(42)
    n = 80;
    p = ps(pnum);
    rho = .2;
    y = randn(n,1);
    X = repmat(y, [1 p])*rho + randn(n,p)*sqrt(1-rho^2);

    lambdas = exp(-10:.1:20);
    press = zeros(size(lambdas));
    [U,S,V] = svd(X, 'econ');
    % S = diag(flipud(diag(S)));   % sanity check

    for i = 1:length(lambdas)
        H = U * diag(diag(S).^2./(diag(S).^2 + lambdas(i))) * U';
        e = y - H*y;
        press(i) = sum((e ./ (1-diag(H))).^2);
    end

    subplot(1, length(ps), pnum)
    plot(log(lambdas), press/sum(y.^2))
    hold on
    title(['p = ' num2str(p)])
    plot(xlim, [1 1], 'k--')

    if p > n
        Ginv = U * diag(diag(S).^-2) * U';
        press0 = sum((Ginv*y ./ diag(Ginv)).^2);
        plot(log(lambdas(1)), press0/sum(y.^2), 'ko', 'MarkerFaceColor', [0,0,0]);

        press0approx = sum((diag(diag(S).^-2/mean(diag(S).^-2)) * U' * y).^2);
        plot(log(lambdas(1)), press0approx/sum(y.^2), 'ro');
    end
end

Seconda parte. Aggiunta di predittori di rumore puro come forma di regolarizzazione

Argomenti positivi sono stati fatti da @Jonny, @Benoit, @Paul, @Dikran e altri sul fatto che l'aumento del numero di predittori ridurrà la soluzione OLS a norma minima. Infatti, una volta , qualsiasi nuovo predittore può solo diminuire la norma della soluzione di minima norma. Quindi l'aggiunta di predittori spingerà la norma verso il basso, in qualche modo simile a come la regressione della cresta sta penalizzando la norma.p>n

Quindi può essere usato come strategia di regolarizzazione? Iniziamo con e e quindi continuiamo ad aggiungere predittori di puro rumore come tentativo di regolarizzazione. Farò LOOCV e lo confronterò con LOOCV per la cresta (calcolata come sopra). Nota che dopo aver ottenuto sui predittori , lo sto "troncando" in perché sono interessato solo ai predittori originali.n=80p=40qβ^p+qp

inserisci qui la descrizione dell'immagine

FUNZIONA!!!

In effetti, non è necessario "troncare" la beta; anche se utilizzo la versione beta completa e tutti i predittori , posso ottenere buone prestazioni (linea tratteggiata nella sottotrama corretta). Penso che questo imiti i miei dati reali nella domanda: solo pochi predittori stanno davvero predicendo , la maggior parte di essi è puro rumore e servono da regolarizzazione. In questo regime, la regolarizzazione della cresta aggiuntiva non aiuta affatto.p+qy

rng(42)
n = 80;
p = 40;
rho = .2;
y = randn(n,1);
X = repmat(y, [1 p])*rho + randn(n,p)*sqrt(1-rho^2);

lambdas = exp(-10:.1:20);
press = zeros(size(lambdas));
[U,S,V] = svd(X, 'econ');

for i = 1:length(lambdas)
    H = U * diag(diag(S).^2./(diag(S).^2 + lambdas(i))) * U';
    e = y - H*y;
    press(i) = sum((e ./ (1-diag(H))).^2);
end

figure('Position', [100 100 1000 300])
subplot(121)
plot(log(lambdas), press/sum(y.^2))
hold on
xlabel('Ridge penalty (log)')
plot(xlim, [1 1], 'k--')
title('Ridge regression (n=80, p=40)')
ylim([0 2])

ps = [0 20 40 60 80 100 200 300 400 500 1000];
error = zeros(n, length(ps));
error_trunc = zeros(n, length(ps));
for fold = 1:n
    indtrain = setdiff(1:n, fold);
    for pi = 1:length(ps)
        XX = [X randn(n,ps(pi))];
        if size(XX,2) < size(XX,1)
            beta = XX(indtrain,:) \ y(indtrain,:);
        else
            beta = pinv(XX(indtrain,:)) * y(indtrain,:);
        end
        error(fold, pi) = y(fold) - XX(fold,:) * beta;
        error_trunc(fold, pi) = y(fold) - XX(fold,1:size(X,2)) * beta(1:size(X,2));
    end
end

subplot(122)
hold on
plot(ps, sum(error.^2)/sum(y.^2), 'k.--')
plot(ps, sum(error_trunc.^2)/sum(y.^2), '.-')
legend({'Entire beta', 'Truncated beta'}, 'AutoUpdate','off')
legend boxoff
xlabel('Number of extra predictors')
title('Extra pure noise predictors')
plot(xlim, [1 1], 'k--')
ylim([0 2])

@MartijnWeterings In questo esperimento, inizio con n = 80 e p = 40. Man mano che il numero totale di predittori (p + q) si avvicina a n = 80, il problema diventa mal condizionato e la soluzione OLS si adatta drasticamente. C'è un picco enorme nell'errore attorno a q = 40. Non appena p + q> n, il vincolo "minima-norma" si attiva e l'errore inizia a diminuire, ma ci vuole del tempo prima che torni a dove era con q = 0. Succede intorno a q = 70, ovvero p + q = 130. Successivamente, l'errore sta diminuendo ulteriormente e questa parte del diagramma è simile al diagramma di regressione della cresta. Ha senso?
ameba dice di reintegrare Monica il

@MartijnWeterings Al primo commento: siamo sulla stessa pagina. Al secondo commento: nella mia domanda non sto troncando la beta, è vero. Ma in realtà se non troncare la beta nella mia simulazione (usare y(fold) - XX(fold,:) * betainvece di XX(fold,1:size(X,2)) * beta(1:size(X,2))), i risultati non cambiano troppo. Immagino che dovrei aggiungere questo alla mia risposta. Penso che i miei dati originali mostrino questo tipo di comportamento.
ameba dice di reintegrare Monica il

(1/2): Sto ancora cercando di capire tutti i commenti e il codice per capire, ma mi viene in mente un pensiero: esiste una relazione tra questo fenomeno che stiamo osservando e la relazione tra regressione della cresta ed effetti casuali?
Ryan Simmons,

(2/2): qui la risposta di Randel ( stats.stackexchange.com/questions/122062/… ), vediamo una stima equivalente tra effetti casuali e regressione della cresta, dove lambda è uguale al rapporto tra i residui e la varianza di l'effetto casuale. Qui, secondo la risposta di Benoit Sanchez, vediamo che la regressione della cresta equivale all'aggiunta di un numero arbitrario di falsi predittori indipendenti ciascuno con varianza uguale a una funzione di lambda e al numero di parametri. Mi sembra che ci sia una relazione concettuale.
Ryan Simmons,

@amoeba è stato un errore. l'aggiunta di un vettore in scala y alla matrice X regolarizza in qualche modo ma non è la stessa della regressione della cresta o dei vettori di rumore. Tuttavia, mi chiedo cosa succede quando sottraggiamo un po 'di da ogni x per rendere ogni variabile leggermente correlata negativamente (o meno positiva) con il vettore y. Questo al fine di eseguire una certa regolarizzazione "negativa". Ciò per 'annullare' la regolarizzazione dei 1000 vettori (ad un certo punto potrebbe diventare troppo, come si vede con il coefficiente di regolarizzazione picco / ottimale ora quasi fuori portata). y
Sesto Empirico,

15

Ecco una situazione artificiale in cui ciò si verifica. Supponiamo che ogni variabile predittore sia una copia della variabile target con una grande quantità di rumore gaussiano applicato. Il miglior modello possibile è una media di tutte le variabili predittive.

library(glmnet)
set.seed(1846)
noise <- 10
N <- 80
num.vars <- 100
target <- runif(N,-1,1)
training.data <- matrix(nrow = N, ncol = num.vars)
for(i in 1:num.vars){
  training.data[,i] <- target + rnorm(N,0,noise)
}
plot(cv.glmnet(training.data, target, alpha = 0,
               lambda = exp(seq(-10, 10, by = 0.1))))

MSE per vari lambda con 100 predittori

100 variabili si comportano in modo "normale": alcuni valori positivi di lambda riducono al minimo l'errore del campione.

Ma aumenta num.vars nel codice sopra a 1000, ed ecco il nuovo percorso MSE. (Ho esteso a log (Lambda) = -100 per convincermi.

MSE per vari lambda con 1000 predittori

Quello che penso stia succedendo

Quando si adattano molti parametri con bassa regolarizzazione, i coefficienti vengono distribuiti casualmente attorno al loro valore reale con varianza elevata.

Man mano che il numero di predittori diventa molto grande, l '"errore medio" tende verso lo zero e diventa meglio lasciar cadere i coefficienti dove possono e sommare tutto piuttosto che inclinarli verso 0.

Sono sicuro che questa situazione in cui la vera previsione è una media di tutti i predittori non è l'unica volta che si verifica, ma non so come iniziare a individuare qui la più grande condizione necessaria.

MODIFICARE:

Il comportamento "piatto" per lambda molto bassa si verificherà sempre, poiché la soluzione sta convergendo alla soluzione OLS di minima norma. Allo stesso modo la curva sarà piatta per lambda molto alta poiché la soluzione converge a 0. Non ci sarà alcun minimo se una di queste due soluzioni è ottimale.

Perché la soluzione OLS a norma minima è così (comparativamente) buona in questo caso? Penso che sia correlato al seguente comportamento che ho trovato molto controintuitivo, ma sulla riflessione ha molto senso.

max.beta.random <- function(num.vars){
  num.vars <- round(num.vars)
  set.seed(1846)
  noise <- 10
  N <- 80
  target <- runif(N,-1,1)
  training.data <- matrix(nrow = N, ncol = num.vars)

  for(i in 1:num.vars){
    training.data[,i] <- rnorm(N,0,noise)
  }
  udv <- svd(training.data)

  U <- udv$u
  S <- diag(udv$d)
  V <- udv$v

  beta.hat <- V %*% solve(S) %*% t(U) %*% target

  max(abs(beta.hat))
}


curve(Vectorize(max.beta.random)(x), from = 10, to = 1000, n = 50,
      xlab = "Number of Predictors", y = "Max Magnitude of Coefficients")

abline(v = 80)

Grafico della magnitudine massima dei coefficienti all'aumentare del numero di predittori

Con predittori generati casualmente non correlati alla risposta, quando p aumenta i coefficienti diventano più grandi, ma una volta che p è molto più grande di N si riducono verso lo zero. Questo succede anche nel mio esempio. Quindi, in modo molto approssimativo, le soluzioni non regolamentate per questi problemi non hanno bisogno di restringimento perché sono già molto piccole!

Questo accade per una ragione banale. può essere espressa esattamente come combinazione lineare delle colonne di . è il vettore minimo di coefficienti. Man mano che vengono aggiunte più colonne, la norma di deve diminuire o rimanere costante, poiché una possibile combinazione lineare è quella di mantenere gli stessi coefficienti precedenti e impostare i nuovi coefficienti su .yXβ^β^0


1
(+1). Il fenomeno sembra quindi verificarsi quando i predittori sono correlati. Non significa formalmente che la curva di errore non abbia un minimo per positivo , né che il limite a 0 non sia grande. Significa solo che la curva tende a diventare piatta e che la soglia per quanto deve essere piccolo affinché la regolarizzazione smetta di funzionare tende verso 0 per grande . Qui questa soglia va oltre il limite computazionale ma la risposta di Firebug suggerisce che potrebbe sempre esistere. λλp
Benoit Sanchez,

1
Perché è necessario glmnetnel tuo aggiornamento? Se hai solo bisogno di una soluzione OLS a norma minima, allora c'è una formula diretta (vedi la seconda formula nella mia domanda) e se uno calcola SVD di allora questa formula diventa semplicemente . Probabilmente esiste anche una funzione in R che calcola questa soluzione ma non conosco davvero R :)ß = V S - 1 U yX=USVβ^=VS1Uy
ameba dice Reinstate Monica il

2
Pensandoci un po 'di più non è affatto sorprendente. può essere espressa esattamente come combinazione lineare di vettori in . è il vettore di coefficienti con la norma più piccola. Quando aggiungi un vettore, la norma di deve diminuire o rimanere della stessa dimensione, perché potresti mantenere gli stessi coefficienti vecchi e impostare i nuovi a zero. X ß ßyXβ^β^
Jonny Lomond,

3
L'esempio di Jonny è buono perché è già stato analizzato: vedi lo stimatore di James-Stein . Quando si stima la media di un vettore fisso con dimensione 3 o maggiore, si può sempre migliorare la media semplice orientando lo zero, che è più o meno ciò che fa la regressione della cresta. Mi chiedo se forse il miglioramento è troppo leggero per essere osservato in questo caso? θ
Paul,

3
È ben noto infatti che cresta regressione è equivalente ad aggiungere supplementare "falsi" campioni nell'insieme di dati con ciascun campione avente valore in una caratteristica e zeri altrove, e tutte le risposte corrispondenti essendo zero. (È banale riscrivere la funzione di costo RR in questo modulo.) Ora mi chiedo se c'è un modo per aggiungere funzionalità extra (ad esempio puro rumore?) Che avrebbe un effetto simile. Ovviamente l'aggiunta di funzionalità extra significa che aumenterà la sua dimensionalità ma si possono solo guardare i suoi valori ai predittori "originali". @Paulpßλβ^
ameba dice

6

Così ho deciso di eseguire la validazione incrociata nidificata usando il mlrpacchetto specializzato in R per vedere cosa proviene effettivamente dall'approccio alla modellazione.

Codice (l'operazione richiede alcuni minuti su un normale notebook)

library(mlr)
daf = read.csv("https://pastebin.com/raw/p1cCCYBR", sep = " ", header = FALSE)

tsk = list(
  tsk1110 = makeRegrTask(id = "tsk1110", data = daf, target = colnames(daf)[1]),
  tsk500 = makeRegrTask(id = "tsk500", data = daf[, c(1,sample(ncol(daf)-1, 500)+1)], target = colnames(daf)[1]),
  tsk100 = makeRegrTask(id = "tsk100", data = daf[, c(1,sample(ncol(daf)-1, 100)+1)], target = colnames(daf)[1]),
  tsk50 = makeRegrTask(id = "tsk50", data = daf[, c(1,sample(ncol(daf)-1, 50)+1)], target = colnames(daf)[1]),
  tsk10 = makeRegrTask(id = "tsk10", data = daf[, c(1,sample(ncol(daf)-1, 10)+1)], target = colnames(daf)[1])
)

rdesc = makeResampleDesc("CV", iters = 10)
msrs = list(mse, rsq)
configureMlr(on.par.without.desc = "quiet")
bm3 = benchmark(learners = list(
    makeLearner("regr.cvglmnet", alpha = 0, lambda = c(0, exp(seq(-10, 10, length.out = 150))),
    makeLearner("regr.glmnet", alpha = 0, lambda = c(0, exp(seq(-10, 10, length.out = 150))), s = 151)
    ), tasks = tsk, resamplings = rdesc, measures = msrs)

risultati

getBMRAggrPerformances(bm3, as.df = TRUE)
#   task.id    learner.id mse.test.mean rsq.test.mean
#1    tsk10 regr.cvglmnet     1.0308055  -0.224534550
#2    tsk10   regr.glmnet     1.3685799  -0.669473387
#3   tsk100 regr.cvglmnet     0.7996823   0.031731316
#4   tsk100   regr.glmnet     1.3092522  -0.656879104
#5  tsk1110 regr.cvglmnet     0.8236786   0.009315037
#6  tsk1110   regr.glmnet     0.6866745   0.117540454
#7    tsk50 regr.cvglmnet     1.0348319  -0.188568886
#8    tsk50   regr.glmnet     2.5468091  -2.423461744
#9   tsk500 regr.cvglmnet     0.7210185   0.173851634
#10  tsk500   regr.glmnet     0.6171841   0.296530437

Fondamentalmente fanno lo stesso in tutte le attività.

Quindi, per quanto riguarda l'agnello ottimale?

sapply(lapply(getBMRModels(bm3, task.ids = "tsk1110")[[1]][[1]], "[[", 2), "[[", "lambda.min")
# [1] 4.539993e-05 4.539993e-05 2.442908e-01 1.398738e+00 4.539993e-05
# [6] 0.000000e+00 4.539993e-05 3.195187e-01 2.793841e-01 4.539993e-05

Notare che le lambda sono già trasformate. Alcune volte hanno persino scelto il minimo lambda .λ=0

Ho armeggiato un po 'di più con glmnete ho scoperto che non è stata scelta la minima lambda. Dai un'occhiata:

MODIFICARE:

Dopo i commenti di ameba, è diventato chiaro che il percorso di regolarizzazione è un passo importante nella glmnetstima, quindi il codice ora lo riflette. In questo modo, la maggior parte delle discrepanze è svanita.

cvfit = cv.glmnet(x = x, y = y, alpha = 0, lambda = exp(seq(-10, 10, length.out = 150)))
plot(cvfit)

inserisci qui la descrizione dell'immagine

Conclusione

Quindi, in sostanza, migliora davvero la misura ( modifica: ma non di molto! ).λ>0

Come è possibile e cosa dice del mio set di dati? Mi sto perdendo qualcosa di ovvio o è davvero controintuitivo?

Probabilmente siamo più vicini alla vera distribuzione dell'impostazione dei dati su un valore più piccolo di zero. Non c'è nulla di contro-intuitivo al riguardo però.λ

Modifica: tieni presente, tuttavia, che il percorso di regolarizzazione della cresta utilizza le stime dei parametri precedenti quando chiamiamo glmnet, ma questo va oltre la mia esperienza. Se impostiamo un lambdaisolamento molto basso , probabilmente peggioreranno le prestazioni.

EDIT: la selezione lambda dice qualcosa in più sui tuoi dati. Poiché lambda più grandi riducono le prestazioni, significa che ci sono coefficienti preferenziali, cioè più grandi, nel modello, poiché lambda grandi riducono tutti i coefficienti verso zero. Sebbene significhi che i gradi effettivi di libertà nel modello sono inferiori agli apparenti gradi di libertà, .pλ0p

Come può esserci una differenza qualitativa tra p = 100 e p = 1000 dato che entrambi sono maggiori di n?

p = 100p=1000 contiene invariabilmente almeno la stessa informazione o anche più di .p=100


Commenti

Sembra che tu stia ottenendo un minimo minimo per un lambda diverso da zero (sto guardando la tua figura), ma la curva è ancora davvero piatta alla sua sinistra. Quindi la mia domanda principale rimane sul perché λ → 0 non si adatta in modo evidente. Non vedo ancora una risposta qui. Ti aspetti che questo sia un fenomeno generale? Vale a dire per qualsiasi dato con n≪p, lambda = 0 funzionerà [quasi] buono come lambda ottimale? O è qualcosa di speciale in questi dati? Se guardi sopra nei commenti, vedrai che molte persone non mi hanno nemmeno creduto che sia possibile.

Penso che stai unendo le prestazioni di convalida con le prestazioni dei test e tale confronto non è garantito.

Modifica: nota però che quando impostiamo lambda0 dopo aver eseguito l'intero percorso di regolarizzazione, le prestazioni non peggiorano come tali, quindi il percorso di regolarizzazione è la chiave per capire cosa sta succedendo!

Inoltre, non capisco bene la tua ultima riga. Guarda l'output di cv.glmnet per p = 100. Avrà una forma molto diversa. Quindi cosa influenza questa forma (asintoto a sinistra vs. nessun asintoto) quando p = 100 o p = 1000?

Confrontiamo i percorsi di regolarizzazione per entrambi:

fit1000 = glmnet(x, y, alpha = 0, lambda = exp(seq(-10,10, length.out = 1001)))
fit100 = glmnet(x[, sample(1000, 100)], y, alpha = 0, lambda = exp(seq(-10,10, length.out = 1001)))
plot(fit1000, "lambda")

inserisci qui la descrizione dell'immagine

x11()
plot(fit100, "lambda")

inserisci qui la descrizione dell'immagine

p=1000λp=100

p=1000


λ0np

Inoltre, non capisco bene la tua ultima riga. Guarda l' cv.glmnetoutput per p = 100. Avrà una forma molto diversa. Quindi cosa influenza questa forma (asintoto a sinistra vs. nessun asintoto) quando p = 100 o p = 1000?
ameba dice di reintegrare Monica il

Sai se mlrseleziona lambda.mino lambda.1se(nella cv.glmnetterminologia)?
ameba dice di reintegrare Monica il

@amoeba lambda.min. C'è anche uno regr.cvglmnetstudente, che probabilmente consente di selezionare altre regole.
Firebug,

Grazie. Ad essere sincero, non capisco l'output del tuo benchmark 1e-100. Ad esempio per p = 1100 dà MSE = 1.45. Ma qui non c'è sintonia dell'iperparametro nel loop interno, quindi sostanzialmente non è necessario alcun loop CV interno. Ciò significa che il risultato dovrebbe essere lo stesso del CV non nidificato su lambda = 1e-100. Ma vediamo nella prima cifra che il MSE è di circa 0,7. Non ha senso per me.
ameba dice di reintegrare Monica il

5

In che modo OLS (norma minima) non riesce a sopravvivere?

In breve:

I parametri sperimentali correlati ai parametri (sconosciuti) nel modello reale avranno maggiori probabilità di essere stimati con valori elevati in una procedura di adattamento OLS a norma minima. Questo perché si adatteranno al "modello + rumore" mentre gli altri parametri si adatteranno solo al "rumore" (quindi si adatteranno a una parte più grande del modello con un valore inferiore del coefficiente e avranno più probabilità di avere un valore elevato nella norma minima OLS).

Questo effetto ridurrà la quantità di overfitting in una procedura di adattamento OLS di norma minima. L'effetto è più pronunciato se sono disponibili più parametri da allora diventa più probabile che una parte più ampia del "modello reale" venga incorporata nella stima.

Parte più lunga:
(Non sono sicuro di cosa collocare qui poiché il problema non mi è del tutto chiaro, o non so di quale precisione una risposta abbia bisogno per rispondere alla domanda)

Di seguito è riportato un esempio che può essere facilmente costruito e dimostra il problema. L'effetto non è così strano e gli esempi sono facili da fare.

  • p=200
  • n=50
    • tm=10
    • i coefficienti del modello sono determinati casualmente

In questo caso di esempio osserviamo che c'è un eccesso di adattamento ma i coefficienti dei parametri che appartengono al modello vero hanno un valore più alto. Pertanto R ^ 2 può avere un valore positivo.

L'immagine seguente (e il codice per generarlo) dimostrano che il sovradimensionamento è limitato. I punti relativi al modello di stima di 200 parametri. I punti rossi si riferiscono a quei parametri che sono presenti anche nel "modello reale" e vediamo che hanno un valore più alto. Quindi, c'è un certo grado di approccio al modello reale e di ottenere R ^ 2 sopra 0.

  • Si noti che ho usato un modello con variabili ortogonali (le funzioni sinusoidali). Se i parametri sono correlati, possono verificarsi nel modello con coefficiente relativamente molto elevato e diventare più penalizzati nella norma minima OLS.
  • sin(ax)sin(bx)xxnp

esempio di ridimensionamento eccessivo

library(MASS)

par(mar=c(5.1, 4.1, 9.1, 4.1), xpd=TRUE)

p <- 200       
l <- 24000
n <- 50
tm <- 10

# generate i sinus vectors as possible parameters
t <- c(1:l)
xm <- sapply(c(0:(p-1)), FUN = function(x) sin(x*t/l*2*pi))

# generate random model by selecting only tm parameters
sel <- sample(1:p, tm)
coef <- rnorm(tm, 2, 0.5)

# generate random data xv and yv with n samples
xv <- sample(t, n)
yv <- xm[xv, sel] %*% coef + rnorm(n, 0, 0.1)

# generate model
M <- ginv(t(xm[xv,]) %*% xm[xv,])

Bsol <- M %*% t(xm[xv,]) %*% yv
ysol <- xm[xv,] %*% Bsol

# plotting comparision of model with true model
plot(1:p, Bsol, ylim=c(min(Bsol,coef),max(Bsol,coef)))
points(sel, Bsol[sel], col=1, bg=2, pch=21)
points(sel,coef,pch=3,col=2)

title("comparing overfitted model (circles) with true model (crosses)",line=5)
legend(0,max(coef,Bsol)+0.55,c("all 100 estimated coefficients","the 10 estimated coefficients corresponding to true model","true coefficient values"),pch=c(21,21,3),pt.bg=c(0,2,0),col=c(1,1,2))

Tecnica beta troncata in relazione alla regressione della cresta

l2β

  • Sembra che il modello di rumore troncato faccia lo stesso (calcola solo un po 'più lentamente e forse un po' più spesso meno bene).
  • Tuttavia, senza il troncamento, l'effetto è molto meno forte.
  • Questa corrispondenza tra l'aggiunta di parametri e la penalità della cresta non è necessariamente il meccanismo più forte dietro l'assenza di un eccesso di adattamento. Questo può essere visto specialmente nella curva a 1000p (nell'immagine della domanda) andando quasi a 0,3 mentre le altre curve, con p diversa, non raggiungono questo livello, indipendentemente dal parametro di regressione della cresta. I parametri aggiuntivi, in quel caso pratico, non sono gli stessi di uno spostamento del parametro ridge (e immagino che ciò sia dovuto al fatto che i parametri extra creeranno un modello migliore, più completo).

  • I parametri del rumore riducono la norma da un lato (proprio come la regressione della cresta) ma introducono anche rumore aggiuntivo. Benoit Sanchez mostra che nel limite, aggiungendo molti parametri di rumore con una deviazione minore, alla fine diventerà lo stesso della regressione della cresta (il numero crescente di parametri di rumore si annullano a vicenda). Allo stesso tempo, richiede molti più calcoli (se aumentiamo la deviazione del rumore, per consentire di utilizzare meno parametri e accelerare il calcolo, la differenza diventa più grande).

Rho = 0,2 confrontando il rumore troncato con la regressione della cresta

Rho = 0.4 confrontando il rumore troncato con la regressione della cresta

Rho = 0,2 aumentando la varianza dei parametri di rumore a 2 confrontando il rumore troncato con la regressione della cresta

esempio di codice

# prepare the data
set.seed(42)
n = 80
p = 40
rho = .2
y = rnorm(n,0,1)
X = matrix(rep(y,p), ncol = p)*rho + rnorm(n*p,0,1)*(1-rho^2)

# range of variables to add
ps = c(0, 5, 10, 15, 20, 40, 45, 50, 55, 60, 70, 80, 100, 125, 150, 175, 200, 300, 400, 500, 1000)
#ps = c(0, 5, 10, 15, 20, 40, 60, 80, 100, 150, 200, 300) #,500,1000)

# variables to store output (the sse)
error   = matrix(0,nrow=n, ncol=length(ps))
error_t = matrix(0,nrow=n, ncol=length(ps))
error_s = matrix(0,nrow=n, ncol=length(ps))

# adding a progression bar
pb <- txtProgressBar(min = 0, max = n, style = 3)

# training set by leaving out measurement 1, repeat n times 
for (fold in 1:n) {
    indtrain = c(1:n)[-fold]

    # ridge regression
    beta_s <- glmnet(X[indtrain,],y[indtrain],alpha=0,lambda = 10^c(seq(-4,2,by=0.01)))$beta
    # calculate l2-norm to compare with adding variables
    l2_bs <- colSums(beta_s^2)

    for (pi in 1:length(ps)) {
        XX = cbind(X, matrix(rnorm(n*ps[pi],0,1), nrow=80))
        XXt = XX[indtrain,]

        if (p+ps[pi] < n) {
            beta = solve(t(XXt) %*% (XXt)) %*% t(XXt) %*% y[indtrain]
        }
        else {
            beta = ginv(t(XXt) %*% (XXt)) %*% t(XXt) %*% y[indtrain]
        }

        # pickout comparable ridge regression with the same l2 norm      
        l2_b <- sum(beta[1:p]^2)
        beta_shrink <- beta_s[,which.min((l2_b-l2_bs)^2)] 

        # compute errors
        error[fold, pi] = y[fold] - XX[fold,1:p] %*% beta[1:p]
        error_t[fold, pi] = y[fold] - XX[fold,] %*% beta[]
        error_s[fold, pi] = y[fold] - XX[fold,1:p] %*% beta_shrink[]
    }
    setTxtProgressBar(pb, fold) # update progression bar
}

# plotting
plot(ps,colSums(error^2)/sum(y^2) , 
     ylim = c(0,2),
     xlab ="Number of extra predictors",
     ylab ="relative sum of squared error")
lines(ps,colSums(error^2)/sum(y^2))
points(ps,colSums(error_t^2)/sum(y^2),col=2)
lines(ps,colSums(error_t^2)/sum(y^2),col=2)
points(ps,colSums(error_s^2)/sum(y^2),col=4)
lines(ps,colSums(error_s^2)/sum(y^2),col=4)

title('Extra pure noise predictors')

legend(200,2,c("complete model with p + extra predictors",
               "truncated model with p + extra predictors",
               "ridge regression with similar l2-norm",
               "idealized model uniform beta with 1/p/rho"),
       pch=c(1,1,1,NA), col=c(2,1,4,1),lt=c(1,1,1,2))

# idealized model (if we put all beta to 1/rho/p we should theoretically have a reasonable good model)
error_op <- rep(0,n)
for (fold in 1:n) {
  beta = rep(1/rho/p,p)
    error_op[fold] = y[fold] - X[fold,] %*% beta
}
id <- sum(error_op^2)/sum(y^2)
lines(range(ps),rep(id,2),lty=2)

1
(+1) Grazie. Penso che l'argomento intuitivo all'inizio della tua risposta abbia un senso.
ameba dice di reintegrare Monica il

1

np

Ax=gδ,
Agδ

Ovviamente, questo è un problema inverso mal posto. Quindi, puoi risolverlo con SVD o Moore-Penrose inverso, il che renderebbe la soluzione con la minima norma. Così dovrebbe non essere sorprendente che la soluzione norma almeno non sta venendo a mancare a titolo definitivo.

Tuttavia, se segui il documento puoi vedere che la regressione della cresta sarebbe un miglioramento rispetto a quanto sopra. Il miglioramento è davvero un comportamento migliore dello stimatore, poiché la soluzione di Moore-Penrose non è necessariamente limitata.

AGGIORNARE

Mi sono reso conto che non stavo chiarendo che problemi sbagliati portano a un eccesso di adattamento. Ecco la citazione dall'articolo Gábor A, Banga JR. Stima dei parametri robusta ed efficiente in modelli dinamici di sistemi biologici . BMC Systems Biology. 2015; 9: 74. doi: 10,1186 / s12918-015-0219-2:

Il mal condizionamento di questi problemi insorge tipicamente da (i) modelli con un gran numero di parametri (sovramparametrizzazione), (ii) scarsità di dati sperimentali e (iii) errori di misurazione significativi [19, 40]. Di conseguenza, spesso otteniamo un overfitting di tali modelli cinetici, ovvero modelli calibrati con adattamenti ragionevoli ai dati disponibili ma scarsa capacità di generalizzazione (basso valore predittivo)

Quindi, il mio argomento può essere affermato come segue:

  • problemi di cattiva qualità comportano un eccesso di adattamento
  • (n <p) case è un problema inverso estremamente mal posto
  • X+ , risolve un problema mal posto
  • pertanto, si occupa di sovralimentare almeno in una certa misura e non dovrebbe sorprendere che non fallisca completamente, a differenza di un normale OLS dovrebbe

Ancora una volta, la regolarizzazione è ancora una soluzione più solida.


1
(+1) Grazie, ma non vedo bene come questo documento sia rilevante. Lo guarderò domani in modo più dettagliato. Dove dicono esattamente che la soluzione OLS a norma minima non si adatta troppo o che il requisito di norma minima può essere visto come una regolarizzazione?
ameba dice di reintegrare Monica il

1
Discutiamo quando leggi il documento. Non dicono che lo psudo inverso sia regolarizzazione. Quello che dicono è che è la soluzione al problema mal posto. Quello che sto dicendo è che il sovrautilizzo è dovuto alla cattiva posizione del problema, quindi rivolgendoti a quest'ultimo ti prendi cura del primo anche se non con regolarizzazione.
Aksakal,

1
Penso che la cosa sconcertante non sia che la soluzione della norma minima non migliora in qualche misura il sovra-adattamento, ma che l'aggiunta di più regolarizzazione non migliora ulteriormente le cose. Anche perché la soluzione di norma minima è più efficace quando il numero di funzionalità aumenta. La mia intuizione è che i problemi con più parametri necessitano di più regolarizzazione (a parità di condizioni) piuttosto che di meno. Questo è un problema davvero interessante e può aiutare a spiegare perché, ad esempio, anche le reti neurali non regolamentate non si adattano troppo a quanto ci si potrebbe aspettare.
Dikran Marsupial,

1
@Dikran In realtà altre forme o regolarizzazioni possono ancora migliorare le prestazioni: ad esempio, posso migliorare le prestazioni (rispetto alla OLS di minima norma) con regressione dei componenti principali o con rete elastica. È solo che la regolarizzazione della cresta diventa inutile. L'analogia con le reti neurali è un pensiero affascinante che non mi è passato per la testa. Quello che ho fatto pensare di recente, però, è che non c'è da stupirsi nessuno capisce il motivo per cui le cose difficili di apprendimento profonde come la normalizzazione lotti davvero lavoro, dato che anche cresta regressione lineare da Statistics 101 può essere così sconcertante :-)
ameba dice Ripristinare Monica

2
βn<<prmsols
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.