如何用 pandas 处理不同时间序列的变长?

Posted

技术标签:

【中文标题】如何用 pandas 处理不同时间序列的变长?【英文标题】:How to deal with different time series of variable length with pandas? 【发布时间】:2020-09-01 16:30:29 【问题描述】:

我有数据矩阵,其中每一行都被视为时间序列,但长度不同。看起来是这样的:

在文本中:

0 1 2 3 4 5 6 7 8 9

0 12 32 45 67 89 54 23.0 56.0 78.0 98.0

1 34 76 34 89 34 3 NaN NaN NaN NaN

2 76 34 54 12 43 78 56.0 NaN NaN NaN

3 76 56 45 23 43 45 67.0 76.0 67.0 8.0

4 87 9 9 0 89 90 6.0 89.0 NaN NaN

5 23 90 90 32 23 34 56.0 9.0 56.0 87.0

6 23 56 34 3 5 8 7.0 6.0 98.0 NaN

7 32 23 34 6 65 78 67.0 87.0 89.0 87.0

8 12 23 34 32 43 67 45.0 NaN NaN NaN

9 343 76 56 7 8 9 4.0 5.0 8.0 68.0

我曾尝试使用带有代码的 pandas 读取数据:

timeseries=pd.read_excel('timeseries.xlsx',header=None)
######   timeseries   ##############
print(timeseries)

然后我想将每一行数据矩阵传递给时间序列分析模型,该模型将为每个时间序列生成一个值,在传递所有时间序列后,我将得到一个特征向量。

我曾尝试使用以下代码实现:

features=[]
for i,j in timeseries.iterrows():
    row=timeseries.iloc[i]
    model=AR(row.values)
    model_fit=model.fit()
    yhat=model_fit.predict(len(row),len(row))
    features.append(yhat)
fvector=pd.DataFrame(features)
print(fvector)

但我认为这是错误

MissingDataError: exog 包含 inf 或 nans

据我所知,它发生在分析方法限制 NaN 值并引发此错误时,但根据我的情况,每个时间序列都需要被视为分析方法的独立输入,并且应该读取到最后一个实际值每一行。

我该如何解决这个问题?

【问题讨论】:

请不要发布您的数据图片,分享可以复制的实际数据。 完成,感谢您的建议。 在应用模型之前填充缺失值。许多时间序列模型不适用于 NaN 等缺失值。 不,无论如何我都无法插入或插补数据...是否有可能我独立解析每一行,以便 NaN 不会被 pandas 标记? 【参考方案1】:

您需要删除 NaN 并将它们替换为 0 或其他内容:

timeseries.fillna(0, inplace=True)
print(timeseries)
features=[]
for i,j in timeseries.iterrows():
    row=timeseries.iloc[i]
    model=AR(row.values)
    model_fit=model.fit()
    yhat=model_fit.predict(len(row),len(row))
    features.append(yhat)
fvector=pd.DataFrame(features)
print(fvector)

            0
0  100.704274
1    0.000000
2    0.000000
3  -23.468840
4   19.943124
5   37.442981
6    5.771667
7  105.138431
8    0.000000
9  237.903666

【讨论】:

不能用任何值替换 NaN。是否有可能我读取每一行的值,直到其中出现 NaN?【参考方案2】:

您可以使用 NumPy 并将缺失值输入为np.NaN。 然后您可以将数据读取为 NumPy 数组,转置它(因为在 pandas 中,时间序列应该是一列而不是一行),将其转换为 DataFrame,设置 DatetimeIndex 并从那里获取。

例如:

import numpy as np
import pandas as pd

data = np.asarray([[12, 32, 45, 67, 89, 54, 23.0, 56.0, 78.0, 98.0],
                   [34, 76, 34, 89, 34, 3, np.NaN, np.NaN, np.NaN, np.NaN],
                   [76, 34, 54, 12, 43, 78, 56.0, np.NaN, np.NaN, np.NaN],
                   [76, 56, 45, 23, 43, 45, 67.0, 76.0, 67.0, 8.0],
                   [87, 9, 9, 0, 89, 90, 6.0, 89.0, np.NaN, np.NaN],
                   [23, 90, 90, 32, 23, 34, 56.0, 9.0, 56.0, 87.0],
                   [23, 56, 34, 3, 5, 8, 7.0, 6.0, 98.0, np.NaN],
                   [32, 23, 34, 6, 65, 78, 67.0, 87.0, 89.0, 87.0],
                   [12, 23, 34, 32, 43, 67, 45.0, np.NaN, np.NaN, np.NaN],
                   [343, 76, 56, 7, 8, 9, 4.0, 5.0, 8.0, 68.0]])

