Prenez 20 points aléatoires dans un espace de 10 000 dimensions avec chaque coordonnée iid de . Répartissez-les en 10 paires («couples») et ajoutez la moyenne de chaque paire («un enfant») à l'ensemble de données. Ensuite, faites PCA sur les 30 points résultants et tracez PC1 vs PC2.
Une chose remarquable se produit: chaque "famille" forme un triplet de points qui sont tous proches les uns des autres. Bien sûr, chaque enfant est plus proche de chacun de ses parents dans l'espace d'origine de 10 000 dimensions, on peut donc s'attendre à ce qu'il soit proche des parents également dans l'espace PCA. Cependant, dans l'espace PCA, chaque paire de parents est également proche, même si dans l'espace d'origine ce ne sont que des points aléatoires!
Comment les enfants parviennent-ils à rassembler les parents dans la projection PCA?
On peut craindre que cela soit en quelque sorte influencé par le fait que les enfants ont une norme inférieure à celle des parents. Cela ne semble pas avoir d'importance: si je produis les enfants comme où et sont des points parentaux, alors ils auront en moyenne la même norme que les parents. Mais j'observe toujours qualitativement le même phénomène dans l'espace PCA:
Cette question utilise un ensemble de données sur les jouets, mais elle est motivée par ce que j'ai observé dans un ensemble de données réelles issues d'une étude d'association à l'échelle du génome (GWAS) où les dimensions sont des polymorphismes mononucléotidiques (SNP). Cet ensemble de données contenait des trios mère-père-enfant.
Code
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
def generate_families(n = 10, p = 10000, divide_by = 2):
X1 = np.random.randn(n,p) # mothers
X2 = np.random.randn(n,p) # fathers
X3 = (X1+X2)/divide_by # children
X = []
for i in range(X1.shape[0]):
X.extend((X1[i], X2[i], X3[i]))
X = np.array(X)
X = X - np.mean(X, axis=0)
U,s,V = np.linalg.svd(X, full_matrices=False)
X = U @ np.diag(s)
return X
n = 10
plt.figure(figsize=(4,4))
X = generate_families(n, divide_by = 2)
for i in range(n):
plt.scatter(X[i*3:(i+1)*3,0], X[i*3:(i+1)*3,1])
plt.tight_layout()
plt.savefig('families1.png')
plt.figure(figsize=(4,4))
X = generate_families(n, divide_by = np.sqrt(2))
for i in range(n):
plt.scatter(X[i*3:(i+1)*3,0], X[i*3:(i+1)*3,1])
plt.tight_layout()
plt.savefig('families2.png')