首先让我澄清一下这里"稀疏的PCA"表示具有L1惩罚和稀疏加载的PCA,而不是稀疏矩阵上的PCA。
我已经阅读了Zou和Hastie关于稀疏PCA的论文,我已经阅读了sklearn.decomposition.SparsePCA上的文档,我知道如何使用PCA,但我似乎无法理解从SparsePCA获得正确的结果。
即,当L1惩罚为0时,SparsePCA的结果应与PCA一致,但负载相差很大。为了确保我没有弄乱任何超参数,我在R中使用了相同的超参数(收敛容差,最大迭代次数,脊线惩罚,套索惩罚...)和spca'来自' elasticnet',R给了我正确的结果。如果有人有使用此功能的经验,我宁愿不必浏览SparsePCA的源代码,如果我犯了任何错误,可以告诉我。
以下是我生成数据集的方法。这有点令人费解,因为我想要一个特定的马尔可夫决策过程来测试一些强化学习算法。只需将其视为一些非稀疏数据集。
obsvList.add("item1");
cbTest.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Item clicked");
}
});
现在我运行PCA和SparsePCA。当套索惩罚&#39; alpha&#39;为0时,SparsePCA应该给出与PCA相同的结果,但事实并非如此。其他超参数使用R中的elasticnet的默认值设置。如果我使用SparsePCA中的默认值,结果仍然不正确。
import numpy as np
from sklearn.decomposition import PCA, SparsePCA
import numpy.random as nr
def transform(data, TranType=None):
if TranType == 'quad':
data = np.minimum(np.square(data), 3)
if TranType == 'cubic':
data = np.maximum(np.minimum(np.power(data, 3), 3), -3)
if TranType == 'exp':
data = np.minimum(np.exp(data), 3)
if TranType == 'abslog':
data = np.minimum(np.log(abs(data)), 3)
return data
def NewStateGen(OldS, A, TranType, m=0, sd=0.5, nsd=0.1, dim=64):
# dim needs to be a multiple of 4, and preferably a multiple of 16.
assert (dim == len(OldS) and dim % 4 == 0)
TrueDim = dim / 4
NewS = np.zeros(dim)
# Generate new state according to action
if A == 0:
NewS[range(0, dim, 4)] = transform(OldS[0:TrueDim], TranType) + \
nr.normal(scale=nsd, size=TrueDim)
NewS[range(1, dim, 4)] = transform(OldS[0:TrueDim], TranType) + \
nr.normal(scale=nsd, size=TrueDim)
NewS[range(2, dim, 4)] = nr.normal(m, sd, size=TrueDim)
NewS[range(3, dim, 4)] = nr.normal(m, sd, size=TrueDim)
R = 2 * np.sum(transform(OldS[0:int(np.ceil(dim / 32.0))], TranType)) - \
np.sum(transform(OldS[int(np.ceil(dim / 32.0)):(dim / 16)], TranType)) + \
nr.normal(scale=nsd)
if A == 1:
NewS[range(0, dim, 4)] = nr.normal(m, sd, size=TrueDim)
NewS[range(1, dim, 4)] = nr.normal(m, sd, size=TrueDim)
NewS[range(2, dim, 4)] = transform(OldS[0:TrueDim], TranType) + \
nr.normal(scale=nsd, size=TrueDim)
NewS[range(3, dim, 4)] = transform(OldS[0:TrueDim], TranType) + \
nr.normal(scale=nsd, size=TrueDim)
R = 2 * np.sum(transform(OldS[int(np.floor(dim / 32.0)):(dim / 16)], TranType)) - \
np.sum(transform(OldS[0:int(np.floor(dim / 32.0))], TranType)) + \
nr.normal(scale=nsd)
return NewS, R
def MDPGen(dim=64, rep=1, n=30, T=100, m=0, sd=0.5, nsd=0.1, TranType=None):
X_all = np.zeros(shape=(rep*n*T, dim))
Y_all = np.zeros(shape=(rep*n*T, dim+1))
A_all = np.zeros(rep*n*T)
R_all = np.zeros(rep*n*T)
for j in xrange(rep*n):
# Data for a single subject
X = np.zeros(shape=(T+1, dim))
A = np.zeros(T)
R = np.zeros(T)
NewS = np.zeros(dim)
X[0] = nr.normal(m, sd, size=dim)
for i in xrange(T):
OldS = X[i]
# Pick a random action
A[i] = nr.randint(2)
# Generate new state according to action
X[i+1], R[i] = NewStateGen(OldS, A[i], TranType, m, sd, nsd, dim)
Y = np.concatenate((X[1:(T+1)], R.reshape(T, 1)), axis=1)
X = X[0:T]
X_all[(j*T):((j+1)*T)] = X
Y_all[(j*T):((j+1)*T)] = Y
A_all[(j*T):((j+1)*T)] = A
R_all[(j*T):((j+1)*T)] = R
return {'X': X_all, 'Y': Y_all, 'A': A_all, 'R': R_all, 'rep': rep, 'n': n, 'T': T}
nr.seed(1)
MDP = MDPGen(dim=64, rep=1, n=30, T=90, sd=0.5, nsd=0.1, TranType=None)
X = MDP.get('X').astype(np.float32)
当套索罚分大于0时,SparsePCA的结果仍然与R给我的结果完全不同,后者基于人工检查和我从原始论文中学到的内容是正确的。那么,SparsePCA是破碎的,还是我错过了什么?
答案 0 :(得分:1)
经常:有许多不同的配方和实现强>
sklearn正在使用具有不同特征的不同实现。
让我们来看看它们有何区别:
所以看来sklearn至少在基于l2-norm的组件方面做了一些不同的事情(它缺失了)。
这是设计的,因为这是字典学习领域的基本形式:(algorithm-paper linked by sklearn used for implementation)。
很有可能,当稀疏度参数为零时,这种替代公式并不能保证(或根本不关心)模拟经典PCA(这并不令人惊讶,因为这些问题在优化方面存在很大差异-theory和sparsePCA必须驻留在一些基于启发式的算法中,因为问题本身就是NP-hard,ref)。这里的概念通过描述等价定理得到了加强:
答案 1 :(得分:0)
答案没有什么不同。首先,我认为它可能是解算器,但检查不同的求解器,我得到几乎相同的载荷。见:
nr.seed(1)
MDP = MDPGen(dim=16, rep=1, n=30, T=90, sd=0.5, nsd=0.1, TranType=None)
X = MDP.get('X').astype(np.float32)
PCA_model = PCA(n_components=10,svd_solver='auto',tol=1e-6)
PCA_model.fit(X)
SPCA_model = SparsePCA(n_components=10, alpha=0, ridge_alpha=0)
SPCA_model.fit(X)
PC1 = PCA_model.components_[0]/np.linalg.norm(PCA_model.components_[0])
SPC1 = SPCA_model.components_[0].T/np.linalg.norm(SPCA_model.components_[0])
print(np.dot(PC1,SPC1))
import pylab
pylab.plot(PC1)
pylab.plot(SPC1)
pylab.show()