J'ai récemment effectué des travaux dans lesquels j'ai examiné le comportement de lda de manière assez détaillée, et j'ai découvert que pour les observations proches de la frontière de décision, predict.lda renvoie des classes non déterministes. Au départ, je pensais que cela pouvait être un problème de précision numérique, mais les données projetées semblent être de l'ordre de 1e-6 à partir de la limite de décision, ce qui est bien au-dessus de la double précision .... J'ai écrit un minimum (ish) exemple, voir ci-dessous :

# Fit an LDA model to a subset of Fisher's Iris data
x = as.matrix(iris[iris$Species != 'setosa', 1:4])
y = as.factor(as.character(iris[iris$Species != 'setosa', 'Species']))
m = MASS::lda(x, y)

# Generate data near the decision boundary
d = m$scaling
ord = order(x %*% d)
y.pred = MASS:::predict.lda(m, newdata = x)$class
ind = min(which(y.pred[ord] == 'virginica'))
# Interpolate between the two data points on either side of the decision boundary
s = seq(0, 1, length.out = 100001)
s = s[47479:47484] # Zoom on the decision boundary
x.test = (as.matrix(s) %*% t(x[ord[ind - 1], ])) + (as.matrix(1 - s) %*% t(x[ord[ind], ]))

# running predict.lda() on x.test seems to generate non-deterministic results.
# set.seed(123) # set.seed here seems to remove the non-determinism.
for (i in 1:10) {
  y.pred = MASS:::predict.lda(m, newdata = x.test)$class
  print(as.character(y.pred))
}

Et au cas où cela ferait une différence, voici la sortie sessionInfo :

> sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1

locale:
 [1] LC_CTYPE=en_AU.UTF-8       LC_NUMERIC=C               LC_TIME=en_AU.UTF-8        LC_COLLATE=en_AU.UTF-8     LC_MONETARY=en_AU.UTF-8   
 [6] LC_MESSAGES=en_AU.UTF-8    LC_PAPER=en_AU.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_AU.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] MASS_7.3-51.4  compiler_3.6.1 tools_3.6.1   
r
0
Lyron 19 nov. 2019 à 09:19

1 réponse

Meilleure réponse

La méthode predict recherche des liens et utilise une sélection aléatoire pour les rompre. C'est pourquoi la définition de la graine aléatoire la rend déterministe.

Pour trouver d'où vient le hasard, j'ai édité une copie de MASS:::predict.lda pour ajouter des lignes comme celle-ci :

cat("after cl:"); print(rnorm(1)); set.seed(123); print(rnorm(1)); set.seed(123)

Si le générateur de nombres aléatoires est utilisé après cela, la valeur suivante de rnorm(1) sera différente de celle qui suit directement après l'appel set.seed(123).

Voici une partie de la source modifiée de predict.lda qui illustre le problème :

posterior <- dist/drop(dist %*% rep(1, ng))
cat("after posterior:"); print(rnorm(1)); set.seed(123); print(rnorm(1)); set.seed(123)

nm <- names(object$prior)
cl <- factor(nm[max.col(posterior)], levels = object$lev)
cat("after cl:"); print(rnorm(1)); set.seed(123); print(rnorm(1)); set.seed(123)

Si vous exécutez cette version, votre boucle imprimera du texte comme celui-ci à plusieurs reprises :

after posterior:[1] -0.5604756
[1] -0.5604756
after cl:[1] 1.558708
[1] -0.5604756
[1] "virginica"  "virginica"  "versicolor" "virginica" 
[5] "versicolor" "versicolor"

Et puis si vous regardez l'aide pour max.col, utilisée dans le calcul cl, vous pouvez voir

Lorsque ties.method = "random", par défaut, les égalités sont rompues au hasard. Dans ce cas, la détermination d'une égalité suppose que les entrées sont des probabilités : il existe une tolérance relative de 1e-5, par rapport à la plus grande entrée (en amplitude, en omettant l'infini) de la ligne.

0
user2554330 19 nov. 2019 à 11:24