【问题标题】:PCA with several time series as features of one instance with sklearn具有多个时间序列的 PCA 作为具有 sklearn 的一个实例的特征
【发布时间】:2019-02-26 04:39:56
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: python scikit-learn time-series pca


    【解决方案1】:

    首先,我建议您查看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))
    

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

    【讨论】:

      【解决方案2】:

      将 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。

      【讨论】:

      • 这是个坏人。 PCA 试图捕捉最大方差的方向。一个接一个地合并两个特征会带走数据集的方差。更重要的是,你无法做到这一点的时间序列数据集
      • 感谢@Justice_Lords 我错过了那部分,感谢您指出
      【解决方案3】:

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

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

      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])
      

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

      【讨论】:

        【解决方案4】:

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

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

        主成分分析

        silgon之后,我们将数据转换成一个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

        但是,您可以(并且在我看来应该)使用偏最小二乘法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) 创建一个新特征。

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

        实例i: x1,i, x1,i-1,..., x1,ij, x2,i, x2,i-1,..., x2,ij,..., xP,i, xP,i-1,..., xP,ij with j=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(工作文件here)(3PRF)。 Kelly 和 Pruitt 表明 PLS 只是他们 3PRF 的一个特例:

        ()

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

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

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

        【讨论】:

          猜你喜欢
          • 2019-03-11
          • 2019-10-21
          • 2021-03-01
          • 1970-01-01
          • 2019-05-30
          • 1970-01-01
          • 2021-02-02
          • 1970-01-01
          • 2019-12-22
          相关资源
          最近更新 更多