Chapter on SVD for correspondence analysis nearly done

This commit is contained in:
Pierre-Edouard Portier 2022-12-30 15:47:58 +01:00
parent 652301c761
commit 6138583917
4 changed files with 370 additions and 56 deletions

View File

@ -2,39 +2,103 @@
```{r}
set.seed(1123)
source('05_c_svd_ca_code.R')
```
## Profils lignes et profils colonnes
Soit une matrice de données $\mathbf{N} \in \mathbb{R}^{I \times J}$. Elle peut par exemple représenter $I$ individus décrits par $J$ variables ($n_{i,j}$ est alors la valeur, considérée ici positive, de la variable $j$ pour l'individu $i$), ou le croisement d'une première variable avec $I$ modalités et d'une seconde variable avec $J$ modalités (par exemple, couleurs des yeux et couleurs des cheveux d'un groupe de personnes, alors $n_{i,j}$ peut être le décompte du nombre de personnes ayant des yeux de la $i$-ème couleur et des cheveux de la $j$-ème couleur). Notons :
Soit une matrice de données $\mathbf{N} \in \mathbb{R}^{I \times J}$. Elle peut représenter $I$ individus décrits par $J$ variables ($n_{i,j}$ est alors la valeur (qui doit être positive pour que les analyses à venir fassent sens) de la variable $j$ pour l'individu $i$) ou le croisement d'une première variable avec $I$ modalités et d'une seconde variable avec $J$ modalités (par exemple, couleurs des yeux et couleurs des cheveux d'un groupe de personnes, alors $n_{i,j}$ est le décompte du nombre de personnes ayant des yeux de la $i$-ème couleur et des cheveux de la $j$-ème couleur). Notons :
$$n \triangleq \sum_{i=1}^{I} \sum_{j=1}^{J} n_{i,j}$$
Pour fixer les idées, nous considérons un exemple jouet en R.
Pour fixer les idées, nous considérons un exemple développé par Jean-Paul Benzécri [@benzecri1985phosphates] dans un article qui introduit à l'analyse des correspondances sur la base de données du commerce mondial des phosphates (voir Table \@ref(tab:mat-N)). A l'intersection de la ligne $i$ et de la colonne $j$ du tableau de données, nous lisons, en milliers de tonnes de $P_2O_5$, la quantité importée par le pays $i$ depuis le pays $j$ durant 8 années, de 1973 à 1980. Les labels des pays importateurs et exportateurs sont donnés dans les Tables \@ref(tab:lblI) et \@ref(tab:lblJ).
```{r}
N <- matrix( c(1,2,1,3,2,5,1,7,3,6,2,8),
nrow = 4, ncol = 3,
dimnames = list( c("i1", "i2", "i3", "i4"),
c("v1", "v2", "v3")) )
```{r, include=FALSE}
#N <- matrix( c(1,2,1,3,2,5,1,7,3,6,2,8),
# nrow = 4, ncol = 3,
# dimnames = list( c("i1", "i2", "i3", "i4"),
# c("v1", "v2", "v3")) )
# N <- matrix( c(4, 3, 6, 2, 2, 3, 0, 0, 2, 0,
# 2, 4, 4, 0, 5, 3, 0, 2, 1, 1,
# 4, 2, 5, 5, 0, 1, 0, 0, 1, 4,
# 4, 2, 2, 1, 1, 0, 0,11, 0, 1,
# 1, 1, 3, 3, 4, 0, 1, 1, 2, 6,
# 2, 1, 1, 3, 1, 3, 4, 3, 4, 0,
# 2, 0, 1, 3, 2, 0, 1,10, 0, 3,
# 4, 3, 3, 1, 1, 2, 5, 1, 2, 0,
# 1, 2, 0, 5, 3, 1, 3, 1, 0, 6),
# nrow = 10, ncol = 9,
# dimnames = list(
# c("red", "orange", "yellow", "green",
# "blue", "purple", "white", "black",
# "pink", "brown"),
# c("video", "jazz", "country", "rap",
# "pop", "opera", "low F", "high F",
# "middle F")) )
```
```{r lblI, echo=FALSE}
lblI <- matrix( c("iBL", "iCA", "iFR", "iDL", "iIT", "iJP", "iNL",
"Belgique", "Canada", "France", "Deutschland", "Italie", "Japon", "Nederland",
"iSP", "iUK", "iIN", "iBR", "iPL", "iRM", "iEE",
"Espagne", "United Kingdom", "Inde", "Brésil", "Pologne", "Roumanie", "Autres pays Europe Est"),
nrow = 7 )
kbl(lblI, caption = "Pays importateurs de phosphates")
```
```{r lblJ, echo=FALSE}
lblJ <- matrix( c("eBL", "eUS", "eJR", "eMR", "Belgique", "USA", "Jordanie", "Maroc",
"eSN", "eTG", "eTN", "eCC", "Sénégal", "Togo", "Tunisie", "URSS (CCCP)"),
nrow = 4 )
kbl(lblJ, caption = "Pays exportateurs de phosphates")
```
```{r mat-N}
N <- matrix( c(0, 2, 1311, 1322, 42, 0, 299, 20, 122, 0, 29, 0, 0, 2,
1305, 8335, 2691, 3808, 1883, 4426, 1484, 339, 645, 2559, 4918,
1284, 768, 201,
0, 0, 70, 0, 194, 522, 0, 0, 2, 996, 0, 271, 483, 136,
3573, 0, 4891, 1445, 2881, 1540, 1853, 5073, 2852, 1149, 1398,
3311, 1541, 1398,
25, 0, 1484, 261, 67, 239, 249, 2, 971, 218, 15, 33, 6, 0,
500, 8, 2526, 200, 195, 93, 1584, 85, 36, 0, 0, 540, 138, 0,
110, 0, 1697, 288, 493, 0, 59, 11, 197, 134, 241, 548, 22, 333,
293, 0, 4, 1442, 0, 0, 84, 0, 0, 0, 0, 1996, 1206, 5533),
nrow = 14, ncol = 8,
dimnames = list(
c("iBL", "iCA", "iFR", "iDL", "iIT", "iJP", "iNL", "iSP", "iUK",
"iIN", "iBR", "iPL", "iRM", "iEE"),
c("eBL", "eUS", "eJR", "eMR", "eSN", "eTG", "eTN", "eCC")))
I <- dim(N)[1]
J <- dim(N)[2]
n <- sum(sum(N))
print(N)
print(n)
kbl(N, caption = "Commerce des phosphates entre 1973 et 1980", booktabs = TRUE) %>%
kable_styling(latex_options = "striped")
```
Soit une matrice, dite de probabilités, $\mathbf{P} \triangleq \frac{1}{n} \mathbf{N}$.
Sur cet exemple, la somme totale $n$ est égale à `r format(n, scientific=FALSE)`.
```{r}
Soit une matrice, dite de probabilités, $\mathbf{P} \triangleq \frac{1}{n} \mathbf{N}$ (voir Table \@ref(tab:mat-p)).
```{r mat-p}
P <- (1/n) * N
print(P)
kbl( round_preserve_sum(1000 * P),
caption = "Matrice de probabilités $P$ (en millièmes)", booktabs = TRUE) %>%
kable_styling(latex_options = "striped")
```
Notons $\mathbf{r} \triangleq \mathbf{P} \mathbf{1}$ les sommes des éléments de chaque ligne de $\mathbf{P}$ et $\mathbf{c} \triangleq \mathbf{P}^T \mathbf{1}$ les sommes des éléments de chaque colonne de $\mathbf{P}$.
Notons $\mathbf{r} \triangleq \mathbf{P} \mathbf{1}$ les sommes des éléments de chaque ligne de $\mathbf{P}$ (voir Table \@ref(tab:vec-r)) et $\mathbf{c} \triangleq \mathbf{P}^T \mathbf{1}$ les sommes des éléments de chaque colonne de $\mathbf{P}$ (voir Table \@ref(tab:vec-c)).
```{r}
```{r vec-r}
r <- rowSums(P)
kbl( t(as.matrix( round_preserve_sum(1000 * r) )),
caption = "Poids des lignes de $P$", booktabs = TRUE)
```
```{r vec-c}
c <- colSums(P)
print(r)
print(c)
kbl( t(as.matrix( round_preserve_sum(1000 * c) )),
caption = "Poids des colonnes de $P$", booktabs = TRUE)
```
Notons $\mathbf{D_r} \triangleq diag(\mathbf{r})$ une matrice avec sur sa diagonale les éléments de $\mathbf{r}$ et $\mathbf{D_c} \triangleq diag(\mathbf{c})$ une matrice avec sur sa diagonale les éléments de $\mathbf{c}$.
@ -42,35 +106,34 @@ Notons $\mathbf{D_r} \triangleq diag(\mathbf{r})$ une matrice avec sur sa diagon
```{r}
Dr <- diag(r)
Dc <- diag(c)
print(Dr)
print(Dc)
```
Notons $\mathbf{R} \triangleq \mathbf{D_r^{-1}} \mathbf{P}$ la matrice des \emph{profils lignes} et $\mathbf{C} \triangleq \mathbf{D_c^{-1}} \mathbf{P}^T$ la matrice des \emph{profils colonnes}.
Notons $\mathbf{R} \triangleq \mathbf{D_r^{-1}} \mathbf{P}$ la matrice des \emph{profils lignes} (voir Table \@ref(tab:mat-r)) et $\mathbf{C} \triangleq \mathbf{D_c^{-1}} \mathbf{P}^T$ la matrice des \emph{profils colonnes} (voir Table \@ref(tab:mat-c)).
```{r}
```{r mat-r}
# Pour construire R ou C, il n'est pas nécessaire de construire Dr ou Dc.
# L'utilisation de la fonction sweep est plus efficace.
R <- sweep(P, MARGIN = 1, 1/r, '*')
kbl( round_preserve_sum(1000 * R),
caption = "$R$, matrice des profils lignes", booktabs = TRUE ) %>%
kable_styling(latex_options = "striped")
```
```{r mat-c}
C <- sweep(t(P), MARGIN = 1, 1/c, '*')
print(R)
print(C)
kbl( round_preserve_sum(1000 * C),
caption = "$C$, matrice des profils colonnes", booktabs = TRUE ) %>%
kable_styling(latex_options = "striped")
```
Notons $\mathbf{r^i}$ la $i$-ème ligne de $\mathbf{R}$, c'est-à-dire le profil du $i$-ème individu si $\mathbf{N}$ est une matrice qui croise individus et variables. Notons $\mathbf{c^j}$ la $j$-ème ligne de $\mathbf{C}$, c'est-à-dire le profil de la $j$-ème variable si $\mathbf{N}$ est une matrice qui croise individus et variables.
$\mathbf{r^i}$ (resp. $\mathbf{c^j}$) est un vecteur dont la somme des éléments est égale à $1$ : $\sum_{j=1}^{J} r_j^i = 1$ (resp. $\sum_{i=1}^{I} c_i^j = 1$). $r_j^i$ représente la part relative de la variable $j$ dans la description de l'individu $i$. De même, $c_i^j$ représente la part relative de l'individu $i$ dans la description de la variable $j$.
```{r}
# On vérifie que la somme des éléments d'une ligne de R ou C est égale à 1.
print(rowSums(R))
print(rowSums(C))
```
## Principe d'équivalence distributionnelle
Nous considérons le nuage des profils lignes $\left\{ \mathbf{r^i} \right\}_{i=1}^I$ avec leurs masses associées $\left\{ r_i \right\}_{i=1}^I$. Nous plongeons ce nuage dans un espace avec une métrique euclidienne pondérée, dite métrique du $\chi^2$ :
$$d^2(\mathbf{r^{i_1}}, \mathbf{r^{i_2}}) = \sum_{j=1}^J \frac{\left( r^{i_1}_j - r^{i_2}_j \right)^2}{c_j}$$
\[d^2(\mathbf{r^{i_1}}, \mathbf{r^{i_2}}) = \sum_{j=1}^J \frac{\left( r^{i_1}_j - r^{i_2}_j \right)^2}{c_j}\]
Nous considèrerions de façon symétrique le nuage des profils colonnes.
@ -78,7 +141,7 @@ Montrons que ce choix de métrique assure le principe dit d'équivalence distrib
Considérons deux profils lignes pondérés $(r_{i_1}, \mathbf{r^{i_1}})$ et $(r_{i_2}, \mathbf{r^{i_2}})$ qui ont même profils : $\mathbf{r^{i_1}} = \mathbf{r^{i_2}}$. Considérons également un profil pondéré $(r_{i_0}, \mathbf{r^{i_0}})$ tel que $\mathbf{r^{i_1}} = \mathbf{r^{i_2}} = \mathbf{r^{i_0}}$ et $r_{i_0} = r_{i_1} + r_{i_2}$.
En remplaçant $(r_{i_1}, \mathbf{r^{i_1}})$ et $(r_{i_2}, \mathbf{r^{i_2}})$ par $(r_{i_0}, \mathbf{r^{i_0}})$, les valeurs $c_j$ sont inchangées et donc les distances $d^2(\mathbf{r^{i}}, \mathbf{r^{i'}})$ sont également inchangées. Nous allons maintenant prouver que les distances entre profils colonnes sont également inchangées.
En remplaçant $(r_{i_1}, \mathbf{r^{i_1}})$ et $(r_{i_2}, \mathbf{r^{i_2}})$ par $(r_{i_0}, \mathbf{r^{i_0}})$, les valeurs $c_j$ sont inchangées et donc les distances $d^2(\mathbf{r^{i}}, \mathbf{r^{i'}})$ sont inchangées. Nous allons maintenant prouver que les distances entre profils colonnes sont inchangées.
$$
d^2(\mathbf{c^{j_1}}, \mathbf{c^{j_2}}) = \sum_{i=1}^{I} \frac{\left(c^{j_1}_{i} - c^{j_2}_{i}\right)^2}{r_i} = \dots + \frac{1}{r_{i_1}} \left(\frac{P_{i_1,j_1}}{c_{j_1}} - \frac{P_{i_1,j_2}}{c_{j_2}}\right)^2 + \frac{1}{r_{i_2}} \left(\frac{P_{i_2,j_1}}{c_{j_1}} - \frac{P_{i_2,j_2}}{c_{j_2}}\right)^2 + \dots
$$
@ -109,7 +172,7 @@ Ainsi, nous pouvons montrer que les deux termes de $d^2(\mathbf{c^{j_1}}, \mathb
## Centre de masse
Calculons le centre de masse des profils lignes.
Calculons la j-ème coordonnée du centre de masse des profils lignes.
\begin{align*}
& \frac{\sum_i r_i (P_{i,j} / r_i)}{\sum_i r_i} \\
= \{& \sum_i r_i = 1 \} \\
@ -117,6 +180,7 @@ Calculons le centre de masse des profils lignes.
= \phantom{\{}& \\
& c_j \\
\end{align*}
Donc, $\mathbf{c}$ est le centre de masse du nuage des profils lignes $\left\{ \mathbf{r^i} \right\}_{i=1}^I$ avec leurs masses associées $\left\{ r_i \right\}_{i=1}^I$. Par symétrie, $\mathbf{r}$ est le centre de masse du nuage des profils colonnes $\left\{ \mathbf{c^j} \right\}_{j=1}^J$ avec leurs masses associées $\left\{ c_j \right\}_{j=1}^J$.
## Inertie des écarts à l'indépendance
@ -131,7 +195,7 @@ Ainsi, l'inertie du nuage des profils lignes par rapport à son centre de masse
## GSVD des profils lignes et des profils colonnes
Nous souhaitons représenter les profils lignes dans un repère dont les axes orthonormaux sont orientés selon les direction d'inertie maximale. Nous devons ainsi calculer le SVD :
Nous souhaitons représenter les profils lignes dans un repère dont les axes orthonormaux sont orientés selon les direction d'inertie maximale. Nous nommerons ces axes les \emph{axes principaux} ou encore les \emph{facteurs}. Nous devons ainsi calculer le SVD :
$$\mathbf{P} - \mathbf{r}\mathbf{c}^T = \mathbf{A}\boldsymbol{\Delta}\mathbf{B}^T \; \text{avec } \; \mathbf{A}^T\mathbf{D_r^{-1}}\mathbf{A} = \mathbf{B}^T\mathbf{D_c^{-1}}\mathbf{B} = \mathbf{I}$$
C'est une forme généralisée de la décomposition en valeurs singulières (GSVD) puisque $\mathbf{A}$ et $\mathbf{B}$ sont des matrices orthogonales dans des espaces euclidiens associés aux métriques respectives $\mathbf{D_r^{-1}}$ (pour prendre en compte les masses associées à chaque profil ligne) et $\mathbf{D_c^{-1}}$ (pour prendre en compte les échelles différentes de chaque colonne).
@ -177,21 +241,21 @@ De même pour montrer $\mathbf{B}^T\mathbf{D_c^{-1}}\mathbf{B} = \mathbf{I}$.
## Décomposition de l'inertie des profils
Nous avons montré plus haut que pour représenter les profils lignes dans un repère dont les axes orthonormaux sont orientés selon les direction d'inertie maximale, nous devions calculer le SVD :
Nous avons montré plus haut que pour représenter les profils lignes dans un repère dont les axes orthonormaux sont orientés selon les direction d'inertie maximale (nous appelons ces axes les \emph{facteurs}), il faut calculer le SVD :
$$\mathbf{P} - \mathbf{r}\mathbf{c}^T = \mathbf{A}\boldsymbol{\Delta}\mathbf{B}^T \; \text{avec } \; \mathbf{A}^T\mathbf{D_r^{-1}}\mathbf{A} = \mathbf{B}^T\mathbf{D_c^{-1}}\mathbf{B} = \mathbf{I}$$
Montrons que cette décomposition correspond bien à celle des profils lignes centrés.
Montrons que cette décomposition correspond bien à celle des profils lignes centrés (rappel : $\mathbf{c}$ est le centre de masse des profils lignes).
\begin{align*}
& \mathbf{D_r^{-1}}\mathbf{P} - \mathbf{1}\mathbf{c}^T = \boldsymbol\alpha \boldsymbol\Delta \boldsymbol\beta^T \; \text{avec} \; \boldsymbol\alpha^T\mathbf{D_r^{-1}}\boldsymbol\alpha = \boldsymbol\beta^T\mathbf{D_c^{-1}}\boldsymbol\beta = \mathbf{I} \\
= \{& \times \mathbf{D_r} \} \\
= \{& \mathbf{D_r} \times \} \\
& \mathbf{P} - \mathbf{r}\mathbf{c}^T = \left(\mathbf{D_r}\boldsymbol\alpha\right) \boldsymbol\Delta \boldsymbol\beta^T \; \text{avec} \; \left(\mathbf{D_r}\boldsymbol\alpha\right)^T\mathbf{D_r^{-1}}\left(\mathbf{D_r}\boldsymbol\alpha\right) = \boldsymbol\beta^T\mathbf{D_c^{-1}}\boldsymbol\beta = \mathbf{I} \\
\end{align*}
## Axes principaux et coordonnées principales des profils
## Facteurs et coordonnées principales des profils
Ainsi, les colonnes de $\mathbf{B}$ sont les axes principaux, $\mathbf{D_c^{-1}}$-orthogonaux, pour le nuage centré des profils lignes. Nous montrerions de même que les colonnes de $\mathbf{A}$ sont les axes principaux, $\mathbf{D_r^{-1}}$-orthogonaux, pour le nuage centré des profils colonnes.
Ainsi, les colonnes de $\mathbf{B}$ sont les facteurs (ou \emph{axes principaux}), $\mathbf{D_c^{-1}}$-orthogonaux, pour le nuage centré des profils lignes. Nous montrerions de même que les colonnes de $\mathbf{A}$ sont les facteurs, $\mathbf{D_r^{-1}}$-orthogonaux, pour le nuage centré des profils colonnes.
Notons $\mathbf{F}$ (respectivement, $\mathbf{G}$) une matrice dont les lignes sont les coordonnées principales (i.e., les coordonnées selon les axes principaux) des profils lignes centrés (respectivement, des profils colonnes centrés).
Notons $\mathbf{F}$ (respectivement, $\mathbf{G}$) une matrice dont les lignes sont les coordonnées principales (i.e., les coordonnées selon les facteurs) des profils lignes centrés (respectivement, des profils colonnes centrés).
\begin{align*}
& \mathbf{F} \\
= \{& \text{Par définition de $\mathbf{F}$} \} \\
@ -256,30 +320,225 @@ Nous découvrons ainsi des formules de transition entre les coordonnées princip
& \mathbf{R}\mathbf{G}\boldsymbol\Delta^{-1}
\end{align*}
## Inertie des profils selon les axes principaux
## Inertie des profils selon les facteurs
Vérifions maintenant que la décomposition de l'inertie du nuage des profils lignes (ou du nuage des profils colonnes) selon les axes principaux se représente par une matrice diagonale.
Vérifions maintenant que la décomposition de l'inertie du nuage des profils lignes (ou du nuage des profils colonnes) selon les facteurs se représente par une matrice diagonale.
$$\mathbf{F}^T\mathbf{D_r}\mathbf{F} = \left(\mathbf{D_r^{-1}} \mathbf{A}\boldsymbol\Delta\right)^T\mathbf{D_r}\mathbf{D_r^{-1}} \mathbf{A}\boldsymbol\Delta = \boldsymbol\Delta^2$$
Ainsi, l'inertie du nuage centré des profils lignes est : $\sum_i r_i \sum_k f_{ik}^2 = \sum_k \delta_k^2$ (où $\delta_k \triangleq \boldsymbol\Delta_{k,k}$).
Les lignes de $\boldsymbol\Phi \triangleq \mathbf{F}\boldsymbol\Delta^{-1}$ sont appelées les coordonnées standard des profils lignes. Selon ces dernières, les profils lignes centrés ont une inertie unité selon les axes principaux ($\boldsymbol\Phi^T\mathbf{D_r}\boldsymbol\Phi = \mathbf{I}$).
Les lignes de $\boldsymbol\Phi \triangleq \mathbf{F}\boldsymbol\Delta^{-1}$ sont appelées les coordonnées standard des profils lignes. Selon ces dernières, les profils lignes centrés ont une inertie unité selon les facteurs ($\boldsymbol\Phi^T\mathbf{D_r}\boldsymbol\Phi = \mathbf{I}$).
$$\mathbf{G}^T\mathbf{D_c}\mathbf{G} = \left(\mathbf{D_c^{-1}} \mathbf{B}\boldsymbol\Delta\right)^T\mathbf{D_c}\mathbf{D_c^{-1}} \mathbf{B}\boldsymbol\Delta = \boldsymbol\Delta^2$$
Ainsi, l'inertie du nuage centré des profils colonnes est : $\sum_j c_j \sum_k g_{jk}^2 = \sum_k \delta_k^2$.
Les lignes de $\boldsymbol\Gamma \triangleq \mathbf{G}\boldsymbol\Delta^{-1}$ sont appelées les coordonnées standard des profils colonnes. Selon ces dernières, les profils colonnes centrés ont une inertie unité selon les axes principaux ($\boldsymbol\Gamma^T\mathbf{D_c}\boldsymbol\Gamma = \mathbf{I}$).
Les lignes de $\boldsymbol\Gamma \triangleq \mathbf{G}\boldsymbol\Delta^{-1}$ sont appelées les coordonnées standard des profils colonnes. Selon ces dernières, les profils colonnes centrés ont une inertie unité selon les facteurs ($\boldsymbol\Gamma^T\mathbf{D_c}\boldsymbol\Gamma = \mathbf{I}$).
## Relations barycentriques
En observant l'égalité $\mathbf{G} = \mathbf{C}\mathbf{F}\boldsymbol\Delta^{-1}$, nous remarquons que la $j$-ème ligne de $\mathbf{G}$ (i.e., les coordonnées principales du $j$-ème profil colonne) est une combinaison linéaire (viz., un barycentre) des lignes de $\mathbf{F}$ (i.e., c'est à dire de l'ensemble des profils lignes exprimés dans leurs coordonnées principales) suivi par un changement d'échelle $1/\delta_k$ selon chacun des $K$ axes principaux. Nous ferions une observation symétrique à partir de l'égalité $\mathbf{F} = \mathbf{R}\mathbf{G}\boldsymbol\Delta^{-1}$.
En observant l'égalité $\mathbf{G} = \mathbf{C}\mathbf{F}\boldsymbol\Delta^{-1}$, nous remarquons que la $j$-ème ligne de $\mathbf{G}$ (i.e., les coordonnées principales du $j$-ème profil colonne) est une combinaison linéaire (viz., un barycentre) des lignes de $\mathbf{F}$ (i.e., c'est à dire de l'ensemble des profils lignes exprimés dans leurs coordonnées principales) suivi par un changement d'échelle $1/\delta_k$ selon chacun des $K$ facteurs (d'où l'expression de quasi-barycentre). Nous ferions une observation symétrique à partir de l'égalité $\mathbf{F} = \mathbf{R}\mathbf{G}\boldsymbol\Delta^{-1}$.
```{r}
S <- sweep(P - r %*% t(c), 1, -r/2, FUN = "*")
S <- sweep(S, 2, -c/2, FUN = "*")
Comme $\mathbf{G} = \mathbf{C}\boldsymbol\Phi$, et que la somme des éléments d'une ligne de $\mathbf{C}$ (viz. un profil colonne), est égale à 1, un profil colonne exprimé dans ses coordonnées principales (viz. une ligne de $\mathbf{G}$) est un barycentre des profils lignes exprimés dans leurs coordonnées standard (viz. les lignes de $\boldsymbol\Phi$). Symétriquement, comme $\mathbf{F} = \mathbf{R}\boldsymbol\Gamma$, un profil ligne exprimé dans ses coordonnées principales est un barycentre des profils colonnes exprimés dans leurs coordonnées standard.
## Cartes pour représenter les profils
Récapitulons les résultats des dérivations ci-dessus :
\begin{itemize}
\item $\mathbf{N} \in \mathbb{R}^{I \times J}$ ; $n \triangleq \sum_{i=1}^{I} \sum_{j=1}^{J} n_{i,j}$ ; $\mathbf{P} \triangleq \frac{1}{n} \mathbf{N}$
\item $\mathbf{r} \triangleq \mathbf{P} \mathbf{1}$ ; $\mathbf{c} \triangleq \mathbf{P}^T \mathbf{1}$ ; $\mathbf{D_r} \triangleq diag(\mathbf{r})$ ; $\mathbf{D_c} \triangleq diag(\mathbf{c})$
\item $\mathbf{R} \triangleq \mathbf{D_r^{-1}} \mathbf{P}$ ; $\mathbf{C} \triangleq \mathbf{D_c^{-1}} \mathbf{P}^T$
\item $\mathbf{D_r^{-1/2}} \left(\mathbf{P} - \mathbf{r}\mathbf{c}^T\right) \mathbf{D_c^{-1/2}} \; = \; \tilde{\mathbf{A}} \boldsymbol{\Delta} \tilde{\mathbf{B}}^T$, avec $\tilde{\mathbf{A}}^T \tilde{\mathbf{A}} = \tilde{\mathbf{B}}^T \tilde{\mathbf{B}} = \mathbf{I}$
\item $\mathbf{F} = \mathbf{D_r^{-1/2}}\tilde{\mathbf{A}}\boldsymbol\Delta = \boldsymbol\Phi\boldsymbol\Delta$ ; $\mathbf{G} = \mathbf{D_c^{-1/2}} \tilde{\mathbf{B}}\boldsymbol\Delta = \boldsymbol\Gamma\boldsymbol\Delta$
\end{itemize}
Représentons sur une carte les coordonnées principales des dimensions n°1 et n°2 des profils lignes et des profils colonnes (voir Figure \@ref(fig:05-c-map-1-2)).
```{r 05-c-map-1-2, fig.width = 6, fig.cap = "Carte selon les facteurs 1 (x) et 2 (y)"}
scaleR <- 1/sqrt(r)
scaleC <- 1/sqrt(c)
S <- sweep(P - r %*% t(c), 1, scaleR, FUN = "*")
S <- sweep(S, 2, scaleC, FUN = "*")
dec <- svd(S)
Phi <- sweep(dec$u, 1, -r/2, FUN="*")
Phi <- sweep(dec$u, 1, scaleR, FUN="*")
F <- sweep(Phi, 2, dec$d, FUN="*")
Gam <- sweep(dec$v, 1, -c/2, FUN="*")
Gam <- sweep(dec$v, 1, scaleC, FUN="*")
G <- sweep(Gam, 2, dec$d, FUN="*")
plot(c(F[,1], G[,1]), c(F[,2], G[,2]), xlab = "d1", ylab = "d2", type = "n",
asp = 1, xaxt = "n", yaxt = "n")
text(c(F[,1], G[,1]), c(F[,2], G[,2]), c(rownames(P), colnames(P)))
# par(pty="s") # square plotting region, useful in interactive mode
plot(c(F[,1], G[,1]), c(F[,2], G[,2]), type = "n",
xlab="", ylab="", asp = 1, xaxt = "n", yaxt = "n")
text(c(F[,1], G[,1]), c(F[,2], G[,2]), c(rownames(P), colnames(P)),
adj = 0, cex = 0.6)
points(0, 0, pch = 3)
```
Calculons la proportion d'inertie cumulée exprimée par les facteurs (voir Table \@ref(tab:05-c-vec-delta2)).
```{r 05-c-vec-delta2}
tblTotalInr <- cumsum(round_preserve_sum(1000 * (dec$d^2 / sum(dec$d^2))))
tblTotalInr <- matrix(tblTotalInr, nrow=1)
colnames(tblTotalInr) <- 1:length(dec$d)
kbl(tblTotalInr, caption = "Proportion de l'inertie cumulée exprimée \
par les facteurs successifs (en millièmes)", booktabs = TRUE)
```
La carte de la Figure \@ref(fig:05-c-map-1-2) représente donc `r tblTotalInr[2]`‰ de l'inertie totale.
## Importance des axes et des profils
Nous pouvons mesurer la contribution d'un profil ligne $i$ (resp. d'un profil colonne $j$) à l'inertie exprimée par l'axe principal $k$ :
\[CTR_{i,k} = \frac{r_i f_{i,k}^2}{\sum_i r_i f_{i,k}^2} = \frac{r_i f_{i,k}^2}{\delta_k^2}\]
\[CTR_{j,k} = \frac{c_j g_{j,k}^2}{\sum_j c_j g_{j,k}^2} = \frac{c_j g_{j,k}^2}{\delta_k^2}\]
Les contributions ont des valeurs entre $0$ et $1$. La somme des contributions des profils (ligne ou colonne) à un axe est égale à $1$.
Une heuristique utile : la contribution d'un profil ligne (resp. colonne) peut être considéré important quand sa valeur dépasse $1/I$ (resp. $1/J$).
```{r}
temp <- sweep(F^2, 1, r, FUN = "*")
CTRI <- sweep(temp, 2, dec$d^2, FUN = "/")
temp <- sweep(G^2, 1, c, FUN = "*")
CTRJ <- sweep(temp, 2, dec$d^2, FUN = "/")
```
Nous pouvons également mesurer la corrélation des axes principaux à un profil donné, c'est-à-dire la proportion de variance d'un profil qui peut être attribuée à un axe principal :
\[COR_{i,k} = \frac{f_{i,k}^2}{\sum_k f_{i,k}^2}\]
\[COR_{j,k} = \frac{g_{j,k}^2}{\sum_k g_{j,k}^2}\]
Les corrélations ont des valeurs entre $0$ et $1$. La somme des corrélations des axes à un profil (ligne ou colonne) est égale à $1$.
```{r}
temp <- temp <- F^2
CORI <- sweep(temp, 1, rowSums(temp), FUN = "/")
temp <- temp <- G^2
CORJ <- sweep(temp, 1, rowSums(temp), FUN = "/")
```
## Tableaux synthétiques des profils
Nous calculons la part d'inertie expliquée par chaque profil ligne :
\[ INR(i) = \sum_j r_i F_{i,j}^2 \]
Nous choisissons d'exprimer cette part d'inertie en proportion de l'inertie totale.
```{r}
INRI <- rowSums(sweep(F^2, 1, r, FUN="*"))
INRI <- INRI / sum(INRI)
INRJ <- rowSums(sweep(G^2, 1, c, FUN="*"))
INRJ <- INRJ / sum(INRJ)
```
Nous rappelons le poids d'un profil ligne : $PDS(i) = r_i$.
Nous synthétisons ces données dans un tableau pour les profils lignes sur 4 premiers facteurs (voir Table \@ref(tab:05-c-synth-row)).
```{r}
nbFact <- 4 # print data for the first nbFact factors
tempFactData <- c()
tempFactNames <- c()
for (k in 1:nbFact) {
tempFactData <- c(tempFactData,
round_preserve_sum(1000*F[,k]),
round_preserve_sum(1000*CORI[,k]),
round_preserve_sum(1000*CTRI[,k]))
tempFactNames <- c(tempFactNames, paste('F#', k, sep=""), 'COR', 'CTR')
}
tblI <- matrix( c(round_preserve_sum(1000*r),
round_preserve_sum(1000*INRI),
tempFactData),
ncol = 2 + nbFact * 3)
rownames(tblI) <- rownames(N)
colnames(tblI) <- c('PDS', 'INR', tempFactNames)
```
```{r 05-c-synth-row}
kbl(tblI, caption = "Synthèse des profils lignes \
sur les 4 premiers facteurs", booktabs = TRUE) %>%
add_header_above(c(" " = 3, "F#1" = 3, "F#2" = 3, "F#3" = 3, "F#4" = 3)) %>%
kable_styling(latex_options = c("striped", "scale_down"))
```
Nous donnons aussi un tableau synthétique pour les profils colonnes sur les 4 premiers facteurs (voir Table \@ref(tab:05-c-synth-col)).
```{r}
nbFact <- 4 # print data for the first nbFact factors
tempFactData <- c()
tempFactNames <- c()
for (k in 1:nbFact) {
tempFactData <- c(tempFactData,
round_preserve_sum(1000*G[,k]),
round_preserve_sum(1000*CORJ[,k]),
round_preserve_sum(1000*CTRJ[,k]))
tempFactNames <- c(tempFactNames, paste('F#', k, sep=""), 'COR', 'CTR')
}
tblJ <- matrix( c(round_preserve_sum(1000*c),
round_preserve_sum(1000*INRJ),
tempFactData),
ncol = 2 + nbFact * 3)
rownames(tblJ) <- colnames(N)
colnames(tblJ) <- c('PDS', 'INR', tempFactNames)
```
```{r 05-c-synth-col}
kbl(tblJ, caption = "Synthèse des profils colonnes \
sur les 4 premiers facteurs", booktabs = TRUE) %>%
add_header_above(c(" " = 3, "F#1" = 3, "F#2" = 3, "F#3" = 3, "F#4" = 3)) %>%
kable_styling(latex_options = c("striped", "scale_down"))
```
## Éléments d'interprétation des cartes des profils améliorées
Nous calculons les parts de l'inertie du plan factoriel 1-2 expliquées par chaque profil ligne et chaque profil colonne. Nous utilisons ces valeurs pour fixer la taille de la police des labels des profils. Nous empruntons cette technique à [@greenacre2010biplots] (pp.181-182).
```{r}
# Parts de l'inertie du plan factoriel 1-2 expliquée par chaque profil ligne
rowcon <- r * (F[,1]^2 + F[,2]^2) / sum(dec$d[1:2]^2)
rnames <- rownames(P)
rnames[rowcon < 0.01] <- "."
rsize <- log(1 + exp(1) * rowcon^0.3)
rsize[rowcon < 0.01] <- 1
# Parts de l'inertie du plan factoriel 1-2 expliquée par chaque profil colonne
colcon <- c * (G[,1]^2 + G[,2]^2) / sum(dec$d[1:2]^2)
cnames <- colnames(P)
cnames[colcon < 0.01] <- "."
csize <- log(1 + exp(1) * colcon^0.3)
csize[colcon < 0.01] <- 1
```
Nous générons la Figure \@ref(fig:05-c-map-1-2-better) qui est une carte améliorée du plan factoriel 1-2.
```{r 05-c-map-1-2-better, fig.width = 6, fig.cap = "Carte améliorée selon les facteurs 1 (x) et 2 (y)"}
plot(c(F[,1], G[,1]), c(F[,2], G[,2]), type = "n",
xlab="", ylab="", asp = 1, xaxt = "n", yaxt = "n")
text(c(F[,1], G[,1]), c(F[,2], G[,2]), c(rnames, cnames),
adj = 0, cex = c(rsize, csize))
points(0, 0, pch = 3)
```
* Les plus gros pays exportateurs (resp. Maroc, URSS et USA) forment trois pôles d'attraction distincts.
* $eCC$ (URSS en tant qu'exportateur) et $iEE$ (autres pays d'Europe de l'Est en tant qu'importateurs) sont isolés à une extrémité du premier facteur et contribuent de façon majeure à l'inertie de ce dernier.
* Les USA et l'URSS s'opposent sur le premier axe factoriel.
* Les USA et le Maroc s'opposent sur le second axe factoriel.
* Sur le plan factoriel 1-2, autour des USA gravitent les importateurs : d'abord le Canada (presque entièrement expliqué par le plan factoriel 1-2), mais aussi le Japon, le Brésil et l'Inde (le Japon et le Brésil sont très bien expliqués par le plan factoriel 1-2, trandis que l'inertie de l'Inde est fortement expliquée par l'axe factoriel n°4 sur lequel elle s'oppose en particulier à l'Espagne, voir Table \@ref(tab:05-c-synth-row)).
On poursuivrait l'analyse en explorant par exemple la carte du plan factoriel 2-3 (voir Figure \@ref(fig:05-c-map-2-3)).
```{r}
# Parts de l'inertie du plan factoriel 2-3 expliquée par chaque profil ligne
rowcon <- r * (F[,2]^2 + F[,3]^2) / sum(dec$d[2:3]^2)
rnames <- rownames(P)
rnames[rowcon < 0.01] <- "."
rsize <- log(1 + exp(1) * rowcon^0.3)
rsize[rowcon < 0.01] <- 1
# Parts de l'inertie du plan factoriel 2-3 expliquée par chaque profil colonne
colcon <- c * (G[,2]^2 + G[,3]^2) / sum(dec$d[2:3]^2)
cnames <- colnames(P)
cnames[colcon < 0.01] <- "."
csize <- log(1 + exp(1) * colcon^0.3)
csize[colcon < 0.01] <- 1
```
```{r 05-c-map-2-3, fig.width = 6, fig.cap = "Carte des facteurs 2 (x) et 3 (y)"}
plot(c(F[,2], G[,2]), c(F[,3], G[,3]), type = "n",
xlab="", ylab="", asp = 1, xaxt = "n", yaxt = "n")
text(c(F[,2], G[,2]), c(F[,3], G[,3]), c(rnames, cnames),
adj = 0, cex = c(rsize, csize))
points(0, 0, pch = 3)
```

View File

@ -4,9 +4,18 @@ author: "Pierre-Edouard Portier"
documentclass: book
geometry: margin=2cm
fontsize: 12pt
date: "Mars 2022"
date: "Jan 2023"
toc: true
classoption: fleqn
bibliography: intro_to_ml.bib
link-citations: yes
---
\setlength{\abovedisplayskip}{5pt}
\setlength{\belowdisplayskip}{0pt}
\setlength{\abovedisplayshortskip}{0pt}
\setlength{\belowdisplayshortskip}{0pt}
```{r, include=FALSE}
library(kableExtra)
```

View File

@ -30,3 +30,28 @@
year={2015},
publisher={Wiley Online Library}
}
@article{abdi2017correspondence,
title={Correspondence analysis},
author={Abdi, Hervé and Béra, Michel},
journal={Encyclopedia of Social Network Analysis and Mining},
year={2017},
publisher={Springer}
}
@article{benzecri1985phosphates,
title={Introduction {\`a} l'analyse des correspondances d'apr{\`e}s l'analyse du commerce mondial des phosphates},
author={Benz{\'e}cri, F},
journal={Cahiers de l'analyse des donn{\'e}es},
volume={10},
number={2},
pages={145--190},
year={1985}
}
@book{greenacre2010biplots,
title={Biplots in practice},
author={Greenacre, Michael J},
year={2010},
publisher={Fundacion BBVA}
}

21
pad.R
View File

@ -4,3 +4,24 @@
# :/^\#
# bash make_chapter 19_nystroem_approximation.Rmd
# knitr::purl("05_c_svd_ca.Rmd")
# Extrait de 05_c_svd_ca.Rmd
#
# Affichons encore une carte avec les coordonnées principales sur les dimensions n°1 et n°2, mais uniquement pour les profils lignes et les profils colonnes considérés importants.
#
# ```{r}
# selI <- CTRI > (1/I)
# selI12 <- selI[,1] | selI[,2]
# selJ <- CTRJ > (1/J)
# selJ12 <- selJ[,1] | selJ[,2]
# par(pty="s") # square plotting region
# plot(c(F[selI12,1], G[selJ12,1]), c(F[selI12,2], G[selJ12,2]),
# main = "x: d1, y: d2", type = "n",
# xlab="", ylab="", asp = 1, xaxt = "n", yaxt = "n")
# text(c(F[selI12,1], G[selJ12,1]), c(F[selI12,2], G[selJ12,2]),
# c(rownames(P)[selI12], colnames(P)[selJ12]),
# adj = 0, cex = 0.6)
# points(0, 0, pch = 3)
# ```