流形学习的标准理由是从潜在空间到观察空间的映射是非线性的。例如,下面是另一个 StackExchange 用户如何证明 Isomap 优于 PCA:
在这里,我们正在寻找二维中的一维结构。这些点位于 S 形曲线上。PCA 试图用线性一维流形来描述数据,它只是一条线;当然,一条线非常适合这些数据。Isomap 正在寻找非线性(即弯曲!)一维流形,并且应该能够发现潜在的 S 形曲线。
然而,根据我的经验,要么 PCA 与非线性模型相当好,要么非线性模型也失败了。例如,考虑这个结果:
一个简单的潜在变量随时间变化。进入观察空间的地图共有三张。二是噪音;一个是正弦波(参见下面的代码 1)。显然,观察空间中的大值并不对应于大潜在空间中的价值。这是按索引着色的数据:
在这种情况下,PCA 和 Isomap 一样好。我的第一个问题:为什么 PCA 在这里做得很好?地图不是非线性的吗?
你可能会说这个问题太简单了。这是一个更复杂的例子。让我们介绍两个非线性:非线性潜在空间和非线性映射。在这里,潜在变量的形状像“S”。并且这些地图是 GP 分发的,这意味着如果有地图,每个, 在哪里是基于核函数的协方差矩阵(参见下面的代码 2)。同样,PCA 做得很好。事实上,其数据生成过程完全匹配的 GPLVM似乎与它的 PCA 初始化没有太大偏差:
所以我再次问:这里发生了什么?为什么我不破坏 PCA?
最后,我可以打破 PCA 并仍然从流形学习器中获得一些结构化的唯一方法是,如果我真的将潜在变量“嵌入”到更高维空间中(参见下面的代码 3):
总而言之,我有几个问题我认为与共同的误解有关:
为什么 PCA 在简单的非线性映射(正弦函数)上表现出色?这些地图不是线性的建模假设吗?
为什么 PCA 在双重非线性问题上的表现与 GPLVM 一样好?特别令人惊讶的是,我使用了 GPLVM 的数据生成过程。
为什么第三个案例最终打破了 PCA?这个问题有什么不同?
我很欣赏这是一个广泛的问题,但我希望对这些问题有更多了解的人可以帮助综合和完善它。
编辑:
非线性可分且具有非线性映射的潜在变量上的 PCA:
代码
1.线性潜变量,非线性映射
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
from sklearn.manifold import Isomap
def gen_data():
n_features = 3
n_samples = 500
time = np.arange(1, n_samples+1)
# Latent variable is a straight line.
lat_var = 3 * time[:, np.newaxis]
data = np.empty((n_samples, n_features))
# But mapping functions are nonlinear or nose.
data[:, 0] = np.sin(lat_var).squeeze()
data[:, 1] = np.random.normal(0, 1, size=n_samples)
data[:, 2] = np.random.normal(0, 1, size=n_samples)
return data, lat_var, time
data, lat_var, time = gen_data()
lat_var_pca = PCA(n_components=1).fit_transform(data)
lat_var_iso = Isomap(n_components=1).fit_transform(data)
fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
fig.set_size_inches(20, 5)
ax1.set_title('True')
ax1.scatter(time, lat_var, c=time)
ax2.set_title('PCA')
ax2.scatter(time, lat_var_pca, c=time)
ax3.set_title('Isomap')
ax3.scatter(time, lat_var_iso, c=time)
plt.tight_layout()
plt.show()
2.非线性潜变量,GP分布图
from GPy.models import GPLVM
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import make_s_curve
from sklearn.manifold import Isomap
from sklearn.metrics.pairwise import rbf_kernel
def gen_data():
n_features = 10
n_samples = 500
# Latent variable is 2D S-curve.
lat_var, time = make_s_curve(n_samples)
lat_var = np.delete(lat_var, obj=1, axis=1)
lat_var /= lat_var.std(axis=0)
# And maps are GP-distributed.
mean = np.zeros(n_samples)
cov = rbf_kernel(lat_var)
data = np.random.multivariate_normal(mean, cov, size=n_features).T
return data, lat_var, time
data, lat_var, time = gen_data()
lat_var_pca = PCA(n_components=2).fit_transform(data)
lat_var_iso = Isomap(n_components=2).fit_transform(data)
gp = GPLVM(data, input_dim=2)
gp.optimize()
lat_var_gp = gp.X
fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4)
fig.set_size_inches(20, 5)
ax1.set_title('True')
ax1.scatter(lat_var[:, 0], lat_var[:, 1], c=time)
ax2.set_title('PCA')
ax2.scatter(lat_var_pca[:, 0], lat_var_pca[:, 1], c=time)
ax3.set_title('Isomap')
ax3.scatter(lat_var_iso[:, 0], lat_var_iso[:, 1], c=time)
ax4.set_title('GPLVM')
ax4.scatter(lat_var_gp[:, 0], lat_var_gp[:, 1], c=time)
plt.tight_layout()
plt.show()
3. 嵌入高维空间的非线性潜变量
from GPy.models import GPLVM
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_s_curve
from sklearn.decomposition import PCA
from sklearn.manifold import Isomap
def gen_data():
n_features = 10
n_samples = 500
# Latent variable is 2D S-curve.
lat_var, time = make_s_curve(n_samples)
lat_var = np.delete(lat_var, obj=1, axis=1)
lat_var /= lat_var.std(axis=0)
# And maps are GP-distributed.
data = np.random.normal(0, 1, size=(n_samples, n_features))
data[:, 0] = lat_var[:, 0]
data[:, 1] = lat_var[:, 1]
return data, lat_var, time
data, lat_var, time = gen_data()
lat_var_pca = PCA(n_components=2).fit_transform(data)
lat_var_iso = Isomap(n_components=2).fit_transform(data)
gp = GPLVM(data, input_dim=2)
gp.optimize()
lat_var_gp = gp.X
fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4)
fig.set_size_inches(20, 5)
ax1.set_title('True')
ax1.scatter(lat_var[:, 0], lat_var[:, 1], c=time)
ax2.set_title('PCA')
ax2.scatter(lat_var_pca[:, 0], lat_var_pca[:, 1], c=time)
ax3.set_title('Isomap')
ax3.scatter(lat_var_iso[:, 0], lat_var_iso[:, 1], c=time)
ax4.set_title('GPLVM')
ax4.scatter(lat_var_gp[:, 0], lat_var_gp[:, 1], c=time)
plt.tight_layout()
plt.show()
4. 不能与 GP 分布图线性分离的潜在变量
from GPy.models import GPLVM
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import make_circles
from sklearn.manifold import Isomap
from sklearn.metrics.pairwise import rbf_kernel
def gen_data():
n_features = 20
n_samples = 500
lat_var, time = make_circles(n_samples)
mean = np.zeros(n_samples)
cov = rbf_kernel(lat_var)
data = np.random.multivariate_normal(mean, cov, size=n_features).T
return data, lat_var, time
data, lat_var, time = gen_data()
lat_var_pca = PCA(n_components=2).fit_transform(data)
lat_var_iso = Isomap(n_components=2).fit_transform(data)
gp = GPLVM(data, input_dim=2)
gp.optimize()
lat_var_gp = gp.X
fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4)
fig.set_size_inches(20, 5)
ax1.set_title('True')
ax1.scatter(lat_var[:, 0], lat_var[:, 1], c=time)
ax2.set_title('PCA')
ax2.scatter(lat_var_pca[:, 0], lat_var_pca[:, 1], c=time)
ax3.set_title('Isomap')
ax3.scatter(lat_var_iso[:, 0], lat_var_iso[:, 1], c=time)
ax4.set_title('GPLVM')
ax4.scatter(lat_var_gp[:, 0], lat_var_gp[:, 1], c=time)
plt.tight_layout()
plt.show()