# CAMA : ma05 Vectors propres -- Applications
# Cours du 30 / 03
## Nuage de points
:::info
On peut étudier la forme d'un nuage de points par une **analyse en composantes principales (ACP)**, c.a.d. chercher les vecteurs propres de la matrice de covariance ou de corrélation.
:::
On vérifie avec un nuage de points ayant une corrélation forte entre $x$ et $y$ :
$$ y = 0.2 \, x + 1.45 + U(-1,1) \quad \textrm{avec U la loi uniforme qui simule du bruit.}
$$
Entre x et y il y a:
* une pente de 0.2
* un décalage vertical de 1.45 en x = 0
:::warning
On essaye de retrouver la corrélation entre x et y malgré le bruit avec seulement le nuage de points.
:::
```python=
N = 50
x = 6 * np.random.rand(N) - 3
nuage = np.array([x, 0.2 * x + 1.45 + np.random.rand(N)])
```
![](https://i.imgur.com/3OKHvTV.png)
On cherche la droite qui minimise la distance entre les points et leur projection sur la droite.
:::success
On construit la **matrice de covariance**, le premier vecteur propre est égal au coefficient 0.2 et est le vecteur directeur de la droite recherchée. On fait la moyenne du nuage de point dans un point de la droite.
:::
```python=
cov = np.cov(nuage.copy()) # estime la matrice de covariance
```
```
array([[2.744, 0.48 ],
[0.48 , 0.168]])
```
```python=
val, vec = lin.eig(cov)
val = val.astype('float') # on convertit puisqu'on sait que ce sont des réels
```
```
Valeurs propres de la matrice de covariance : [2.831 0.081]
Vecteurs propres de la matrice de covariance :
[[ 0.984 -0.177]
[ 0.177 0.984]]
```
![](https://i.imgur.com/TnpFGdD.png)
```python=
moyenne = nuage.mean(axis=1) # Point moyen du nuage
```
```
[0.328 2.085]
```
```python=
eq_droite = lambda x: pente * (x - moyenne[0]) + moyenne[1]
```
![](https://i.imgur.com/Q2BLHjo.png)
## Matrice de covariance
:::danger
La **covariance** entre deux variables indique à quel point elles sont liées.
$$
\textrm{cov}(\textbf{x},\textbf{y}) = \frac{1}{N} \sum_{i=1}^N (x_i - \overline{\textbf{x}}) (y_i - \overline{\textbf{y}})
$$
* $N$ le nombre de points du nuage
* $\overline{\textbf{x}}$ et $\overline{\textbf{y}}$ les moyennes de $\textbf{x}$ et de $\textbf{y}$.
:::
La matrice de covariance exprime toutes les covariances possibles :
$$
\textrm{Cov(nuage 2D)} =
\begin{bmatrix}
\textrm{cov}(\textbf{x},\textbf{x}) & \textrm{cov}(\textbf{x},\textbf{y}) \\
\textrm{cov}(\textbf{y},\textbf{x}) & \textrm{cov}(\textbf{y},\textbf{y}) \\
\end{bmatrix}
$$
```python=
cov = lambda x,y : np.dot((x - x.mean()), (y - y.mean())) / len(x)
Cov = lambda x,y : np.array([[cov(x,x), cov(x,y)], [cov(y,x), cov(y,y)]])
Cov(nuage[0], nuage[1])
```
```
array([[2.69 , 0.47 ],
[0.47 , 0.164]])
```
## Fibonnacci
:::info
Tu le sais, je le sais, on le sais Fibonnacci c'est ca :
$$x_n = x_{n-2} + x_{n-1}$$
* $x_0 = 1$
* $x_1 = 1$.
:::
:::warning
Quelle est la complexité pour calculer $x_n$?
:::
Ecrivons fibonnacci sous forme d'un système matriciel :
$$\begin{align}
x_{n-1} &= x_{n-1} \\
x_n &= x_{n-2} + x_{n-1} \\
\end{align}$$
ce qui donne
$$\begin{bmatrix}
x_{n-1}\\
x_n \\
\end{bmatrix} =
\begin{bmatrix}
0 & 1 \\
1 & 1 \\
\end{bmatrix}
\begin{bmatrix}
x_{n-2}\\
x_{n-1} \\
\end{bmatrix}$$
:::warning
Calculer n produits matriciels n'est pas rentable.
:::
:::success
Sachant que $F = P\, D\, P^{-1}$, avec P matrice des vecteurs propres et D matrice diagonale des valeurs propres :
$$
\begin{bmatrix}
x_{n}\\
x_{n+1} \\
\end{bmatrix} =
\begin{bmatrix}
0 & 1 \\
1 & 1 \\
\end{bmatrix}^n
\begin{bmatrix}
x_{0}\\
x_{1} \\
\end{bmatrix}
= (P\, D\, P^{-1})^n
\begin{bmatrix}
x_{0}\\
x_{1} \\
\end{bmatrix}
= P\, D^n\, P^{-1}
\begin{bmatrix}
x_{0}\\
x_{1} \\
\end{bmatrix}
$$
On peut calculer $x_n$ en **temps constant**.
:::
```python=
fval, fvec = lin.eig(F)
fval = fval.astype('float') # la matrice est symétrique donc ses valeurs propres sont réelles
```
```
Valeurs propres de la matrice de fibonnacci : [-0.618 1.618]
Vecteurs propres de la matrice de fibonnacci :
[[-0.851 -0.526]
[ 0.526 -0.851]]
```
```python=
fibo = lambda n : (fvec @ np.diag(fval**n) @ lin.inv(fvec) @ x0)[0]
```
## Google page rank
:::info
Soit $N$ pages web numerotées qui font référence les unes aux autres. La i-ième ligne montre par qui est référencée la i-ième page web. Il y a 1 dans la j-ième colonne si la page j cite la page i et 0 sinon.
:::
```python=
np.random.seed(42)
A = np.random.randint(2,size=(8,8))
for i in range(len(A)):
A[i,i] = 0 # on ne compte pas les auto-référencements
```
```
array([[0, 1, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 1, 0, 1, 1],
[1, 1, 1, 0, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0]])
```
:::warning
Le classement des pages utilise les vecteurs propres de cette matrice.
:::
```python=
val_pr, vec_pr = lin.eig(A)
np.abs(vec_pr[:,0]).astype(float) # valeur des pages
A.sum(axis=1) # nombre de citations
```
```
Valeur des pages : [0.217 0.153 0.376 0.489 0.243 0.514 0.47 0.071]
Nombre de citations : [2 1 5 5 3 4 5 1]
```
:::success
* La page ayant le meilleur score n'a que 4 citations mais est citée par les 3 pages ayant 5 citations
* une page ayant 5 citations est moins bien notée que les autres car elle n'est pas citée par la meilleure page
La matrice A est une application linéaire dont l'orientation principale est celle du premier vecteur propre. Le coefficient le plus important de ce vecteur indique la page web la plus importante.
:::