新加坡政府数据科学部门如何利用大数据协助诊断环线地铁故障

本文发表于新加坡政府开放数据门户站的博客,经授权由InfoQ中文站翻译并分享,本文由InfoQ社区编辑刘志勇翻译,感谢译者的辛苦奉献。

撰文: Daniel Sim | 分析: Lee Shangqian、Daniel Sim、Clarence Ng

编者按:大数据正在渗透各行各业,甚至能跟你考试能力测试、患上某种疾病的机率等非常生活化的场景应用都发生紧密的联系。今后大数据在我们的生活中就像是水和电一样,让社会整个信息质量更好、让信息利用效率更高效。

世界著名未来学家托夫勒曾说改变这个世界的力量有三种暴力、知识、金钱,而如今我们的世界正在被第四种力量改变,那就是大数据!大数据不管应用在哪个行业它的核心都是通过技术来获知事情发展的真相,最终利用这个“真相”来更加合理的配置资源。具体来说,要实现大数据的核心价值,还需要前两个重要的步骤,第一步是通过“众包”的形式收集海量数据,第二步是通过大数据的技术途径进行“全量数据挖掘”,最后利用分析结果进行“资源优化配置”。说白了,大数据最终的落地就是资源优化配置。

本文揭示了新加坡政府是如何利用大数据技术来捕获引发地铁被中断的反常列车,我们得以再一次见识大数据技术的神奇力量。

最近几个月,新加坡的地铁环线(MRT Circle Line)遭到了一连串的神秘中断,对数以千计的乘客造成了很大的混乱和痛苦。

同大多数同事一样,我每天早晨搭乘环线地铁到办公室。因此,在11月5日,当我所在的团队有调查原因的机会时,我就毫不犹豫地自告奋勇参加了。

根据新加坡地铁公司(SMRT)和新加坡陆路交通管理局(Land Transport Authority,LTA)的先前调查,我们知道这些事件是由于某种形式的信号干扰造成的,导致了一些列车的信号丢失。信号丢失会触发那些列车中的制动安全功能,并使它们沿着轨道随机停止。

但是这起第一次发生在八月份的事件——似乎是随机发生的,使调查小组很难找到确切的原因。

我们获得了由SMRT编译的数据集,其中包含以下信息:

  • 每个事件的日期和时间
  • 事件的位置
  • 涉及的列车编号
  • 列车的方向

我们开始清理数据,在Jupyter Notebook中进行工作,这是一个流行的编写和记录Python代码的工具。

像往常一样,第一步是导入一些有用的Python库。


  1. import math 
  2. import xlrd 
  3. import itertools as it 
  4. import numpy as np 
  5. import pandas as pd 
  6. from datetime import datetime  

片段1

然后我们从原始数据中提取有用的部分。


  1. dfincidents_0 = pd.read_excel('CCL EVAC E-brake occurrences hourly update_mod.xlsx', sheetname='Aug Sep') 
  2. dfincidents_1 = pd.read_excel('CCL EVAC E-brake occurrences hourly update_mod.xlsx', sheetname='Nov') 
  3. # Incident data for Nov had different format 
  4. dfincidents_1['Time'] = dfincidents_1['Time'].str.strip('hrs').str.strip(' ') 
  5. dfincidents_1['Time'] = pd.to_datetime(dfincidents_1['Time'], format='%H%M').dt.time 
  6. dfincidents = pd.concat([dfincidents_0, dfincidents_1]) 
  7. # Reset the index because they were concatenated from two data sources 
  8. dfincidents.reset_index(inplace=True, drop=True)  

片段2

我们将日期和时间列合并为一个标准列,以便更容易地将数据可视化:


  1. def datetime_from_date_and_time(row): 
  2.     """ 
  3.     Combines the date column and time column into a single column 
  4.     """ 
  5.     d = row['Date'] 
  6.     t = row['Time'] 
  7.     return datetime( 
  8.         d.year, d.month, d.day, 
  9.         t.hour, t.minute, t.second 
  10.     ) 
  11. # Add DateTime to the data for easier visualization 
  12. dfincidents['DateTime'] = dfincidents.apply(datetime_from_date_and_time, axis=1)  

