线性判别分析逆变换
Linear Discriminant Analysis inverse transform
我尝试使用 scikit-learn 库中的 Linear Discriminant Analysis,以便对具有 200 多个特征的数据进行降维。但是我在LDAclass.
中找不到inverse_transform
函数
我只想问一下,如何从LDA域中的一个点重建原始数据?
根据@bogatron 和@kazemakase 的回答编辑:
我认为 "original data" 这个词是错误的,我应该使用 "original coordinate" 或 "original space"。我知道如果没有所有 PCA,我们无法重建 原始数据 ,但是当我们构建形状 space 时,我们会在 PCA 的帮助下将数据向下投影到较低的维度。 PCA 尝试仅用 2 或 3 个分量来解释数据,这些分量可以捕获数据的大部分方差,如果我们基于它们重建数据,它应该向我们显示导致这种分离的形状部分。
我再次检查了 scikit-learn LDA 的源代码,我注意到特征向量存储在 scalings_
变量中。当我们使用 svd
求解器时,不可能对特征向量 (scalings_
) 矩阵求逆,但是当我尝试矩阵的伪逆时,我可以重建形状。
这里有两幅图像分别由[4.28,0.52]和[0,0]点重建而成:
我认为,如果有人能深入解释 LDA 逆变换的数学限制,那就太好了。
没有逆变换,因为一般来说,你不能return从低维特征space到你的原始坐标space。
可以把它想象成看投射在墙上的二维影子。您无法从单个阴影返回到 3 维几何体,因为在投影过程中会丢失信息。
为了解决您对 PCA 的评论,请考虑包含 10 个随机 3 维向量的数据集:
In [1]: import numpy as np
In [2]: from sklearn.decomposition import PCA
In [3]: X = np.random.rand(30).reshape(10, 3)
现在,如果我们应用主成分变换 (PCT) 并通过仅保留前 2 个(共 3 个)PC 应用降维,然后应用逆变换,会发生什么情况?
In [4]: pca = PCA(n_components=2)
In [5]: pca.fit(X)
Out[5]:
PCA(copy=True, iterated_power='auto', n_components=2, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
In [6]: Y = pca.transform(X)
In [7]: X.shape
Out[7]: (10, 3)
In [8]: Y.shape
Out[8]: (10, 2)
In [9]: XX = pca.inverse_transform(Y)
In [10]: X[0]
Out[10]: array([ 0.95780971, 0.23739785, 0.06678655])
In [11]: XX[0]
Out[11]: array([ 0.87931369, 0.34958407, -0.01145125])
显然,逆变换并没有重构原始数据。原因是通过丢弃最低的 PC,我们丢失了信息。接下来,让我们看看如果我们保留 all 个 PC 会发生什么(即,我们不应用任何降维):
In [12]: pca2 = PCA(n_components=3)
In [13]: pca2.fit(X)
Out[13]:
PCA(copy=True, iterated_power='auto', n_components=3, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
In [14]: Y = pca2.transform(X)
In [15]: XX = pca2.inverse_transform(Y)
In [16]: X[0]
Out[16]: array([ 0.95780971, 0.23739785, 0.06678655])
In [17]: XX[0]
Out[17]: array([ 0.95780971, 0.23739785, 0.06678655])
在这种情况下,我们能够重建原始数据,因为我们没有丢弃任何信息(因为我们保留了所有 PC)。
LDA的情况更糟,因为可以保留的最大组件数不是200(你输入数据的特征数);相反,您可以保留的最大组件数是 n_classes - 1
。因此,例如,如果您正在处理二元分类问题 (2 类),则 LDA 变换将从 200 个输入维度下降到仅一个维度。
LDA 的逆运算不一定有意义,因为它丢失了很多信息。
为了进行比较,请考虑 PCA。这里我们得到一个用于转换数据的系数矩阵。我们可以通过从矩阵中剥离行来进行降维。为了进行逆变换,我们首先反转完整矩阵,然后删除与删除的行对应的列。
LDA 没有给我们一个完整的矩阵。我们只得到一个不能直接反转的简化矩阵。可以采用伪逆,但这比我们拥有完整矩阵的效率要低得多。
考虑一个简单的例子:
C = np.ones((3, 3)) + np.eye(3) # full transform matrix
U = C[:2, :] # dimensionality reduction matrix
V1 = np.linalg.inv(C)[:, :2] # PCA-style reconstruction matrix
print(V1)
#array([[ 0.75, -0.25],
# [-0.25, 0.75],
# [-0.25, -0.25]])
V2 = np.linalg.pinv(U) # LDA-style reconstruction matrix
print(V2)
#array([[ 0.63636364, -0.36363636],
# [-0.36363636, 0.63636364],
# [ 0.09090909, 0.09090909]])
如果我们有完整的矩阵,我们会得到一个不同的逆变换 (V1
) 与如果我们简单地反转变换 (V2
)。 那是因为在第二种情况下,我们丢失了有关丢弃组件的所有信息。
您已收到警告。如果你还想做逆LDA变换,这里有一个函数:
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.utils.validation import check_is_fitted
from sklearn.utils import check_array, check_X_y
import numpy as np
def inverse_transform(lda, x):
if lda.solver == 'lsqr':
raise NotImplementedError("(inverse) transform not implemented for 'lsqr' "
"solver (use 'svd' or 'eigen').")
check_is_fitted(lda, ['xbar_', 'scalings_'], all_or_any=any)
inv = np.linalg.pinv(lda.scalings_)
x = check_array(x)
if lda.solver == 'svd':
x_back = np.dot(x, inv) + lda.xbar_
elif lda.solver == 'eigen':
x_back = np.dot(x, inv)
return x_back
iris = datasets.load_iris()
X = iris.data
y = iris.target
target_names = iris.target_names
lda = LinearDiscriminantAnalysis()
Z = lda.fit(X, y).transform(X)
Xr = inverse_transform(lda, Z)
# plot first two dimensions of original and reconstructed data
plt.plot(X[:, 0], X[:, 1], '.', label='original')
plt.plot(Xr[:, 0], Xr[:, 1], '.', label='reconstructed')
plt.legend()
你看,逆变换的结果与原始数据没有太大关系(嗯,可以猜测投影的方向)。相当一部分变体已经永远消失了。
我尝试使用 scikit-learn 库中的 Linear Discriminant Analysis,以便对具有 200 多个特征的数据进行降维。但是我在LDAclass.
中找不到inverse_transform
函数
我只想问一下,如何从LDA域中的一个点重建原始数据?
根据@bogatron 和@kazemakase 的回答编辑:
我认为 "original data" 这个词是错误的,我应该使用 "original coordinate" 或 "original space"。我知道如果没有所有 PCA,我们无法重建 原始数据 ,但是当我们构建形状 space 时,我们会在 PCA 的帮助下将数据向下投影到较低的维度。 PCA 尝试仅用 2 或 3 个分量来解释数据,这些分量可以捕获数据的大部分方差,如果我们基于它们重建数据,它应该向我们显示导致这种分离的形状部分。
我再次检查了 scikit-learn LDA 的源代码,我注意到特征向量存储在 scalings_
变量中。当我们使用 svd
求解器时,不可能对特征向量 (scalings_
) 矩阵求逆,但是当我尝试矩阵的伪逆时,我可以重建形状。
这里有两幅图像分别由[4.28,0.52]和[0,0]点重建而成:
我认为,如果有人能深入解释 LDA 逆变换的数学限制,那就太好了。
没有逆变换,因为一般来说,你不能return从低维特征space到你的原始坐标space。
可以把它想象成看投射在墙上的二维影子。您无法从单个阴影返回到 3 维几何体,因为在投影过程中会丢失信息。
为了解决您对 PCA 的评论,请考虑包含 10 个随机 3 维向量的数据集:
In [1]: import numpy as np
In [2]: from sklearn.decomposition import PCA
In [3]: X = np.random.rand(30).reshape(10, 3)
现在,如果我们应用主成分变换 (PCT) 并通过仅保留前 2 个(共 3 个)PC 应用降维,然后应用逆变换,会发生什么情况?
In [4]: pca = PCA(n_components=2)
In [5]: pca.fit(X)
Out[5]:
PCA(copy=True, iterated_power='auto', n_components=2, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
In [6]: Y = pca.transform(X)
In [7]: X.shape
Out[7]: (10, 3)
In [8]: Y.shape
Out[8]: (10, 2)
In [9]: XX = pca.inverse_transform(Y)
In [10]: X[0]
Out[10]: array([ 0.95780971, 0.23739785, 0.06678655])
In [11]: XX[0]
Out[11]: array([ 0.87931369, 0.34958407, -0.01145125])
显然,逆变换并没有重构原始数据。原因是通过丢弃最低的 PC,我们丢失了信息。接下来,让我们看看如果我们保留 all 个 PC 会发生什么(即,我们不应用任何降维):
In [12]: pca2 = PCA(n_components=3)
In [13]: pca2.fit(X)
Out[13]:
PCA(copy=True, iterated_power='auto', n_components=3, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
In [14]: Y = pca2.transform(X)
In [15]: XX = pca2.inverse_transform(Y)
In [16]: X[0]
Out[16]: array([ 0.95780971, 0.23739785, 0.06678655])
In [17]: XX[0]
Out[17]: array([ 0.95780971, 0.23739785, 0.06678655])
在这种情况下,我们能够重建原始数据,因为我们没有丢弃任何信息(因为我们保留了所有 PC)。
LDA的情况更糟,因为可以保留的最大组件数不是200(你输入数据的特征数);相反,您可以保留的最大组件数是 n_classes - 1
。因此,例如,如果您正在处理二元分类问题 (2 类),则 LDA 变换将从 200 个输入维度下降到仅一个维度。
LDA 的逆运算不一定有意义,因为它丢失了很多信息。
为了进行比较,请考虑 PCA。这里我们得到一个用于转换数据的系数矩阵。我们可以通过从矩阵中剥离行来进行降维。为了进行逆变换,我们首先反转完整矩阵,然后删除与删除的行对应的列。
LDA 没有给我们一个完整的矩阵。我们只得到一个不能直接反转的简化矩阵。可以采用伪逆,但这比我们拥有完整矩阵的效率要低得多。
考虑一个简单的例子:
C = np.ones((3, 3)) + np.eye(3) # full transform matrix
U = C[:2, :] # dimensionality reduction matrix
V1 = np.linalg.inv(C)[:, :2] # PCA-style reconstruction matrix
print(V1)
#array([[ 0.75, -0.25],
# [-0.25, 0.75],
# [-0.25, -0.25]])
V2 = np.linalg.pinv(U) # LDA-style reconstruction matrix
print(V2)
#array([[ 0.63636364, -0.36363636],
# [-0.36363636, 0.63636364],
# [ 0.09090909, 0.09090909]])
如果我们有完整的矩阵,我们会得到一个不同的逆变换 (V1
) 与如果我们简单地反转变换 (V2
)。 那是因为在第二种情况下,我们丢失了有关丢弃组件的所有信息。
您已收到警告。如果你还想做逆LDA变换,这里有一个函数:
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.utils.validation import check_is_fitted
from sklearn.utils import check_array, check_X_y
import numpy as np
def inverse_transform(lda, x):
if lda.solver == 'lsqr':
raise NotImplementedError("(inverse) transform not implemented for 'lsqr' "
"solver (use 'svd' or 'eigen').")
check_is_fitted(lda, ['xbar_', 'scalings_'], all_or_any=any)
inv = np.linalg.pinv(lda.scalings_)
x = check_array(x)
if lda.solver == 'svd':
x_back = np.dot(x, inv) + lda.xbar_
elif lda.solver == 'eigen':
x_back = np.dot(x, inv)
return x_back
iris = datasets.load_iris()
X = iris.data
y = iris.target
target_names = iris.target_names
lda = LinearDiscriminantAnalysis()
Z = lda.fit(X, y).transform(X)
Xr = inverse_transform(lda, Z)
# plot first two dimensions of original and reconstructed data
plt.plot(X[:, 0], X[:, 1], '.', label='original')
plt.plot(Xr[:, 0], Xr[:, 1], '.', label='reconstructed')
plt.legend()
你看,逆变换的结果与原始数据没有太大关系(嗯,可以猜测投影的方向)。相当一部分变体已经永远消失了。