MDS non métrique avec R

En Français : échelles multidimensionnelles, positionnement multidimensionnel

Source : Borg, I., Groenen, P., Modern Multidimensional Scaling : Theory and Applications, Second Edition, Springer, 2005.

Principe de la méthode :

On désigne sous le terme de MDS (multidimensional scaling), un ensemble de techniques permettant de représenter les données d'une matrice de proximités entre objets à l'aide de modèles de distances spatiales.

Cette méthode est fondée sur les travaux de Shepard et Kruskal.

Principe mathématique :

Les données sont constituées par une matrice de proximités (pij) entre n objets. Ces proximités sont soit des similarités (score élevé entre deux objets très semblables) soit des dissimilarités (score faible sur des objets très semblables). Nous supposerons dans la suite qu'il s'agit ici de dissimilarités.

On cherche une transformation monotone f(pij) sur les proximités et un système X de n points dans un espace de dimension m choisie a priori, de façon à minimiser le stress brut :

Stress =somme((f(pij)-dij)^2)

où les dij représentent les distances euclidiennes entre les points de X et la somme étendue à tous les couples i, j tels que i < j.

N.B. Des pondérations wij, dichotomiques (0 ou 1) sont parfois ajoutées dans cette formule pour tenir compte des valeurs manquantes.

Dans le MDS non métrique, on cherche à préserver l'ordre des proximités et non leurs valeurs absolues ou relatives. Autrement dit, le but est de représenter les distances entre les objets, en respectant l'ordre entre les proximités plutôt que leurs valeurs exactes. A partir des proximités pij, on détermine donc des disparités f(pij), vérifiant une règle de monotonie : si p1 < p2 alors f(p1) <= f(p2).

N.B. Contrairement à ce que les notations pourraient laisser penser, f(pij) n'est pas une fonction de p, mais une fonction de (i, j) : à deux proximités égales, mais provenant d'objets différents, peuvent correspondre des disparités différentes.

On détermine ensuite les coordonnées des points représentatifs dans l'espace image et les distances dij entre ces points, selon une méthode proche de celle utilisée en MDS métrique.

A la suite de cette étape, de nouvelles disparités sont calculées et une nouvelle solution est recherchée dans l'espace image.

On peut donc décrire très brièvement l'algorithme de la manière suivante :

  1. On part d'une configuration initiale X0 de la solution
  2. On recherche des disparités "optimales" f(pij) ou d-hat(i, j)
  3. On recherche une solution dij(X) minimisant le stress brut, calculé entre les disparités et les distances entre les points de X
  4. On recherche de nouvelles valeurs pour les disparités f(pij)=d-hat(i, j)
  5. Si la condition d'arrêt n'est pas respectée, on retourne au (3).

Calcul des disparités

Les disparités peuvent être calculées par régression monotone (Kruskal, 1964) :

Une autre méthode a été proposée par Lingoes et De Leeuw (programme MINISSA) : les rank-images ou images des rangs ou permutaton de l'image du rang (terme utilisé dans l'aide de Statistica). Dans ce cas, à partir d'une solution dij(X), on effectue une permutation entre ces points de manière que les dij(X) et les proximités pij de départ soient classées dans le même ordre.

Mais l'algorithme ainsi obtenu n'est pas nécessairement convergent et d'autres algorithmes, combinant la régression monotone et les rank-images ont été proposés. Guttman, par exemple, distingue les d-hat (obtenus par régression monotone) et les d-star (obtenus par rank-images). C'est un algorithme de ce type qui est implémenté par exemple, dans Statistica. L'aide du logiciel indique : "Les valeurs ajustées sont calculées grâce à la procédure de permutation de l'image du rang (...). Après chaque itération (..) le programme va réaliser jusqu'à cinq intérations utilisant la procédure de transformation monotone de régression."

On peut noter que la contrainte de monotonie n'indique pas de méthode particulière pour gérer les ex aequo. Plusieurs méthodes (primary approach, secondary approach, etc) ont été proposées.

Fonction de perte - critère de qualité de la solution

On évalue la qualité de la solution trouvée à l'aide du stress (plus exactement, stress-1, car plusieurs versions de cette fonction existent dans la littérature) :

STRESS = (( somme(f(pij) - dij)^2)/somme(dij^2))^0.5

Selon Kruskal, la qualité de l'ajustement (GOF : goodness of fit) peut être évaluée de la la façon suivante :

