Nehmen Sie 20 zufällige Punkte in einem 10.000-dimensionalen Raum mit jeder Koordinate iid aus . Teilen Sie sie in 10 Paare ("Paare") auf und addieren Sie den Durchschnitt jedes Paares ("ein Kind") zum Datensatz. Führen Sie dann PCA für die resultierenden 30 Punkte durch und zeichnen Sie PC1 gegen PC2.
Eine bemerkenswerte Sache passiert: Jede "Familie" bildet ein Triplett von Punkten, die alle nahe beieinander liegen. Natürlich ist jedes Kind im ursprünglichen 10.000-dimensionalen Raum näher an jedem seiner Eltern, so dass man erwarten kann, dass es auch im PCA-Raum nahe an den Eltern ist. Im PCA-Bereich ist jedoch auch jedes Elternpaar nahe beieinander, obwohl es sich im ursprünglichen Bereich nur um zufällige Punkte handelt!
Wie schaffen es Kinder, Eltern in der PCA-Projektion zusammenzubringen?
Man könnte befürchten, dass dies irgendwie durch die Tatsache beeinflusst wird, dass die Kinder eine niedrigere Norm haben als die Eltern. Dies scheint keine Rolle zu spielen: Wenn ich die Kinder als wobei und Elternpunkte sind, haben sie im Durchschnitt die gleiche Norm wie die Eltern. Aber ich beobachte qualitativ immer noch das gleiche Phänomen im PCA-Raum:
Diese Frage verwendet einen Spielzeugdatensatz, ist jedoch durch das motiviert, was ich in einem realen Datensatz aus einer genomweiten Assoziationsstudie (GWAS) beobachtet habe, in der Dimensionen Einzelnukleotidpolymorphismen (SNP) sind. Dieser Datensatz enthielt Mutter-Vater-Kind-Trios.
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')
Antworten:
Während der Diskussion mit @ttnphns in den obigen Kommentaren wurde mir klar, dass das gleiche Phänomen bei viel weniger als 10 Familien beobachtet werden kann. Drei Familien (
n=3
in meinem Code-Snippet) erscheinen ungefähr in den Ecken eines gleichseitigen Dreiecks. Tatsächlich reicht es aus, nur zwei Familien (n=2
) zu berücksichtigen : Sie werden entlang PC1 getrennt, wobei jede Familie ungefähr auf einen Punkt projiziert wird.Der Fall zweier Familien kann direkt visualisiert werden. Die ursprünglichen vier Punkte im 10.000-dimensionalen Raum sind nahezu orthogonal und befinden sich in einem 4-dimensionalen Unterraum. Sie bilden also einen 4-Simplex. Nach dem Zentrieren bilden sie ein reguläres Tetraeder, das eine Form in 3D ist. So sieht es aus:
Bevor die Kinder hinzugefügt werden, kann PC1 auf eine beliebige Stelle zeigen. Es gibt keine Vorzugsrichtung. Nachdem jedoch zwei Kinder in der Mitte zweier gegenüberliegender Kanten positioniert wurden, wird PC1 sie direkt durchlaufen! Diese Anordnung von sechs Punkten wurde von @ttnphns als "Hantel" beschrieben:
Es ist zu beachten, dass die gegenüberliegenden Kanten eines regulären Tetraeders orthogonal zueinander und auch orthogonal zu der Linie sind, die ihre Zentren verbindet. Dies bedeutet, dass jede Familie auf PC1 auf einen einzelnen Punkt projiziert wird.
Vielleicht noch weniger intuitiv, wenn die beiden Kinder durch das skaliert werden2- -√
quelle