片段3

这就产生了如下表格:

截图1:初始处理的输出

最初的可视化没有明确的答案

我们在初步探索性的分析中找不到任何明显的答案,如下图所示:

1.事件发生在一天之中,整天的事件数量反映了高峰和非高峰旅行时间。

图1 出现反映高峰和非高峰旅行时间的次数

2.事故发生在环线上的各个地点,西侧发生的事件略多一些。

图2 干扰的原因似乎与位置无关

3.只有一辆或两辆列车的话,信号干扰并不会产生影响,但在这条环线上有许多列车。“PV”是“客运车辆”(Passenger Vehicle)的缩写。

图3 60辆不同列车受到信号干扰

Marey图表:显示时间、位置和方向

我们的下一步是将多维度纳入探索性分析。

我们的灵感来自Marey图表,这是1983年Edward Tufte出版的经典著作《定量信息的视觉显示》(《The Visual Display of Quantitative Information》)最近,它被Mike Barry和Brian Card应用在波士顿地铁系统的大规模可视化项目:

截图2 摘自http://mbtaviz.github.io/

在该图表中,垂直轴表示时间——按时间顺序从上到下;而水平轴表示沿着列车线路的车站。对角线则表示列车运行。

在我们的Marey图表中开始绘制轴:

图4 环线版本的一个空白Marey图表

在正常情况下,在HarbourFront和Dhoby Ghaut之间运行的列车将在类似与此的线路上移动,每次单程行程只需要一个小时以上:

图5 环线上列车运行的程式化表示

我们的目的是在这个图表上绘制事件——是点而不是线。

准备可视化数据

首先,我们将站名从三字母代码转换为数字:

  • Marina Bay到Promenade之前:0到1.5;
  • Dhoby Ghaut到HarbourFront:2到29。

如果事故发生在两个站之间,则将其表示为0.5加上两个站号中的较小数。例如,如果事件发生在HarbourFront(29)和Telok Blangah(28)之间,则位置将是“28.5”。这样我们就很容易绘制沿水平轴的点。


  1. stations=("MRB,BFT,DBG,BBS,EPN,PMN,NCH,SDM,MBT,DKT,PYL,MPS,TSG,BLY,SER," 
  2.  
  3.           "LRC,BSH,MRM,CDT,BTN,FRR,HLV,BNV,ONH,KRG,HPV,PPJ,LBD,TLB,HBF").split(',')  
  4. def loc_id(station1, station2 = None):  
  5.     """  
  6.     Translates a 3-letter station code to a number,  
  7.     or a pair of 3-letter station codes to a number.  
  8.     Single stations are represented as whole numbers.  
  9.     Locations between stations are represented with a .5.  
  10.     Example:  
  11.     loc_id('MRB')         # 0 (Marina Bay)  
  12.     loc_id('MRB', 'BFT')  # 0.5 (Between Marina Bay and Bayfront) 
  13.     loc_id('DBG')         # 2 (Dhoby Ghaut)  
  14.     loc_id('HBF')         # 29  
  15.     loc_id('HBF', 'TLB')  # 28.5 (Between Harbourfront and Telok Blangah)  
  16.     loc_id('HBF', 'DBG')  # throws and error, because these stations are not adjacent  
  17.     """  
  18.     if station2 == None or station2 == 'nan' or (type(station2) is float and math.isnan(station2)):  
  19.         # Single stations  
  20.         return stations.index(station1)  
  21.     else: # Pairs of stations -- take the average to get the 0.5  
  22.         stn1_index = stations.index(station1)  
  23.         stn2_index = stations.index(station2)  
  24.         # Handle the branch at Promenade  
  25.         if (set(['PMN', 'EPN']) == set([station1, station2])):  
  26.             return float(stations.index('EPN')) + 0.5  
  27.         elif set(['PMN', 'BFT']) == set([station1, station2]):  
  28.             return float(stations.index('BFT')) + 0.5  
  29.         else:  
  30.             # Require station pairs to be adjacent stations  
  31.             assert(math.fabs(stn1_index - stn2_index) == 1)  
  32.             return float(stn1_index + stn2_index) / 2 

