2025-04-04
In psicologia e neuroscienze alcuni esperimenti includono delle variabili che possono variare tra soggetti, nonostante siano manipolate sperimentalmente.
Ad esempio, in psicofisica gli stimoli vengono spesso adattati ai soggetti e quindi non tutti i soggetti sono sottoposti allo stesso tipo di stimolazione.
Ipotizziamo che siamo interessati a capire la sensibilità al contrasto (visibilità rispetto allo sfondo) di un gruppo di soggetti. A livello individuale possiamo ipotizzare che la relazione vera di due soggetti sia ad esempio:
Solitamente siamo interessati a stimare la soglia percettiva ed eventualmente la slope. La soglia percettiva è il livello di \(x\) (contrasto) necessario a ad avere una certa percentuale di visibilità (e.g., 50%).
Gli esperimenti possono essere tarati per adattare lo stimolo (contrasto) alle risposte permettendo di focalizzare i trial sulla parte della curva di interesse. Se proviamo a simulare due ipotetici esperimenti:
Ora carichiamo un dataset con un esperimento di questo tipo.
id trial x01 visibility
1 1 1 0.2069943 0
2 2 1 0.6339033 1
3 3 1 0.7137630 0
4 4 1 0.6853990 0
5 5 1 0.2117152 0
6 6 1 0.2450111 0
Possiamo anche vedere i pattern individuali:
Fittiamo i nostri modelli per soggetto e vediamo il pattern di parametri:
Perfetto, ora fittiamo il nostro modello:
library(lme4)
library(lmerTest)
<- glmer(visibility ~ x01 + (x01||id), data = dat, family = binomial(link = "logit"))
fit summary(fit)
Generalized linear mixed model fit by maximum likelihood (Laplace
Approximation) [glmerMod]
Family: binomial ( logit )
Formula: visibility ~ x01 + (x01 || id)
Data: dat
AIC BIC logLik -2*log(L) df.resid
7387.3 7416.2 -3689.7 7379.3 9996
Scaled residuals:
Min 1Q Median 3Q Max
-1.2114 -0.4091 -0.3261 -0.2499 8.6903
Random effects:
Groups Name Variance Std.Dev.
id (Intercept) 2.217 1.489
id.1 x01 1.896 1.377
Number of obs: 10000, groups: id, 100
Fixed effects:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -6.342 1.013 -6.258 3.91e-10 ***
x01 8.738 2.017 4.333 1.47e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
x01 -0.984
library(ggeffects)
plot(ggeffect(fit))
L’effetto fisso stimato dal modello è 8.74. Al netto dello shrinkage, questo è decisamente inferiore rispetto alla media delle slope stimate sui singoli soggetti. Quale potrebbe essere il motivo?
Il problema principale è che abbiamo un effetto del cluster (soggetti) sulla nostra variabile \(x\) (vi dice qualcosa il Simpson’s paradox?). Ogni soggetto ha il suo esperimento con un incremento chiaro (e consistente) della visibilità in funzione del contrasto MA i livelli di contrasto di ogni soggetto sono diversi uno dall’altro.
Quindi in realtà non stiamo stimando esattamente quello che vorremmo, ovvero l’effetto medio (e la sua variabilità) del contrasto in ogni soggetto. Idealmente dovremmo calcolarlo su ogni soggetto e poi fare la media.
Per fare questo è necessario trasformare la \(x\), centrando i valori di contrasto sulla media di ogni soggetto.
<- function(x, cluster){
cmc - cm(x, cluster)
x
}<- function(x, cluster){
cm <- tapply(x, cluster, mean)
cmm <- tapply(x, cluster, length)
cmn as.character(cluster)]
cmm[ }
$x01_cmc <- cmc(dat_ex$x01, dat_ex$id)
dat_ex<- glmer(visibility ~ x01_cmc + (x01_cmc||id), data = dat_ex, family = binomial(link = "logit"))
fit_cmc summary(fit_cmc)
Generalized linear mixed model fit by maximum likelihood (Laplace
Approximation) [glmerMod]
Family: binomial ( logit )
Formula: visibility ~ x01_cmc + (x01_cmc || id)
Data: dat_ex
AIC BIC logLik -2*log(L) df.resid
7081.7 7110.5 -3536.8 7073.7 9996
Scaled residuals:
Min 1Q Median 3Q Max
-1.5490 -0.4042 -0.3101 -0.2293 6.2565
Random effects:
Groups Name Variance Std.Dev.
id (Intercept) 0.2294 0.4789
id.1 x01_cmc 7.6120 2.7590
Number of obs: 10000, groups: id, 100
Fixed effects:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -2.15515 0.05998 -35.93 <2e-16 ***
x01_cmc 18.17924 1.03817 17.51 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
x01_cmc -0.224
Se erroneamente (qualche volta viene fatto), decidiamo di aggregare i dati a livello del soggetto. Possiamo nel migliore dei casi attenuare o distorcere la stima oppure stimare un pattern anche opposto.
<- dat_ex |>
dat_agg group_by(id) |>
summarise(p = mean(visibility),
n = n(),
x01 = mean(x01))
head(dat_agg)
# A tibble: 6 × 4
id p n x01
<int> <dbl> <int> <dbl>
1 1 0.11 100 0.171
2 2 0.08 100 0.623
3 3 0.12 100 0.680
4 4 0.21 100 0.679
5 5 0.02 100 0.180
6 6 0.17 100 0.264
<- glmer(p ~ x01 + (1|id), data = dat_agg, weights = n, family = binomial(link = "logit"))
fit_agg summary(fit_agg)
Generalized linear mixed model fit by maximum likelihood (Laplace
Approximation) [glmerMod]
Family: binomial ( logit )
Formula: p ~ x01 + (1 | id)
Data: dat_agg
Weights: n
AIC BIC logLik -2*log(L) df.resid
633.0 640.8 -313.5 627.0 97
Scaled residuals:
Min 1Q Median 3Q Max
-1.62242 -0.44308 0.02905 0.35862 1.33912
Random effects:
Groups Name Variance Std.Dev.
id (Intercept) 0.2064 0.4543
Number of obs: 100, groups: id, 100
Fixed effects:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -1.9989 0.1605 -12.455 <2e-16 ***
x01 -0.0477 0.3052 -0.156 0.876
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
x01 -0.938