Spark 中的 PCA 输出与 scikit-learn 不匹配

Posted

技术标签:

【中文标题】Spark 中的 PCA 输出与 scikit-learn 不匹配【英文标题】:PCA output in Spark doesn't matches with scikit-learn 【发布时间】:2018-05-26 00:34:05 【问题描述】:

我正在 Spark ML 中尝试 PCA(主成分分析)。

data = [(Vectors.dense([1.0, 1.0]),),
  (Vectors.dense([1.0, 2.0]),),
  (Vectors.dense([4.0, 4.0]),), 
  (Vectors.dense([5.0, 4.0]),)]

df = spark.createDataFrame(data, ["features"])
pca = PCA(k=1, inputCol="features", outputCol="pcaFeatures")
model = pca.fit(df)
transformed_feature = model.transform(df)
transformed_feature.show()

输出:

+---------+--------------------+
| features|         pcaFeatures|
+---------+--------------------+
|[1.0,1.0]|[-1.3949716649258...|
|[1.0,2.0]|[-1.976209858644928]|
|[4.0,4.0]|[-5.579886659703326]|
|[5.0,4.0]|[-6.393620130910061]|
+---------+--------------------+

当我在 scikit-learn 中对相同数据尝试 PCA 时,结果不同

X = np.array([[1.0, 1.0], [1.0, 2.0], [4.0, 4.0], [5.0, 4.0]])
pca = PCA(n_components=1)
pca.fit(X)
X_transformed = pca.transform(X)
for x,y in zip(X ,X_transformed):
    print(x,y)

输出:

[ 1.  1.] [-2.44120041]
[ 1.  2.] [-1.85996222]
[ 4.  4.] [ 1.74371458]
[ 5.  4.] [ 2.55744805]

如您所见,输出有所不同。

为了验证结果,我用数学方法计算了相同数据的 PCA。我从 scikit-learn 得到了相同的结果。以下 sn-p 是第一个数据点 (1.0,1.0) 的 pca 转换计算:

如您所见,它与 scikit 学习结果相匹配。

spark ML 似乎没有从数据向量 X 中减去平均向量 MX,即它使用 Y = A*(X) 代替 Y = A*(X-MX)

对于点 (1.0,1.0):

Y = (0.814*1.0)+(0.581*1.0)) = 1.395 

这与我们使用 spark ML 得到的结果相同。

是 Spark ML 给出了错误的结果还是我遗漏了什么?

【问题讨论】:

为什么不尝试特征的均值减法,甚至在 PCA 之前标准化你的特征,然后进行比较? 我稍微更新了答案,希望对你有用。 【参考方案1】:

在 Spark 中,PCA 转换不会自动为您缩放输入数据。在应用该方法之前,您需要自己处理好这一点。要对数据的均值进行归一化,StandardScaler 可以按以下方式使用:

scaler = StandardScaler(inputCol="features", outputCol="scaledFeatures",
                    withStd=False, withMean=True)
scaled_df = scaler.fit(df).transform(df)

PCA 方法随后可以以与之前相同的方式应用于scaled_df,结果将与 scikit-learn 给出的结果相匹配。


我建议使用 Spark ML 管道来简化流程。要同时使用标准化和 PCA,它可能如下所示:

scaler = StandardScaler(inputCol="features", outputCol="scaledFeatures",
                    withStd=False, withMean=True)
pca = PCA(k=1, inputCol=scaler.getOutputCol(), outputCol="pcaFeatures")
pipeline = Pipeline(stages=[scaler , pca])

model = pipeline.fit(df)
transformed_feature = model.transform(df)

【讨论】:

感谢您在应用 PCA 之前指出功能分类。但仍然输出不匹配。似乎这只是 Spark ML 使用 Y = A*(X) 和 scikit-learn Y = A*(X-MX) 的实现差异。 @DeepakKumar:是的,有一个实现差异。但这并没有错。在 Spark 中,您需要按照答案中的说明自己进行标准化。进行均值归一化后数字是否不匹配? 幅度明智的数字匹配 (2.44,1.85,-1.74,-2.5) 但符号正好相反。 @DeepakKumar:在 PCA 中,向量的符号可以翻转而不改变结果。 Sklearn 在某些情况下会翻转标志,您可以在此处看到一个很好的答案:***.com/questions/44765682/…。

以上是关于Spark 中的 PCA 输出与 scikit-learn 不匹配的主要内容,如果未能解决你的问题,请参考以下文章

用STC单片机的PCA做定时器,输出PWM

机器学习实战基础(二十三):sklearn中的降维算法PCA和SVD PCA与SVD 之 PCA中的SVD

机器学习实战基础(二十三):sklearn中的降维算法PCA和SVD PCA与SVD 之 PCA中的SVD

PCL:主成分分析(PCA)原理与实现

XGBoost 与 GridSearchCV、缩放、PCA 和 sklearn 管道中的 Early-Stopping

STC15系列CCP/PWM/PCA介绍