具有多个时间序列的 PCA 作为具有 sklearn 的一个实例的特征

PCA with several time series as features of one instance with sklearn

我想在一个数据集上应用 PCA,其中我有 20 个时间序列作为一个实例的特征。我有大约 1000 个此类实例,我正在寻找一种降低维度的方法。对于每个实例,我都有一个 pandas 数据框,例如:

import pandas as pd
import numpy as np
df = pd.DataFrame(data=np.random.normal(0, 1, (300, 20)))

有没有办法在 所有 个实例上使用 sklearn.fit,每个实例都有一组时间序列作为特征 space。我的意思是我可以分别对所有实例应用 sklearn.fit,但我希望所有实例都使用相同的主成分。

有办法吗?到目前为止,我唯一不满意的想法是将一个实例的所有这些系列附加到一个实例,这样我就有了一个实例的时间序列。

首先,我建议看一下this link,以便更好地了解 PCA 分析和数据序列。

请注意,如果您有 pandas 1000 个实例,您的数据需要作为 numpy 数组更容易地处理。你会有类似下面的东西:

# your 1000 pandas instances
instances = [pd.DataFrame(data=np.random.normal(0, 1, (300, 20))) for _ in range(1000)]
# transformation to be able to process more easily the data as a numpy array
data=np.array([d.values for d in instances]) 

也就是说,让我们解决 2 种不同的解决方案。

简单的解决方案

这就是说,最简单的解决方案是忽略你有一个时间序列,只是连接信息以执行 PCA 分析与所有

import numpy as np
from sklearn.decomposition import PCA
data = np.random.randn(1000, 300, 20) # n_instances, n_steps, n_features
# combine the features and the steps, then
# you perform PCA for your 1000 instances
preprocessed = data.reshape((1000, 20*300))
pca = PCA(n_components=100)
pca.fit(preprocessed)
# test it in one sample
sample = pca.transform(preprocessed[0].reshape(1,-1))

傅立叶变换的变化

另一种解决方案是使用傅立叶来尝试从您的时间序列中获取更多信息。

import numpy as np
from sklearn.decomposition import PCA
data = np.random.randn(1000, 300, 20) # n_instances, n_steps, n_features
# perform a fast fourier transform
preprocessed_1 = np.fft.fft(data,axis=1)
# combine the features and the steps, then
# you perform PCA for your 1000 instances
preprocessed_2 = preprocessed_1.reshape((1000, 20*300))
pca = PCA(n_components=100)
pca.fit(preprocessed_2)
# test it in one sample
pca.transform(preprocessed_2[0].reshape(1,-1))

注意:请注意,对于这两种情况,我的意思是每个时间序列的长度都相同。

将 2D 特征展平为 1D 特征,然后使用这个新特征集执行 PCA。

假设 X 持有整个 1000 个实例:

from sklearn.decomposition import PCA
X = X.reshape(1000, -1)
pca = PCA(n_components=250)
pca.fit(X)

您可以通过将每个实例传递给 LSTM 来进一步提高性能,以获得将整个数据帧汇总为低维向量表示的向量,将它们展平,然后进一步用于执行 PCA。

数据集中存在基于时间序列的特征。将一个实例的所有系列附加到一个系列,将破坏时间序列的基础属性。

为了在降维后保留时间序列 属性,您需要从现有特征生成新的时间序列特征。

data = np.random.randn(1000, 300, 20)      #instance x #timestamp x #feature
pre_data = data.reshape((1000*300, 20))    #samples               x #features
pca = PCA(n_components=5)                  #features in transformed data
pca.fit(pre_data)
instance_new = pca.transform(data[0])

在这里,每个时间戳都会从原始特征生成五个转换后的特征,因此新特征将与原始特征具有相同的时间戳

我不觉得其他答案令人满意。主要是因为你应该同时考虑数据的时间序列结构和横截面信息。您不能简单地将每个实例的特征视为一个系列。这样做,将不可避免地导致信息丢失,并且简单地说,在统计上是错误的。

也就是说,如果你真的需要做PCA,你至少应该保留时间序列信息:

PCA

之后我们将数据转换成一个numpy数组:

# your 1000 pandas instances
instances = [pd.DataFrame(data=np.random.normal(0, 1, (300, 20))) for _ in range(1000)]
# transformation to be able to process more easily the data as a numpy array
data=np.array([d.values for d in instances]) 

这使得应用 PCA 的方式更容易:

reshaped_data = data.reshape((1000*300, 20))    # create one big data panel with 20 series and 300.000 datapoints
n_comp=10                                       #choose the number of features to have after dimensionality reduction
pca = PCA(n_components=n_comp)                  #create the pca object       
pca.fit(pre_data)                               #fit it to your transformed data
transformed_data=np.empty([1000,300,n_comp])
for i in range(len(data)):
     transformed_data[i]=pca.transform(data[i])           #iteratively apply the transformation to each instance of the original dataset

最终输出形状:transformed_data.shape: Out[]: (1000,300,n_comp).

请问

但是,您可以(并且我认为应该)使用偏最小二乘 PLS 从特征矩阵构造因子。这也将进一步降低维度。

假设您的数据具有以下形状。 T=1000, N=300, P=20.

那么我们有y=[T,1],X=[N,P,T].

现在,很容易理解,要实现这一点,我们需要将矩阵设置为 conformable for multiplication。在我们的例子中,我们将有:y=[T,1]=[1000,1], Xpca=[T,P*N]=[1000,20*300]

直觉上,我们正在做的是为每个 P=20[ 的每个滞后 (299=N-1) 创建一个新特征=93=]基本功能。

即对于给定的实例 i,我们将有这样的东西:

实例i : x1,i,x1,i-1,...,x1,i-j , x2,i, x2,i-1,..., x2,i-j,...,xP,i,xP,i-1,...,xP, i-jj=1,...,N-1:

现在,python 中 PLS 的实现非常简单。

# your 1000 pandas instances
instances = [pd.DataFrame(data=np.random.normal(0, 1, (300, 20))) for _ in range(1000)]
# transformation to be able to process more easily the data as a numpy array
data=np.array([d.values for d in instances]) 

# reshape your data:
reshaped_data = data.reshape((1000, 20*300))

from sklearn.cross_decomposition import PLSRegression

n_comp=10
pls_obj=PLSRegression(n_components=n_comp)
factorsPLS=pls_obj.fit_transform(reshaped_data,y)[0] 
factorsPLS.shape
Out[]: (1000, n_comp)

PLS 在做什么?

为了让事情更容易掌握,我们可以看看 three-pass regression filter (working paper here) (3PRF)。 Kelly 和 Pruitt 表明 PLS 只是他们 3PRF 的特例:

()

其中 Z 表示代理矩阵。我们没有这些,但幸运的是,凯利和普鲁伊特已经证明我们可以没有它。我们需要做的就是确保回归器(我们的特征)是标准化的,并且 运行 前两个回归没有截距。这样,将自动选择代理。

所以,简而言之,PLS 允许您

  1. 实现比PCA更进一步的降维
  2. 在创建因子时考虑每个序列的特征和时间序列信息之间的横截面变异性。