片段 4

然后我们计算位置ID的数字……


  1. def loc_id_from_stations(row): 
  2.     try: 
  3.         # This handles entries with both "Station from" and "Station to" 
  4.         # and entries with only "Station from" 
  5.         return loc_id(row['Station from'], str(row['Station to'])) 
  6.     except ValueError: 
  7.         # Some entries only have "Station to" but no 
  8.         # "Station from" 
  9.         return loc_id(row['Station to'])  

片段 5

并添加到数据集:


  1. # Select only some columns that we are interested in 
  2. sel_dfincidents = dfincidents[['DateTime', 'PV', 'Bound', 'Station from', 'Station to', 'Event', 'Remarks']] 
  3. # Add the location ID into the dataset 
  4. sel_dfincidents['LocID'] = sel_dfincidents.apply(loc_id_from_stations, axis=1)  

片段6

然后我们得到如下表格:

截图3 添加位置ID后的输出表

通过数据处理,我们能够创建所有紧急制动事件的散点图。这里的每个点代表一个事件。我们还是无法发现任何明显的事故模式。

图6 信号干扰事件表示为散点图

接下来,我们通过将每个事件表示为指向左侧或右侧的三角形,而不是点,将列车方向添加到图表中:

图7 方向由箭头和颜色表示。

它看起来相当随机,但当我们放大到如下的图表,一个模式似乎似乎浮出了水面:

图8 上午6点到10点之间的事件

如果你仔细阅读图表,你会注意到,故障似乎按顺序发生。当一趟列车受到干扰时,另一趟在同一方向行驶的列车很快就会受到波及。

信号如何互相干扰?

在这一点上依然不明,一趟列车是罪魁祸首。

我们已经证实的是,似乎有一个随时间和位置相关的模式:事件一个接一个地发生,与上一个事件的方向相反。似乎有一条“破坏的痕迹”,它会不会是导致数据集中那些事件的诱因?

事实上,连接事件的假想线看上去与截图2的Marey图表可疑地类似。干扰的原因会不会是对面轨道的列车?

图9 它会是一趟相反方向行驶的列车吗?

我们决定检验这个“反常列车”的假说。

我们已经知道,沿着环线的车站之间的行驶时间在两到四分钟之间。这意味着如果发生4分钟的间隔,我们可以将所有紧急制动事件分组在一起。


  1. def same_cascade(i, j):  
  2.     """  
  3.     Given a pair of incidents (i,j), returns true if:  
  4.         t <= d * 4 mins  
  5.     where t is  the time difference between occurrences  
  6.     and d is the distance (measured by difference in location ID).  
  7.     Moreover, we consider the track direction, and only consider  
  8.     incidents that are "moving backwards".  
  9.     """  
  10.     # If trains are not travelling in the same direction  
  11.     # they cannot be due to the same "backward moving" interference  
  12.     # source.  
  13.     # (Note: This was the hypothesis when this code was written. 
  14.      # It turned out that the rogue train could affect all  
  15.     # trains in the vicinity, not just in the opposite track)  
  16.     if i["Bound"] != j["Bound"] or \  
  17.         i["Bound"] not in ['IT', 'OT']:  
  18.         return False  
  19.     # time difference in minutes  
  20.     time_difference = (i["DateTime"] - j["DateTime"]) / np.timedelta64(1, 'm')  
  21.     location_difference = i["LocID"] - j["LocID"]  
  22.     if location_difference == 0:  
  23.         return False  
  24.     ratio = time_difference / location_difference  
  25.     if i["Bound"] == 'OT':  
  26.         return ratio > 0 and ratio < 4  
  27.     elif i["Bound"] == 'IT':  
  28.         return ratio < 0 and ratio > -4  

片段 7

