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

时间:2018-09-21 18:29:23

标签: python scikit-learn time-series pca

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

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

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

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

4 个答案:

答案 0 :(得分:4)

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

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

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], X pca = [T,P * N] = [1000,20 * 300]

直观上,我们要做的是为每个 P = 20 基本功能的每个滞后时间( 299 = N-1 )创建一个新功能。 / p>

即对于给定的 i 实例,我们将具有以下内容:

实例 i : x 1,i ,x 1,i-1 ,...,x 1,ij ,x 2,i < / sub>,x 2,i-1 ,...,x 2,ij ,...,x P,i , x P,i-1 ,...,x P,ij j = 1,...,N-1 :< / p>

现在,在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的特例:

The three steps

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

因此,简而言之,PLS允许您

  1. 与PCA相比,尺寸进一步减小。
  2. 在创建因子时要考虑特征之间的横截面变异性和每个序列的时间序列信息。

答案 1 :(得分:0)

First of all, I would recommend to see the this link to have a better understanding of PCA analysis and data series.

Please take into account that if you have pandas 1000 instances, your data needs to be processed to be more easily as a numpy array. You'd have something like the following:

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

This said, let's tackle 2 different solutions.

Simple Solution

This said, the easiest solution is to ignore that you have a time series and just concatenate the information to perform the PCA analysis with all

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

Variation with Fourier Transform

Another solution could be by using fourier to try to get more information from your time series.

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

Note: be careful, for both cases I'm implying that you have the same length for every time series.

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

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

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

在每个时间戳下,将从原始特征生成五个变换特征,因此新特征将具有与原始特征相同的时间戳