df = pd.DataFrame(data.T)
df.index = pd.DatetimeIndex(pd.date_range('2020-05-15', periods=10, freq='d'))

df
               0       1       2       3       4       5       6       7       8        9
2020-05-15  12.0    34.0    76.0    76.0    87.0    23.0    23.0    32.0    12.0    343.0
2020-05-16  32.0    76.0    34.0    56.0    9.0     90.0    56.0    23.0    23.0    76.0
2020-05-17  45.0    34.0    54.0    45.0    9.0     90.0    34.0    34.0    34.0    56.0
2020-05-18  67.0    89.0    12.0    23.0    0.0     32.0    3.0     6.0     32.0    7.0
2020-05-19  89.0    34.0    43.0    43.0    89.0    23.0    5.0     65.0    43.0    8.0
2020-05-20  54.0    3.0     78.0    45.0    90.0    34.0    8.0     78.0    67.0    9.0
2020-05-21  23.0    NaN     56.0    67.0    6.0     56.0    7.0     67.0    45.0    4.0
2020-05-22  56.0    NaN     NaN     76.0    89.0    9.0     6.0     87.0    NaN     5.0
2020-05-23  78.0    NaN     NaN     67.0    NaN     56.0    98.0    89.0    NaN     8.0
2020-05-24  98.0    NaN     NaN     8.0     NaN     87.0    NaN     87.0    NaN     68.0

详情请见pandas Time Series documentation.

如果模型函数确实不接受任何缺失值,您可能不得不以某种方式猜测它们。这当然会影响模型的可靠性。请参阅pandas documentation,尤其是df.fillna() 和Wikipedia article on Imputation。

如果适合您的模型,您还可以从上述数据框中提取没有缺失值的单个时间序列。例如。第二栏:

df[1].dropna()
2020-05-15    34.0
2020-05-16    76.0
2020-05-17    34.0
2020-05-18    89.0
2020-05-19    34.0
2020-05-20     3.0
Freq: D, Name: 1, dtype: float64

【讨论】:

【参考方案3】:

您的示例并未提供所有需要的详细信息,例如你写了 与AR无关。

据我了解,您的软件在某些行中抱怨 NaN 值, 所以你应该:

从每一行中消除 NaN 值, 仅处理之后。

这次关于执行速度的另一个细节是,如果你遍历行,那么:

循环的第二个控制值已经包含当前行, 因此没有必要再按索引再读一遍。

所以改变你的代码做如下的事情:

for i, row in timeseries.iterrows():
    row = row.dropna()
    print(f'i: row.size:2  row.values')
    # Any further processing of "row"

当然,print 仅用于演示目的。 将其放入代码的目标版本中。

我怀疑是否用零替换 NaN 值(如建议 在另一个答案中)是正确的方法,因为它可能会“破坏” 你的模型中有一些东西。

编辑

如果您只想处理当前行的“初始”部分,即 正如您在评论中所要求的,直到第一个 Nan(不包括), 将对 dropna() 的调用替换为:

row = row[row.isna().cumsum() == 0]

要检查它是如何工作的,请替换例如带索引的行中的最后一个 NaN 1 具有一些有限值并观察这一行的结果。

【讨论】:

我是否可以读取每一行的值,直到其中出现 NaN?如果是,那么解决方法是什么?

以上是关于如何用 pandas 处理不同时间序列的变长?的主要内容,如果未能解决你的问题,请参考以下文章

pandas 在同一张表(相同的数据框)中,如何用新名称和其他行值的总和对不同的行进行分组

Python的变长参数

Kafka 消息格式中的变长字段(Varints)

Kotlin的变长参数

Kotlin的变长参数

Kotlin的变长参数