时序分析 48 – 时序数据转为空间数据 (七)
马尔可夫转换场 python 实践(下)
… 接上
从MTF到图模型
从MTF中我们可以生成图 𝐺 = ( 𝑉 , 𝐸 ) 𝐺=(𝑉,𝐸) G=(V,E) ,节点V和时间 𝑖 是一一对应的关系。我们有两种思路来对这里面的信息进行编码,
- Flow Encoding: 流动编码帮助我们观察大的信息流在什么地方出现。我们把时间流映射为图中的节点,使用颜色梯度来表示时间序列中的每个节点,而图中的边是由MTF中的权重决定的。
- Modularity Encoding: 模块度是图分析中一种非常重要的模式,它被经常用来定位图中的一些局部特殊结构,是常用的一种社区发现算法。这里我们把模块标签分配给每一个节点,并且给予特定的颜色,节点的大小代表聚类系数,边的颜色是其目标节点的模块标签。
简单回顾一下模块度概念:
Q
=
Σ
c
[
Σ
i
n
2
m
−
(
Σ
t
o
t
2
m
)
2
]
Q=\Sigma_c[\frac{\Sigma_{in}}{2m}-(\frac{\Sigma_{tot}}{2m})^2]
Q=Σc[2mΣin−(2mΣtot)2]
其实图计算中的模块划分或者说社区发现算法类似于非监督学习中的聚类算法,主要是寻找一种模块划分方案是的模块内部的节点连接比较紧密而模块之间的连接比较松散。上面的公式中的
Q
Q
Q 是评估模块划分是否最优的优化目标(使
Q
Q
Q 最大)。
Q
Q
Q 的含义是加总每个模块的内部聚合度评估减去其与外部连接强度的评估的值。
下面我们将分解建立图分析的步骤,以求更好地理解其特性同时更好的洞察时序数据中所蕴涵的信息。总共分位四步:
- 构建MTF并从其产生图
- 计算图分区和模块并将其编码用来表示图
- 画出图
- 将分区或者模块映射回原始的时序
第一步:构建图
我们从MTF中构建图并画出这个原始图。
G = tsia.network_graph.get_network_graph(tag_mtf[0])
tsia.plot.plot_network_graph(G, title="Network graph")
第二步:计算分区和模块用来表示图
上面的图并没有给我们带来多少信息,我们将采用模块划分算法得到其最佳划分并对图进行编码。
encoding = tsia.network_graph.get_modularity_encoding(G)
同时,计算一些统计量。
stats = tsia.network_graph.compute_network_graph_statistics(G)
stats
{
'Diameter': 1,
'Average degree': 48.0,
'Average weighted degree': 46.273244774344036,
'Density': 1.0425531914893618,
'Average path length': 0.00650027056715701,
'Average clustering coefficient': 0.10427714321139174,
'Modularity': 0.3747117973757859,
'Partitions': 4
}
{‘Diameter’: 1,
‘Average degree’: 48.0,
‘Average weighted degree’: 46.273244774344036,
‘Density’: 1.0425531914893618,
‘Average path length’: 0.00650027056715701,
‘Average clustering coefficient’: 0.10427714321139174,
‘Modularity’: 0.3747117973757859,
‘Partitions’: 4}
第三步. 画出这个新图
nb_partitions = stats['Partitions']
modularity = stats['Modularity']
title = rf'Partitions: $\bf{nb_partitions}$ - Modularity: $\bf{modularity:.3f}$'
_ = tsia.plot.plot_network_graph(G, title=title, encoding=encoding)
社区发现算法在这个信号中抽象出了四个模块或者分区。但我们还不清楚这个新信息对我们有什么用。
第四步. 将分区颜色映射回原来的时序
ng_map = tsia.network_graph.get_network_graph_map(tag_df, encoding, reversed_cmap=True)
_ = tsia.plot.plot_colored_timeseries(tag_df, ng_map)
图中所发现的分区在原始时序中都有对应的子序列,并且该子序列具备相对显著的特点,在时序分析中称为 shapelet。
下面画出了其他信号的类似表示:
def plot_communities_timeseries(tag, image_size=48, colormap='jet'):
# Loads the signal from disk:
tag_df = pd.read_csv(f'{tag}.csv')
tag_df['timestamp'] = pd.to_datetime(tag_df['timestamp'], format='%Y-%m-%dT%H:%M:%S.%f')
tag_df = tag_df.set_index('timestamp')
X = tag_df.values.reshape(1, -1)
mtf = MarkovTransitionField(image_size=image_size, n_bins=n_bins, strategy=strategy)
tag_mtf = mtf.fit_transform(X)
G = tsia.network_graph.get_network_graph(tag_mtf[0])
statistics = tsia.network_graph.compute_network_graph_statistics(G)
nb_partitions = statistics['Partitions']
modularity = statistics['Modularity']
encoding = tsia.network_graph.get_modularity_encoding(G, reversed_cmap=True)
ng_map = tsia.network_graph.get_network_graph_map(tag_df, encoding, reversed_cmap=True)
fig = plt.figure(figsize=(28, 4))
gs = gridspec.GridSpec(1, 2, width_ratios=[1,4])
ax = fig.add_subplot(gs[0])
title = rf'Partitions: $\bf{nb_partitions}$ - Modularity: $\bf{modularity:.3f}$'
tsia.plot.plot_network_graph(G, ax=ax, title=title, reversed_cmap=True, encoding=encoding)
ax = fig.add_subplot(gs[1])
tsia.plot.plot_colored_timeseries(tag_df, ng_map, ax=ax)
return statistics
signals = [f'signal-{i}' for i in range(1,7)]
stats = []
for signal in signals:
s = plot_communities_timeseries(signal)
s.update({'Signal': signal})
stats.append(s)
stats = pd.DataFrame(stats)
stats.set_index('Signal')
似乎我们很难从中解读出多少有价值的信息。
总结一下
将MTF转换概率映射到其原始时序信号是一个可以考虑的工具,它可以帮助我们进一步理解该时序数据。对比之下,把图分析中的社区映射到原始时序似乎并没有为我们到来多少价值,然而从图计算中提取出来的特征可以用来作为一个神经网络的输入。
MTF和其相应的图模型可能可以用来
- 比较训练和验证数据集的一致性,看是否存在概念漂移。
- 训练半监督的异常预测模型:在时序数据上训练一个时序CNN模型,可每隔一段时间(例如每分钟)执行内联的MTF计算,把推理结果和已训练的模型进行比较,观察时序信号是否存在行为改变。
- 进一步解释了非监督时序模型的意义和作用