我们发现了满足这个条件的所有事件对:


  1. incidents = sel_dfincidents.to_records()  
  2. # (a, b, c, d, ...) --> ((a,b), (a,c), (a,d), ..., (b,c), (b,d), ..., (c,d), ...)  
  3. incident_pairs = list(it.combinations(incidents, 2))  
  4. related_pairs = [ip for ip in incident_pairs if same_cascade(*ip)]  
  5. related_pairs = [(i[0], j[0]) for i,j in related_pairs]  

片段 8

然后,我们使用并查集的数据结构将所有相关的事件对分组成更大的集合。这使我们可以将可能关联到同一“反常列车”的事件分组。


  1. def pairs_to_clusters(pairs): 
  2.     """ 
  3.     A quick-and-dirty disjoint-set data structure. But this works fast enough for 200+ records 
  4.     Could be better. 
  5.     Example input: 
  6.     (1,2), (2,3), (4,5) 
  7.     Output: 
  8.     1: {1,2,3} 
  9.     2: {1,2,3} 
  10.     3: {1,2,3} 
  11.     4: {4,5} 
  12.     5: {4,5} 
  13.     """ 
  14.     the_clusters = dict() 
  15.     for i,j in pairs: 
  16.         if i not in the_clusters: 
  17.             if j in the_clusters: 
  18.                 the_clusters[j].add(i) 
  19.                 the_clusters[i] = the_clusters[j] 
  20.             else: 
  21.                 the_clusters[i] = set(list([i, j])) 
  22.                 the_clusters[j] = the_clusters[i] 
  23.         else: 
  24.             if j in the_clusters: 
  25.                 if the_clusters[i] is not the_clusters[j]: # union the two sets 
  26.                     for k in the_clusters[j]: 
  27.                         the_clusters[i].add(k) 
  28.                         the_clusters[k] = the_clusters[i] 
  29.                 else: # they are already in the same set 
  30.                     pass 
  31.             else: 
  32.                 the_clusters[i].add(j) 
  33.                 the_clusters[j] = the_clusters[i] 
  34.     return the_clusters  

片段9

然后将我们的算法应用于数据:


  1. clusters = pairs_to_clusters(related_pairs) 
  2. # Show each set only once 
  3. clusters = [v for k,v in clusters.items() if min(v) == k] 
  4. clusters[0:10]  

片段10

这些是我们确定的一些集群:

[{0, 1},

{2, 4},

{5, 6, 7},

{8, 9},

{18, 19, 20},

{21, 22, 24, 26, 27},

{28, 29, 30, 31, 32, 33, 34},

{42, 44, 45},

{47, 48},

{51, 52, 53, 56}]

接下来,我们计算了可以通过我们的聚类算法解释的事件的百分比。


  1. # count % of incidents occurring in a cluster 
  2. all_clustered_incidents = set() 
  3. for i,clust in enumerate(clusters): 
  4.     all_clustered_incidents |= clust 
  5. (len(all_clustered_incidents), 
  6.  len(incidents), 
  7.  float(len(all_clustered_incidents)) / len(incidents))  

片段11

结果是:


  1. (189, 259, 0.7297297297297297) 

它表达的意思是:在数据集中的259个紧急制动事件中,189个案例(其中73个)可以通过“反常列车”假说来解释。我们觉得我们真的走对了路。

我们基于聚类结果对事件图进行了着色。具有相同颜色的三角形在同一个集群中。

图10 通过我们的算法聚类的事件

有多少反常列车?

如图5所示,在环线上的每个端到端行程需要大约1小时。我们通过事件图和与图5密切匹配的线绘制最佳线。这强烈暗示只有一个“反常列车”。

图11 事件集群的时间强烈暗示干扰能够关联到单趟列车

我们还观察到,不明的“反常列车”本身似乎没有遇到任何信号问题,因为它没有出现在我们的散点图。

我们相信我们有一个很好的例子,决定进一步调查。

捕获反常列车