Un autre coefficient utile est le coefficient d'aliénation qui, lui, fait intervenir les proximités de départ :

K= Racine(1 - (Somme(dij*pij)^2)/(Somme(pij^2))

Une représentation graphique utile est le diagramme de Shepard, construit en plaçant les proximités pij en abscisses, les disparités d-hat(i, j)=f(pij) et les distances dij en ordonnées et en joignant les points (pij, d-hat(i,j)) par une "ligne de régression".

Exemple 1 :

Enoncé :

Source : WICKELMAIER Florian, An Introduction to MDS, Sound Quality Research Unit, Aalborg University, Denmark

On demande à des sujets d'évaluer la similitude entre 12 sons de l'environnement courant.
Les données se présentent sous la forme suivante :


Sound
cs
dd
fa
ho
hw
sh
st
sw
tw
tg
wa
wf
circular-saw
cs
0
1
4
5
3
4
2
8
8
5
7
1
dentist-s-drill
dd
1
0
3
8
2
6
2
7
8
8
7
2
fan
fa
4
3
0
7
2
3
3
7
8
6
4
3
hooves
ho
5
8
7
0
8
9
3
8
2
2
9
5
howling-wind
hw
3
2
2
8
0
6
4
8
9
6
4
2
ship-s-horn
sh
4
6
3
9
6
0
1
3
9
8
5
3
stadium
st
2
2
3
3
4
1
0
4
3
6
7
1
stone-in-well
sw
8
7
7
8
8
3
4
0
9
6
9
5
typewriter
tw
8
8
8
2
9
9
3
9
0
4
9
9
tire-on-gravel
tg
5
8
6
2
6
8
6
6
4
0
4
3
wasp
wa
7
7
4
9
4
5
7
9
9
4
0
6
waterfall
wf
1
2
3
5
2
3
1
5
9
3
6
0

Ces données sont enregistrées au format .csv d'Excel dans le fichier Sounds.csv avec la structure indiquée ci-dessus.

On peut les charger dans R à l'aide de la commande :

> proxim <- read.csv2("Sounds.csv")

N.B. read.csv2 permet de lire des données au format "table", avec les spécifications par défaut suivantes : séparateur = ";", séparateur décimal = ",".

Calcul des coordonnées de la représentation

On se limite aux données numériques :

> prox <- proxim[,3:14]

On utilise la commande isoMDS, qui se trouve dans le package MASS pour obtenir les coordonnées de la solution et le stress associé :

> library(MASS)

> prox.mds <- isoMDS(prox,cmdscale(prox))
initial value 19.391177
iter 5 value 15.912188
iter 10 value 15.596547
final value 15.560651
converged

N.B. Dans la plupart des cas, isoMDS exige une valeur initale, qui peut être celle fournie par cmdscale (le MDS métrique).

> prox.mds$points
[,1] [,2]
cs 0.20163920 -0.15873153
dd -0.76991164 -0.57955403
fa -3.02696501 -0.21941437
ho 4.51063809 -0.02440789
hw -3.05068357 -2.04720081
sh -3.11119700 2.97728343
st 0.08889741 1.45550769
sw -0.59949642 5.55410022
tw 6.21209030 0.22113765
tg 2.94117084 -2.55909595
wa -1.74966163 -5.10156742
wf -1.64652057 0.48194302
> prox.mds$stress
[1] 15.56065

Représentation graphique

> X <- prox.mds$points[,1]
> Y <- prox.mds$points[,2]
> plot(prox.mds$points, pch=".")
> text(X,Y,proxim[,2],pos=1,cex=0.8)

Résultat obtenu :

Diagramme de Shepard

La fonction Shepard semble être assez exigeante sur la forme des paramètres qui lui sont indiqués.

On peut, par exemple, placer les données dans un "vrai" data.frame :

> prox.df <- data.frame(proxim[2:14],row.names = 1)
> prox.df
cs dd fa ho hw sh st sw tw tg wa wf
cs 0 1 4 5 3 4 2 8 8 5 7 1
dd 1 0 3 8 2 6 2 7 8 8 7 2
fa 4 3 0 7 2 3 3 7 8 6 4 3
ho 5 8 7 0 8 9 3 8 2 2 9 5
hw 3 2 2 8 0 6 4 8 9 6 4 2
sh 4 6 3 9 6 0 1 3 9 8 5 3
st 2 2 3 3 4 1 0 4 3 6 7 1
sw 8 7 7 8 8 3 4 0 9 6 9 5
tw 8 8 8 2 9 9 3 9 0 4 9 9
tg 5 8 6 2 6 8 6 6 4 0 4 3
wa 7 7 4 9 4 5 7 9 9 4 0 6
wf 1 2 3 5 2 3 1 5 9 3 6 0

On recalcule alors le positionnement multidimensionnel :

> prox.mds <- isoMDS(prox.df,cmdscale(prox.df))
initial value 19.391177
iter 5 value 15.912188
iter 10 value 15.596547
final value 15.560651
converged

Et, le premier paramètre de Shepard() doit être un objet de type dist, et non une simple matrice symétrique :

> Shepard(as.dist(prox.df),prox.mds$points)
$x
[1] 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 6 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9

$y
[1] 1.058774 1.956057 3.543502 1.989850 1.618171 2.712178 2.208852 1.376670 1.827940 1.719079 2.981253 2.892791 3.760840
[14] 2.285605 3.197807 3.537508 1.548396 4.662825 3.598420 2.893441 6.246372 5.504074 3.229174 4.561740 5.046476 4.703821
[27] 3.319912 4.156001 4.292856 5.335548 4.311092 3.642360 6.177944 8.192778 5.179096 4.258252 6.410363 5.024849 6.013681
[40] 4.924683 8.852134 5.584463 5.314057 6.136021 4.626934 7.540125 6.263072 6.809958 5.768732 6.022443 5.309651 7.027763
[53] 4.206034 9.249553 7.827214 7.565265 7.986745 8.202600 8.191613 8.060329 9.536474 9.722141 8.650908 10.717562 9.577092
[66] 7.862937

$yf
[1] 1.058774 1.956057 2.124530 2.124530 2.124530 2.124530 2.124530 2.124530 2.124530 2.124530 2.886314 2.886314 2.886314 2.886314 2.886314
[16] 2.886314 2.886314 3.718229 3.718229 3.718229 4.529119 4.529119 4.529119 4.529119 4.529119 4.529119 4.529119 4.529119 4.529119 4.529119
[31] 4.529119 4.529119 5.772706 5.772706 5.772706 5.772706 5.772706 5.772706 5.772706 5.772706 6.102722 6.102722 6.102722 6.102722 6.102722
[46] 6.118472 6.118472 6.118472 6.118472 6.118472 6.118472 6.118472 6.118472 8.154760 8.154760 8.154760 8.154760 8.154760 8.154760 8.154760
[61] 9.303174 9.303174 9.303174 9.385864 9.385864 9.385864

Représentation graphique du diagramme de Shepard :

> prox.sh <- Shepard(as.dist(prox.df),prox.mds$points)
> plot(prox.sh,pch="*")
> lines(prox.sh$x,prox.sh$yf,type="S")

Ce qui donne finalement :

L'algorithme de Sammon

Il s'agit d'une autre méthode de positionnement mutidimensionnel non métrique proposée par Sammon.

> sammon(prox.df)
Initial stress : 0.11654
stress after 10 iters: 0.06097, magic = 0.461
stress after 20 iters: 0.05904, magic = 0.500
stress after 30 iters: 0.05895, magic = 0.500
$points
[,1] [,2]
cs -0.8525798 -0.73382691
dd -2.0209380 -0.60379506
fa -3.5149765 -0.29830898
ho 4.3006891 -0.04742348
hw -2.7829840 -2.10319036
sh -1.5191353 2.53727622
st -0.1648869 1.28457871
sw -0.5124628 5.41515169
tw 5.3700226 1.45084191
tg 3.1379383 -1.87976686
wa -0.8867966 -5.06842641
wf -0.5538901 0.04688954

$stress
[1] 0.05895335

$call
sammon(d = prox.df)

> prox.sam <- sammon(prox.df)
> X <- prox.sam$points[,1]
> Y <- prox.sam$points[,2]
> plot(prox.sam$points,pch=".")
> text(X,Y,proxim[,2],pos=1,cex=0.8)

La représentation graphique est alors la suivante :

On peut, comme précédemment, construire un diagramme de Shepard :

> prox.sh2 <- Shepard(as.dist(prox.df),prox.sam$points)
> plot(prox.sh2,pch="*")
> lines(prox.sh2$x,prox.sh2$yf,type="S")

Ce qui donne :