时间序列存储要素

前言

这篇文章的内容其实很浅显,主要是为了明晰一下时间序列的要素是什么,以及尝试如何规范化地产生和存储时间序列。

时间序列概述

时间序列(英语:time series)是一组按照时间发生先后顺序进行排列的数据点序列,如果我们将数据的来源点称之为“变量”,那么时间序列就是这些变量在不同时刻的样本值。

时间序列广泛应用于数理统计、信号处理、模式识别、计量经济学、数学金融、天气预报、地震预测、脑电图、控制工程、航空学、通信工程以及绝大多数涉及到时间数据测量的应用科学与工程学。

认识时间序列数据

数据是分析的前提

时间序列分析,即利用各种手段对时间序列数据进行建模、挖掘,其目的无非三种:

  • 理解过去的规律;
  • 认识现在的状态;
  • 预测未来的变化。

时间序列分析的手段千变万化,但是无论是什么手段、出于哪种目的,其核心都是历史数据的分析。因此,对历史数据的收集、清洗、归集是时间序列分析的重要环节。

不同问题对于数据的要求自然是各有侧重,但是基本的要求是共通的,简单概括为以下方面:

  • 合理的变量维度,太少缺乏解释力,太多则可能过拟合或维数灾难;
  • 足够的时间长度,时间越长则收集的数据越丰富;
  • 适当的采样频率,时间序列其实是对连续过程的离散化,应当与过程的动态特性相匹配,太低固然会遗漏信息,太高并未必增加信息反而可能会引入噪声;
  • 充分的状态激励,此处“状态激励”,是指时间序列的数据分布、模式能够充分反映其变化的内在激励机制。

时间序列存储要素

承上面的分析可知,在存储时间序列时应当包括以下要素:

  • 变量名称
  • 变量维数
  • 样本长度
  • 采样频率
  • 时间戳
  • 数据标签

此外,如果有关于数据模态、数据模型等的信息也应当一并存储。

Roy-Liechenstein-Look-Mickey-1961-National-Galley-of-Art-Washinton-DC-USA

时间序列产生示例

很多时候时间序列并不是随手可得的,为了后续开发测试的方便,这里提供一个伪造时间序列的思路。

数据序列参数

以最简单的情况,平稳单一模态多变量时间序列为例。应当有以下参数:

  • 变量名,variable_name;
  • 变量维数,variable_dim;
  • 样本长度,obs_size;
  • 采样频率,samp_interval;
  • 时间戳,obs_timestamp

生成时间标签

  1. 利用pandas.data_range()方法产生DatetimeIndex
  2. 利用DateimeIndex.format()将时间索引转换为字符串列表。
1
2
date_range = pd.date_range(start=start, end=end, freq=interval, tz=tz_info, closed=closed).format()
date_range[:5]
['2020-01-01 00:00:00+00:00',
 '2020-01-01 00:00:10+00:00',
 '2020-01-01 00:00:20+00:00',
 '2020-01-01 00:00:30+00:00',
 '2020-01-01 00:00:40+00:00']

产生序列数据

产生变量名

1
2
3
4
variable_list = []
for i in range(variable_dim):
variable_list.append(f'variable_{i}')
variable_list[:5]
['variable_0', 'variable_1', 'variable_2', 'variable_3', 'variable_4']

产生样本

1
2
3
4
5
6
obs_size = len(date_range)

mean = np.zeros(variable_dim)
obs = np.random.multivariate_normal(mean,cov,obs_size)
data = dict(zip(variable_list,obs.T.tolist()))
data.keys()
dict_keys(['variable_0', 'variable_1', 'variable_2', 'variable_3', 'variable_4', 'variable_5', 'variable_6', 'variable_7', 'variable_8', 'variable_9'])

存储为JSON格式

1
2
3
4
5
6
7
8
9
10
11
data_dict = {
'variable_list': variable_list,
'variable_dim': variable_dim,
'start': start,
'end': end,
'interval': interval,
'obs_size': obs_size,
'time_index': date_range,
'data': data,
}
json.dumps(data_dict)

结果呈现

1
2
3
4
5
6
7
8
9
import json
import pandas as pd
time_index = pd.DatetimeIndex(result['time_index'])
result = json.loads(generate_fake_ts_data(interval='1min'))
result.keys()
import matplotlib.pyplot as plt
plt.figure(figsize=(16,12))
plt.plot(time_index, result['data']['variable_0'])
plt.show()

output_22_0

Tips

DatetimeIndex转Timestamp

提供一种更加高效的方法:利用,DatetimeIndex.astype(np.int64)转为纳秒数;

1
2
date_range = pd.date_range(start='20200202', end='20200203', freq='1min', tz='utc', closed='left')
date_range.astype(np.int64)//1e9
Float64Index([1580601600.0, 1580601660.0, 1580601720.0, 1580601780.0,
              1580601840.0, 1580601900.0, 1580601960.0, 1580602020.0,
              1580602080.0, 1580602140.0,
              ...
              1580687400.0, 1580687460.0, 1580687520.0, 1580687580.0,
              1580687640.0, 1580687700.0, 1580687760.0, 1580687820.0,
              1580687880.0, 1580687940.0],
             dtype='float64', length=1440)

打印错误信息到stderr

可以像使用print()一样使用eprint()

1
2
3
4
import sys

def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)

小结

关于时间序列的研究多如牛毛,本来只是从数据存储的角度出发谈了一些自己关于时间序列规范化存储的思路,偏颇和不当之处在所难免,也希望能够不断完善提高。