日落之后,我们去了Kim Chuan站以确定“反常列车”。我们不能检查详细的列车日志,因为SMRT需要更多的时间来提取数据。因此,我们决定用传统方式通过查看在事件发生时到达和离开每个车站的列车的视频记录来识别列车。

上午3点,车队出现了头号嫌犯:PV46,一辆自2015年起投入使用的列车。

检验假说

11月6日(星期日),LTA和SMRT测试,如果PV46是通过运行列车在非高峰时间问题的来源,那我们就对了——PV46确实导致了附近列车之间的通信丢失,并触发那些列车上的紧急制动器。在PV46未投入使用的那天之前,并没有这样的事件发生。

在11月7日(星期一),我们的团队处理了PV46的历史位置数据,并得出结论,从8月到11月的所有事件中,超过95%可以用我们的假说来解释。其余的事件,可能是由于偶发在正常情况下的信号丢失。

在某些日子,如9月1日,这种模式特别明显。你可以很容易地看到,当PV46投入运行时 ,在其运行期间或者前后,常常发生发生干扰事件。

LTA和SMRT最终于11月11日发布了一份联合新闻稿,与公众分享调查结果。

小结

当我们开始时,我们曾经希望能够找到跨机构调查组可能感兴趣的模式,其中包括LTA、SMRT和DSTA的许多官员。SMRT和LTA提供的整洁的事件日志帮助我们开了一个好头,因为在导入和分析数据之前需要尽可能少的清理。我们还对LTA和DSTA的有效跟踪调查表示满意,因为他们证实了PV46存在硬件问题。

从数据科学的角度来看,我们很幸运,事件发生得如此接近。这使我们能够在如此短的时间内识别问题和罪魁祸首。如果事件更加孤立,则Z字形模式将不那么明显,并且它将让我们耗费更多的时间和数据来解决这个谜。

当然,令人最高兴的是,现在所有人可以坐环线地铁再次充满信心地工作

本文作者:刘志勇

来源:51CTO

时间: 2024-08-31 10:13:26

新加坡政府数据科学部门如何利用大数据协助诊断环线地铁故障的相关文章

全国政协热议利用大数据提升政府治理能力

中国进入大数据时代后,如何把握住大数据带来的战略机遇成为全国政协委员关注的焦点.在12日下午俞正声主持召开的全国政协双周协商座谈会上,委员们就提升政府治理能力现代化和利用大数据为社会提供更好服务,进行热烈交流,并发表意见建议. 座谈会以"利用大数据技术提升政府治理能力"为主题,全国政协主席俞正声主持会议并讲话. 一年多以来,全国政协十分关心网络工作,俞正声主席多次作出重要批示,委员们深入开展调查研究,积极为网络工作建言献策,提出关于网上舆论.网络安全.信息化等方面的提案50多个,为推动

专访佰腾科技大数据团队,谈专利大数据领域的挑战与实践

11+大数据行业应用实践请见https://yq.aliyun.com/activity/156,同时这里还有流计算.机器学习.性能调优等技术实践.此外,通过Maxcompute及其配套产品,低廉的大数据分析仅需几步,详情访问https://www.aliyun.com/product/odps:更多精彩内容参见大数据频道:https://yq.aliyun.com/big-data . 江苏佰腾科技有限公司成立于2006年,是一家专业从事知识产权服务的高科技服务企业,国内知名的知识产权服务机构

大数据引擎,或改变大数据竞争格局

文/卞海峰 "台风来了,猪都会飞",这是一句耳熟能详的西方谚语,主要描述"机会"的重要性,与中国的古语"时势造英雄"一样.如今的大数据,恐怕就是这样一种"机会",同时这个机会还能帮助我们挖掘出更多的商业机会. 在前不久的百度技术开放日上,百度宣布将正式开放大数据引擎,这也是全球首个开放的大数据引擎.据悉,此次百度开放的大数据引擎主要包含开放云.数据工厂.百度大脑三块,通过这三块可以实现数据的收集.存储.计算.分析.挖掘和管理.

智慧城市首要在政府利用大数据的智慧

