时间地图:离散事件可视化

构造时间地图. 首先,把一系列事件想象成时间轴上的点,相邻事件间的时间间隔标示为 t1, t2, t3, t4, …

一个时间地图可表示为一个二维的离散点,其中,事件的xy坐标是:
(t1,t2), (t2, t3), (t3, t4), 等等.在时间地图上,紫色的点可被绘成如下:

换句话说,散点图上的每个点代表一个事件,它的x坐标是本事件与前一时刻事件间的时间间隔,y坐标是本事件与后一时刻事件间的时间间隔,时间集中仅有第一个点和最后一个点不被展示。下面是两个简单的示例:

对于A:事件均匀分布,由于xy坐标都相等,时间地图是一个点。对于B:事件间的时间间隔分布不均,某些事件稍微有些延迟。时间地图就包含4个点。除非我们选择时间刻度很小的直方图,否则我们看到这两个序列完全一样,看不到隐藏在时间内的变化。为了得到直观的感觉:这是一个被分成四象限的启发式经验图。

时间地图的美在于时间线将不再是问题,这是因为我们仅仅画出了相邻事件间的时间间隔,对于事件间的时间间隔变化巨大的情况,我们可以取对数坐标。这就使得我们可以在同一副图中描绘出时间间隔分布在毫秒至数月的时间地图。下面我们来看看真实世界中的情况。

白宫推文

Twitter API 可以允许你最多收集一个用户的3200条推文。用Twython,我下载了@WhiteHouse的推文,这些推文都是总统的助理团队发布的。下面这幅图是2015年一月至九月间的时间地图。

每条推文都基于发布时间进行颜色编码,并且时间轴经过对数缩放,两个簇分别对应工作日的开始和结束,工作日的第一条推文通常在上午9点或者中午,最后一条推文间隔一个更大的时间窗。
有趣的是,这两个簇代表不同的行为模式,我们称左下角的簇为簇I,时间间隔短促,一般对应重大新闻。右上角对应簇II,它是“例行公事”,一般一小时发布一条推文。
我们很难数出每个簇中的点数,热力时间图可以用红色显示出高密度点。

在热力时间图中,我们仍能看到离散点,“例行公事”这个簇拥有最多的点。

个人账户的推文

@WhiteHouse这个账号是由一个团队运营的,那么个人的推特账号的时间地图又是怎样的一番情景呢?
下面是@Nicholas Felton的推文时间地图

与@WhiteHouse这个公共推特不同,个人推特没有严格的计划安排,它的时间地图也就没有两个簇,但我们仍然能发现他的趋势:服从24小时规律,大量的点遵循缓慢且平稳的模式,一般每天发布一条推文。

网络机器人

网络机器人就是自动执行任务的程序,当PC用户点击某些链接时就会不知不觉的安装在电脑中,我分析了一个为各个网站提供监控服务的公司的数据。

它显示出特定IP对网站的访问量,这个直方图包含了整体行为的重要信息。下面就是这个时间地图:

这些模式不可能是一个人产生的,我们发现一些突出的特征:一些”快速且稳定“的点对应直方图的”加速“和”减速“的柱条。不包含一些稀疏的点。
在左上方和右下方的那些稀疏的点,代表频繁活动中的静止阶段。这和直方图中的长间隙相对应。每间隔8min出现一次。

用Python创建时间图

下面是基于随机生成的数据点创建的时间图。

import numpy as np
import matplotlib.pylab as plt

# a sample array containing the timings of events in order: [1, 2.1, 2.9, 3.1...]
times = np.cumsum(np.abs(np.random.normal(size=100)))

# calculate time differences:
diffs = np.array([times[i]-times[i-1] for i in range(1,len(times))])

xcoords = diffs[:-1] # all differences except the last
ycoords = diffs[1:] # all differences except the first

plt.plot(xcoords, ycoords, 'b.') # make scatter plot with blue dots
plt.show()

基于上面的程序创建时间热力图,通过统计栅格中的事件的个数,我们建立一个二维直方图,把直方图看成一幅图像,运用高斯模糊来平滑图像中的突变。

import scipy.ndimage as ndi

Nside=256 # this is the number of bins along x and y for the histogram
width=8 # the width of the Gaussian function along x and y when applying the blur operation

H = np.zeros((Nside,Nside)) # a 'histogram' matrix that counts the number of points in each grid-square

max_diff = np.max(diffs) # maximum time difference

x_heat = (Nside-1)*xcoords/max_diff # the xy coordinates scaled to the size of the matrix
y_heat = (Nside-1)*ycoords/max_diff # subtract 1 since Python starts counting at 0, unlike Fortran and R

for i in range(len(xcoords)): # loop over all points to calculate the population of each bin
H[x_heat[i], y_heat[i]] += 1 # Increase count by 1
# here, the integer part of x/y_heat[i] is automatically taken

H = ndi.gaussian_filter(H,width) # apply Gaussian blur
H = np.transpose(H) # so that the orientation is the same as the scatter plot

plt.imshow(H, origin='lower') # display H as an image
plt.show()

可以在我的github下载对应的python程序。
Time Map上可以找到详细原文说明。

结论

时间图可以揭示潜在的模式,它和直方图一起各自从不同方面反映数据的特征。Picasso在一副画作中通过多个视角全面展示一个物体的内容。类似的,时间图在多重时间尺度上提取内在隐式结构,在数据驱动的今天,它是潜力巨大的工具。

更多的TimeMap应用如下:

原始博客:Time Maps: Visualizing Discrete Events Across Many Timescales

https://rpubs.com/vadimus/bmore_tow_time_maps