侯波濤
(中國(guó)西南電子技術(shù)研究所,四川 成都 610036)
隨著數(shù)據(jù)科學(xué)的發(fā)展,數(shù)據(jù)分析呈現(xiàn)流行之勢(shì),幾乎滲透到自然科學(xué)、社會(huì)科學(xué)的方方面面。數(shù)據(jù)分析致力于從海量數(shù)據(jù)中挖掘有效信息,通過(guò)可視化等手段展示數(shù)據(jù)中隱含的規(guī)律。Python 是一種面向?qū)ο?、解釋型、?dòng)態(tài)類型程序設(shè)計(jì)語(yǔ)言[1-3],隨著Numpy、Scipy、Pandas、Matplotlib 等眾多庫(kù)的開(kāi)發(fā)及優(yōu)化,Python 在科學(xué)計(jì)算領(lǐng)域占據(jù)著越來(lái)越重要的地位,包括科學(xué)計(jì)算、數(shù)學(xué)建模、數(shù)據(jù)分析等[4-6]。
Python 的Pandas 庫(kù)提供了便捷處理結(jié)構(gòu)化數(shù)據(jù)的大量數(shù)據(jù)結(jié)構(gòu)和函數(shù),兼具Numpy 高性能數(shù)組計(jì)算功能及電子表格和關(guān)系型數(shù)據(jù)庫(kù)(如SQL)靈活的數(shù)據(jù)處理功能[7-8],使得數(shù)據(jù)對(duì)齊、合并、缺失值處理、篩選、分組及聚合運(yùn)算非常便捷。pyecharts 是百度開(kāi)源echarts 與python 結(jié)合強(qiáng)大的數(shù)據(jù)可視化工具,可提供直觀、生動(dòng)、可交互、高度個(gè)性化定制的數(shù)據(jù)可視化圖表。本文利用pandas及pyecharts 對(duì)定向通信系統(tǒng)的組網(wǎng)性能、Qos、話音時(shí)序進(jìn)行了數(shù)據(jù)分析及可視化。
數(shù)據(jù)分析流程如圖1 所示,對(duì)存儲(chǔ)的二進(jìn)制記錄數(shù)據(jù)進(jìn)行十六進(jìn)制ASCII 碼轉(zhuǎn)換,將轉(zhuǎn)換后的數(shù)據(jù)進(jìn)行解析,再對(duì)解析后的數(shù)據(jù)進(jìn)行預(yù)處理,數(shù)據(jù)預(yù)處理主要包括數(shù)據(jù)清洗及預(yù)分析,缺失值、重復(fù)值、不一致數(shù)據(jù)處理、數(shù)據(jù)類型轉(zhuǎn)換等,通常占數(shù)據(jù)分析工作量的70%以上。對(duì)單節(jié)點(diǎn)文件BIT 結(jié)果進(jìn)行統(tǒng)計(jì)及可視化,對(duì)多節(jié)點(diǎn)文件兩兩之間進(jìn)行數(shù)據(jù)合并、分組、篩選、提取及可視化,利用篩選的數(shù)據(jù)及可視化圖形文件對(duì)網(wǎng)絡(luò)、Qos、話音進(jìn)行分析,對(duì)有無(wú)故障做出判斷并進(jìn)一步分析原因,最后撰寫數(shù)據(jù)分析報(bào)告。
圖1 數(shù)據(jù)分析流程
Pandas 的join 方法支持以索引或指定列連接兩個(gè)Dataframe。典型數(shù)據(jù)對(duì)齊、合并及缺失值處理如表1 所示,首先選擇一個(gè)基準(zhǔn)時(shí)間,一般選取周期類消息(如導(dǎo)航數(shù)據(jù))時(shí)標(biāo)或者自定義一個(gè)時(shí)間序列作為基準(zhǔn)時(shí)間序列,根據(jù)時(shí)間序列合并多條數(shù)據(jù)項(xiàng),合并后先進(jìn)行列數(shù)據(jù)項(xiàng)縱向缺失值填充再進(jìn)行行數(shù)據(jù)項(xiàng)的橫向缺失值刪除處理,結(jié)合序號(hào)列可保證合并后的數(shù)據(jù)以基準(zhǔn)時(shí)間序列為周期,最后利用groupby 等函數(shù)進(jìn)行分組、聚合、篩選等處理,提取出關(guān)注信息。
表1 數(shù)據(jù)對(duì)齊、合并及缺失值處理
timeticks=pd.date_range(start=time_start,end=time_end,freq=’20L’) # 時(shí)間基準(zhǔn)20ms
df=pd.DataFrame({‘SN’:np.arange(len(timeticks))},index=timeticks) # 創(chuàng)建基準(zhǔn)時(shí)間序列
df=df.join([Data1,Data2,…,State1,State2,…],how=’outer’,on=’ts’)# 合并數(shù)據(jù)
df[‘Data1’].fillna(method=’pad’,inplace=True) # 按列缺失值填充
…
df.dropna(inplace=True) # 刪除空值行
數(shù)據(jù)可視化采用pyecharts 的散點(diǎn)圖Scatter 和折線圖Line,通過(guò)坐標(biāo)軸指示器配置項(xiàng)AxisPointerOpts和區(qū)域選擇組件配置項(xiàng)BrushOpts 可實(shí)現(xiàn)多圖聯(lián)動(dòng)及區(qū)域選擇聯(lián)動(dòng)。通過(guò)zip 將多維數(shù)據(jù)進(jìn)行打包,實(shí)現(xiàn)多維數(shù)據(jù)可視化。通過(guò)視覺(jué)映射組件VisualMapOpts 可將關(guān)注數(shù)據(jù)映射到視覺(jué)元素,通過(guò)提示框TooltipOpts 實(shí)現(xiàn)與鼠標(biāo)良好的交互性,實(shí)時(shí)顯示多維數(shù)據(jù),通過(guò)區(qū)域縮放配置項(xiàng)DataZoomOpts可實(shí)現(xiàn)區(qū)域縮放,展示出所關(guān)注的細(xì)節(jié)數(shù)據(jù)信息,生成獨(dú)立的html 圖表文件既可概覽整體,又可關(guān)注細(xì)節(jié),可獨(dú)立進(jìn)行交互式數(shù)據(jù)分析。
Python 自帶的binascii 模塊可將記錄數(shù)據(jù)由二進(jìn)制轉(zhuǎn)換為十六進(jìn)制ascii 碼,轉(zhuǎn)為字符串后使用split 函數(shù)根據(jù)幀頭標(biāo)識(shí)將字符串分割為數(shù)據(jù)幀列表,遍歷列表并用bytes().fromhex()將數(shù)據(jù)幀轉(zhuǎn)換為十進(jìn)制字節(jié)序列,最后根據(jù)接口控制文件解析數(shù)據(jù)幀內(nèi)容,對(duì)于超大文件需分塊讀取及處理以避免對(duì)內(nèi)存的過(guò)度消耗。
f=open(‘Record.bin’,’rb’) # 打開(kāi)記錄文件
while True:
Data_b=f.read()
if not Data_b:
break
Data_s=str(binascii.hexlify(Data_b))[2:-1]#二進(jìn)制轉(zhuǎn)十六進(jìn)制
Frame=Data_s.split(‘XXXX’) # 根據(jù)幀頭XXXX 分割數(shù)據(jù)幀
for frame in Frame: #解析數(shù)據(jù)幀
frame_byte=bytes().fromhex(frame)#轉(zhuǎn)十進(jìn)制字節(jié)序列
數(shù)據(jù)分析時(shí)需綜合分析多條數(shù)據(jù)信息,每條數(shù)據(jù)有自身時(shí)間標(biāo)簽,對(duì)于通信節(jié)點(diǎn)A 和B,以A 的慣導(dǎo)數(shù)據(jù)為時(shí)間基準(zhǔn),利用Reindex 將B 的慣導(dǎo)數(shù)據(jù)進(jìn)行重新索引并進(jìn)行向上填充,再利用join 函數(shù)合并雙方慣導(dǎo)數(shù)據(jù),合并后計(jì)算雙節(jié)點(diǎn)距離。
Ins_AB=Ins_B.reindex(Ins_A.index,method=’pad’)#利用reindex 重新索引,向前填充
Ins=Ins_A.join(Ins_AB,how=’left’,lsuffix=’A’,rsuffix=’B’) #數(shù)據(jù)合并
Ins[‘Dis’]=Distance(df[‘Lat%s’%A],df[‘Lo n%s’%A],df[‘Alt%s’%A],df[‘Lat%s’%B],df[‘Lon%s’%B],df[‘Alt%s’%B]) #矢量計(jì)算距離
對(duì)于實(shí)時(shí)性要求較高的波束數(shù)據(jù)及網(wǎng)絡(luò)數(shù)據(jù),可將時(shí)元、時(shí)幀、時(shí)隙設(shè)置為層次化索引進(jìn)行精確對(duì)齊及合并。
Beam.set_index([‘Epoch’,’Frame’,’Slot’],inplace=True)#設(shè)置波束層次化索引
Net.set_index([‘Epoch’,’Frame’,’Slot’],in place=True) #設(shè)置網(wǎng)絡(luò)層次化索引
Beam_Net=Beam.join([Net],how=’outer’) #合并波束與網(wǎng)絡(luò)
Beam_Net.fillna(method=’pad’,inplace=True)#向前填充
最后根據(jù)時(shí)間序列將雙節(jié)點(diǎn)的慣導(dǎo)數(shù)據(jù)、波束及網(wǎng)絡(luò)數(shù)據(jù)、系統(tǒng)使用狀態(tài)數(shù)據(jù)進(jìn)行合并及缺失值處理,合并后數(shù)據(jù)如表2 所示。
表2 雙節(jié)點(diǎn)合并后數(shù)據(jù)
對(duì)于Qos 分析需根據(jù)用戶數(shù)據(jù)的消息序列號(hào)進(jìn)行對(duì)齊及合并,合并后進(jìn)行端到端時(shí)延計(jì)算,如表3 所示。
Pck=Pck_Send.join(Pck_Rcv,how=’outer’,on=’SN’,lsuffix=’T’,rsuffix=’R’,)# 以 序 列號(hào)合并
Pck[‘Delta’]=Pck[‘Ts_R’]-Pck[‘Ts_T’]#計(jì)算端到端時(shí)延
表3 用戶數(shù)據(jù)合并及處理
Pandas 憑借高度優(yōu)化的函數(shù)對(duì)結(jié)構(gòu)化數(shù)據(jù)進(jìn)行遍歷、分組及篩選非常便捷高效。為了分析網(wǎng)絡(luò)整體情況,需對(duì)表2 提取網(wǎng)絡(luò)由連接到斷開(kāi)時(shí)刻及斷開(kāi)到連接時(shí)刻第一次的數(shù)據(jù)并計(jì)算斷網(wǎng)持續(xù)時(shí)間,為了靈活處理需按行遍歷整個(gè)數(shù)據(jù)框,通過(guò)dataframe 的itertuples 函數(shù)可高效完成操作,實(shí)測(cè)遍歷100 萬(wàn)行數(shù)據(jù)框并做簡(jiǎn)單處理僅耗時(shí)13 秒,通過(guò)提取的數(shù)據(jù)可直觀看出網(wǎng)絡(luò)斷開(kāi)及恢復(fù)時(shí)刻雙節(jié)點(diǎn)的距離、高度、姿態(tài)、天線、波束、SNR、系統(tǒng)使用狀態(tài)等信息。
for row in Data.itertuples():
epoch=getattr(row,‘Epoch’)
frame=getattr(row,‘Frame’)
slot=getattr(row,‘Slot’)
…
為了分析由于模擬信道性能下降而造成的網(wǎng)絡(luò)斷續(xù),以此作為硬件性能下降但BIT 無(wú)法給出故障判斷的輔助手段,可通過(guò)計(jì)算表2 多個(gè)天線兩兩配對(duì)時(shí)的通信成功概率(可通率),根據(jù)多個(gè)天線間的可通率計(jì)算結(jié)果快速定位故障天線或信道。用groupby 函數(shù)對(duì)表2 根據(jù)節(jié)點(diǎn)A 和B 的天線索引進(jìn)行分組篩選,根據(jù)篩選后的網(wǎng)絡(luò)狀態(tài)進(jìn)行統(tǒng)計(jì)并計(jì)算可通率,計(jì)算結(jié)果如表4,可直觀的看出節(jié)點(diǎn)A的天線1 有問(wèn)題,代碼非常簡(jiǎn)潔。
for (Ant_A,Ant_B),group in df.groupby([‘Ant_A’,‘Ant_B’]):
link_on=group[group[‘Net’]==1].shape[0]
link_off=group[group[‘Net’]]==0].shape[0]
off_time=link_off * 0.02 #斷開(kāi)時(shí)間統(tǒng)計(jì)
on_rate=‘{:.3%}’.format(link_on/ (group.shape[0]))#計(jì)算可通率
表3 中計(jì)算丟包率只需統(tǒng)計(jì)合并后收端數(shù)據(jù)為空值的次數(shù),通過(guò)isnull 函數(shù)進(jìn)行篩選。
Pck_lost=Pck[Pck.Ts_R].isnull()]# 接收丟包數(shù)
LostRate=Pck_lost.shape[0]/ Pck.shape[0]# 計(jì)算丟包率
表4 可通率計(jì)算
對(duì)于表3 用戶消息需計(jì)算數(shù)據(jù)吞吐量,用groupby 分組聚合的辦法非常高效,根據(jù)整數(shù)秒數(shù)據(jù)進(jìn)行分組并計(jì)算每組中發(fā)送數(shù)據(jù)長(zhǎng)度總和,代碼如下。
df[‘Epoch’]=[int(x.value/ 1000000000) for x in Pck[‘Ts_R’]]#時(shí)間轉(zhuǎn)為整數(shù)秒
grouped=df[‘LEN_T’].groupby(df[‘Epoch’])#根據(jù)整數(shù)秒進(jìn)行分組
Throughout=grouped.sum()*8 #轉(zhuǎn)換為bps,計(jì)算吞吐量
(1)多軸聯(lián)動(dòng)數(shù)據(jù)可視化
對(duì)表2 中的網(wǎng)絡(luò)、距離、SNR、信道數(shù)據(jù)進(jìn)行同步顯示,滑動(dòng)鼠標(biāo)可實(shí)現(xiàn)多圖聯(lián)動(dòng)及區(qū)域放大,如圖2 所示。
(2)多維數(shù)據(jù)可視化及顏色映射
對(duì)表2 中網(wǎng)絡(luò)和距離數(shù)據(jù)作多維散點(diǎn)圖如圖3所示,以網(wǎng)絡(luò)狀態(tài)為顏色映射,過(guò)濾網(wǎng)絡(luò)斷開(kāi)時(shí)刻后如圖4 所示,對(duì)通信雙方的距離、高度、天線、波束、SNR 信息進(jìn)行多維顯示。
圖2 多軸聯(lián)動(dòng)數(shù)據(jù)可視化
圖3 距離與網(wǎng)絡(luò)關(guān)系
圖4 網(wǎng)絡(luò)斷開(kāi)時(shí)刻信息
對(duì)表2 慣導(dǎo)航跡和SNR 數(shù)據(jù)作多維散點(diǎn)圖,用SNR 數(shù)據(jù)進(jìn)行顏色映射,如圖5 所示,可直觀看出區(qū)域分布,拖動(dòng)SNR 范圍可查看對(duì)應(yīng)區(qū)域,滑動(dòng)鼠標(biāo)動(dòng)態(tài)放大可查看每個(gè)點(diǎn)的多維數(shù)據(jù)信息。
圖5 軌跡與SNR 多維數(shù)據(jù)可視化
(3)時(shí)序分析
根據(jù)時(shí)間標(biāo)簽將通信雙方的話音PTT 數(shù)據(jù)、收發(fā)話狀態(tài)數(shù)據(jù)進(jìn)行合并及缺失值處理,將數(shù)據(jù)項(xiàng)無(wú)效時(shí)刻替換為None(空值),進(jìn)行可視化如圖6所示,滑動(dòng)放大可直觀看出收發(fā)雙方的時(shí)序關(guān)系,對(duì)發(fā)話異常、PTT 按壓時(shí)間較短、話音搶發(fā)等情況進(jìn)行直觀分析。
圖6 話音時(shí)序
(1)盡量使用內(nèi)置函數(shù)
Python 標(biāo)準(zhǔn)庫(kù)中有很多內(nèi)置函數(shù)是使用C 語(yǔ)言編寫的,運(yùn)行效率很高,所以在功能實(shí)現(xiàn)時(shí)優(yōu)先使用內(nèi)置函數(shù)可提高程序運(yùn)行效率。
(2)矢量計(jì)算
對(duì)數(shù)據(jù)集進(jìn)行并行計(jì)算等矢量運(yùn)算可顯著提高運(yùn)算效率。在數(shù)據(jù)量較大情況下避免使用for…in 循環(huán)迭代,盡量采用apply、pandas series 矢量化及numpy arrays 矢量化,使用values 方法將鏈表Pandas series 轉(zhuǎn)換為Numpy arrays 再進(jìn)行矢量運(yùn)算將會(huì)顯著提高運(yùn)算速度。
(3)多進(jìn)程與多線程
充分利用計(jì)算機(jī)的多核CPU 資源進(jìn)行并行處理,python 提供了非常好用的多進(jìn)程包multiprocessing,可輕松完成從單進(jìn)程到并發(fā)進(jìn)程的轉(zhuǎn)換,對(duì)數(shù)據(jù)密集型場(chǎng)景可極大提升處理效率。在GUI 設(shè)計(jì)時(shí),為了防止執(zhí)行較耗時(shí)任務(wù)時(shí)造成的界面無(wú)響應(yīng),應(yīng)利用Thread 函數(shù)將多個(gè)任務(wù)加入多線程處理。
(4)避免內(nèi)存過(guò)度消耗
(a)讀取結(jié)構(gòu)化數(shù)據(jù)時(shí)指定數(shù)據(jù)類型,對(duì)大型數(shù)據(jù)框要進(jìn)行分塊讀??;
(b)數(shù)據(jù)合并后進(jìn)行缺失值處理后進(jìn)行強(qiáng)制類型轉(zhuǎn)換,表5 為數(shù)據(jù)類型轉(zhuǎn)換前后內(nèi)存占用對(duì)比;
(c)對(duì)無(wú)用數(shù)據(jù)及時(shí)進(jìn)行刪除處理釋放內(nèi)存。
表5 數(shù)據(jù)類型轉(zhuǎn)換前后內(nèi)存消耗對(duì)比
使用python 及matlab 語(yǔ)言實(shí)現(xiàn)本通信系統(tǒng)數(shù)據(jù)分析對(duì)比如表6 所示,可看出python 語(yǔ)言在代碼簡(jiǎn)潔性、字節(jié)序列化、數(shù)據(jù)對(duì)齊、時(shí)間序列具有明顯優(yōu)勢(shì)。
表6 python 與matlab 性能對(duì)比
隨著大數(shù)據(jù)時(shí)代的日益發(fā)展,數(shù)據(jù)的獲取及分析已成為熱點(diǎn),python 語(yǔ)言成為目前數(shù)據(jù)分析領(lǐng)域最熱門的語(yǔ)言之一,可高效的實(shí)現(xiàn)數(shù)據(jù)分析,特別適合需求頻繁變化的敏捷開(kāi)發(fā)場(chǎng)景。隨著越來(lái)越多高效庫(kù)的開(kāi)發(fā)及活躍的社區(qū),python 的應(yīng)用會(huì)越來(lái)越廣泛[9]。本文利用python 實(shí)現(xiàn)了較大容量數(shù)據(jù)的解析、預(yù)處理、可視化等工作,并通過(guò)與matlab 語(yǔ)言的對(duì)比展示出了python 在數(shù)據(jù)分析領(lǐng)域的優(yōu)勢(shì),對(duì)通信系統(tǒng)數(shù)據(jù)分析提供了一條便捷途徑。