在大数据时代,大数据发展与提升政府治理能力现代化紧密相连,与之而来的,则是精细化管理的理念越来越普遍运用到公共治理中.如何提升政府的"精准治理",便是管理部门必须深思并亟需付诸行动的问题. 好在,创新型社会不缺探索者.3月15日,滴滴出行与成都市交委签署战略合作协议,共同推进成都市"智慧交通"建设.根据媒体所披露的内容,滴滴出行将充分发挥在大数据.技术.平台等方面优势,参与成都市智慧城市.智慧交通建设,加强大数据开发利用,加大新能源汽车推广应用,不断提升服务质量,为

互联网大佬刘庆峰:利用大数据提升政府效率

2015年3月3日15时,全国政协十二届三次会议在人民大会堂举行.这次大会总共有两千多名政协委员和接近三千名人大代表参与,其中互联网行业的代表人士已经增加至6人,反映这个行业影响力或者重要性正在逐渐提高.那在今年两会上互联网大佬们都有哪些提议呢? 马化腾:用移动互联网防治雾霾 这两天柴静的<穹顶之下>可谓是刷爆了朋友圈,因此雾霾问题也成为此次两会关注的焦点.我们的小马哥也就这一点用自己的互联网思维提了自己的建议. 腾讯CEO马化腾表示,随着移动互联网.大数据.云计算.物联网与人工智能等新技术的

有效利用大数据资源,释放数据隐藏的价值

数据的真实价值就像漂浮在海洋中冰山,第一眼只能看到冰山一角,而绝大部分则隐藏在表面之下.在大数据时代,数据的价值仍然存在,只是处于"休眠"状态,而要解锁这些数据的价值,就必须通过统计人员的不懈努力并借助新一代的方法和工具,来释放数据隐藏的价值. 大数据来袭势不可挡 世界每时每刻都在产生数据,数据又开始以几何级增长,这种增长速度已经不是"爆炸"二字可以形容的了.国际数据公司(IDC)的<数据宇宙>报告显示:2008年全球数据量为0.5ZB,2010年为1.

利用大数据取得成功的7条建议

就在您认为大数据不可能再变大时,它还在不断变大. 无论其实际大小,大数据正在显示价值. 各个地方的组织都有各种形态与大小的大数据. 这些组织意识到其重要性.机遇以及给予关注的迫切需要. 很显然,无论忽略与否,大数据都会不断发展. 已掌控大数据(在明了其价值前储存的多结构混乱数据)的组织正在提升组织效率.提高收益,并发展新的业务模式. 他们是怎样做到的? 这些机构成功的方法可以总结为七条建议. 1.以短期考虑促进长期考虑 担心能否跟上大数据的潮流的人,不止您一个. 一切都瞬息万变,因此无从知道今年

利用大数据取得成功的 7 条建议

就在您认为大数据不可能再变大时,它还在不断变大.无论其实际大小,大数据正在显示价值.各个地方的组织都有各种形态与大小的大数据.这些组织意识到其重要性.机遇以及给予关注的迫切需要.很显然,无论忽略与否,大数据都会不断发展. 已掌控大数据(在明了其价值前储存的多结构混乱数据)的组织正在提升组织效率.提高收益,并发展新的业务模式.他们是怎样做到的?这些机构成功的方法可以总结为七条建议. 1.以短期考虑促进长期考虑 担心能否跟上大数据的潮流的人,不止您一个.一切都瞬息万变,因此无从知道今年或明年哪些工具

委员建议合理利用“大数据” 打造“智慧烟台”

"互联网+"时代,"大数据"正在深刻改变这人们的生活.工作和思维方式.烟台市政协十二届五次会议期间,政协委员彭成瑶建议政府强化利用"大数据"技术,提升社会治理能力和公共服务能力,建设"智慧烟台". 彭成瑶称,目前,部分政府职能部门缺乏"大数据"意识,一些管理理念和运作方式也不适应"大数据"的管理决策要求.放眼全国,现阶段在"大数据"使用的安全性保障与相关法律的制定方面