sklearn中的IncrementalPCA,主要是为了解决单机内存限制的。有时候样本数量过大,直接去拟合数据会让内存爆炸的,此时可用IncrementalPCA来解决这个问题。IncrementalPCA先将数据分成多个batch,然后对每个batch依次调用partial_fit,这样一步步得到最终的样本最优降维。那么IncrementalPCA的工作原理是什么呢?看sklearn中的源码是最好的方式了!
- 判断参数n_components的输入是否规范:n_components要满足两个要求,一是在区间[1, n_features]之间,二是要小于输入样本数量n_samples。
- 对重要的中间变量的更新,包括col_mean、col_var和n_total_samples。其中,col_mean、col_var是将当前batch的样本的mean迭代到之前已经训练的总样本的mean和variance上,而n_total_samples则是记录了加上这一batch后参与训练的总样本数量。具体代码可以看这一部分源码。
- 接下来就是IncrementalPCA的核心代码了,主要是对当前输入的batch数据
进行“修改”,使得新得到的训练样本
还包含之前已经参与训练的样本数据的信息。代码如下图:
IncrementalPCA核心代码.png进行简单的白化(减去均值);如果不是0,那就需要创造一个新的矩阵
,
不仅包括新的输入信息,还包括过去的训练数据信息。源码中的做法是在当前输入样本
的基础上堆叠上两部分新的矩阵。一个是self.n_singular_values_.reshape((-1, 1)) * self.components_,其中n_singular_values_保存的是部分奇异值,维度是[n_components],components_保存的是分解后的V矩阵的部分,维度是[n_components, n_features](其实components_就是样本矩阵的主成分,将components_与样本矩阵进行矩阵乘法就可以得到降维后的矩阵,所以PCA降维的实现是可以基于SVD实现的。事实上,几乎所有PCA都是利用SVD求主成分的,而不是利用样本协方差矩阵求主成分);另一部分是mean_correction,由名字可以看出是对矩阵均值的修正。也就是说,第一部分self.n_singular_values_.reshape((-1, 1)) * self.components_的加入带来之前的样本信息,第二部分mean_correction只是为了平衡第一部分加入后给矩阵均值带来的偏移。
- 然后就是对新的训练矩阵
的主成分提取,源代码如下:
U, S, V = linalg.svd(X, full_matrices=False)
U, V = svd_flip(U, V, u_based_decision=False)
这里svd_flip函数的作用我还不太清楚,源代码中的解释是
其具体代码如下图:"Sign correction to ensure deterministic output from SVD. Adjusts the columns of u and the rows of v such that the loadings in the columns in u that are largest in absolute value are always positive."
说实话,这里我还不是很理解。先挖个坑,以后再填。
- 最后就是IncrementalPCA的属性更新了,包括n_samples_seen_、components_、singular_value_、mean_、var_等。
虽然在.transform()函数中只判断了components_和mean_是否为空,但是由上面对partial_fit()函数源码的分析可知,n_samples_seen_、components_、singular_value_、mean_、var_这几个参数是很重要的。所以如果要保存一个训练好的IncrementalPCA模型,就需要保存n_samples_seen_、components_、singular_value_、mean_、var_这5种属性。
所以,我们可以利用IncrementalPCA对大规模数据集进行间断式训练。保存n_samples_seen_、components_、singular_value_、mean_、var_这5种属性,然后直接赋给新的IncrementalPCA模型就相当于已经训练好的PCA模型。
2019年1月15号补充:今天跑代码时发现只存上述5种属性是不够的,在IncrementalPCA.transform()中尽管没有判断PCA模型是否有属性explained_variance_,但是在这里却直接用到了,所以这个属性也是要保存的。为了避免后面使用训练好的PCA模型的过程中出现问题,还是将fit过程中更新的所有属性都保存下来,也就是下图中这些属性。
- n_samples_seen_,已经参与训练的数据量
- components_,主成分
- singular_values_,奇异值
- mean_,待降维矩阵的均值
- var_,待降维矩阵的方差
- explained_variance_
- explained_variance_ratio_
- noise_variance_