乾貨丨DolphinDB高頻數據處理技巧:非等間隔的時間序列處理

高頻時間序列的處理中,常常會用到滑動,偏移,聚合,轉置,關聯等操做。譬如說我想對一個某指標列用過去一個小時的數據的均值來作平滑處理,又或者想找到每個時刻,該指標一個小時前的相應的指標值。若是序列中每一個指標的間隔是相等的並且中間沒有缺失數據,譬如說0.5s,3s,那麼咱們能夠把時間窗口轉化成固定記錄條數的窗口,基本上經常使用的數據分析軟件語言均可以完成滑動窗口函數功能。若是條件不能知足,就變成了比較複雜的非等間隔的時間序列處理問題。數據庫

假設有一組這樣的數據:函數

time   val
------ ---
12:31m 1  
12:33m 2  
12:34m 3  
12:35m 4  
12:37m 5  
12:40m 6  
12:41m 7  
12:42m 8  
12:43m 9  
12:45m 10

咱們在每個時間點上,須要計算過去5分鐘內val的均值。因爲每條數據的時間間隔不相等,咱們不能肯定時間窗口的數據條數。所以,咱們須要將數據逐條與時間窗口的邊界對比,找到時間窗口中的數據,再計算avg(val)。性能

這一類問題,DolphinDB和kdb均提供了window join,能夠方便地完成這一任務。DolphinDB的實現腳本以下:測試

t=table(12:31m 12:33m 12:34m 12:35m 12:37m 12:40m 12:41m 12:42m 12:43m 12:45m as time,1..10 as val)
wj(t,t,-5:-1,<avg(val)>,`time)
time   val avg_val
------ --- -------
12:31m 1          
12:33m 2   1      
12:34m 3   1.5    
12:35m 4   2      
12:37m 5   3      
12:40m 6   4.5    
12:41m 7   5.5    
12:42m 8   6      
12:43m 9   7      
12:45m 10  7.5

window join須要提供左右表、時間窗口、聚合函數和鏈接列。左表用於指定發生計算的時間點,右表是原始數據。-5:-1是時間窗口,表示當前時刻的前5分鐘。若是時間窗口的上下邊界都爲正數,如1:5,表示當前時刻的後5分鐘。若是時間窗口的邊界爲0,如-5:0或0:5,表示當前時刻也包含在時間窗口內。若是時間窗口的上下邊界是一正一負,如-5:5,表示過去5分鐘到將來5分鐘,當前時刻也包含在窗口中。優化

下面詳細解釋一下計算過程。以第一條數據爲例,發生計算的時間點爲12:31m,數據窗口爲12:31m-5到12:31m-1,即12:26m到12:30m,上下邊界都包含在內。系統會在t中尋找時間在數據窗口的數據,並對它們計算avg(val),如此類推。code

上面的例子中,數據只包含一隻股票,若是數據包含多隻股票,要求每一時刻每隻股票過去5分鐘的avg(val),那要怎麼操做呢?window join能夠指定多個鏈接列,系統會先根據前面N - 1鏈接列作等值鏈接(equal join),在每個細分的組中,再根據最後一個鏈接列作window join。請看下面的例子,假設原始數據以下:blog

time   sym val
------ --- ---
12:31m A   1  
12:31m B   2  
12:33m A   3  
12:33m B   4  
12:34m B   5  
12:35m A   6  
12:35m B   7  
12:36m A   8  
12:28m A   9  
12:39m B   10 
12:40m A   11 
12:40m B   12

如今要計算每一時刻,過去5分鐘內每隻股票代碼的avg(val)。腳本以下:內存

t=table(12:31m 12:31m 12:33m 12:33m 12:34m 12:35m 12:35m 12:36m 12:28m 12:39m 12:40m 12:40m as time,`A`B`A`B`B`A`B`A`A`B`A`B as sym,1..12 as val)
wj(t,t,-5:-1,<avg(val)>,`sym`time)
time   sym val avg_val 
------ --- --- --------
12:31m A   1           
12:31m B   2           
12:33m A   3   1       
12:33m B   4   2       
12:34m B   5   3       
12:35m A   6   2       
12:35m B   7   3.666667
12:36m A   8   3.333333
12:28m A   9           
12:39m B   10  6       
12:40m A   11  7.666667
12:40m B   12  8.5

以左表的第一條數據爲例,sym=A,time=12:31m,所以數據窗口爲12:26m到12:30m,系統會在右表中尋找在時間窗口中的數據,而且sym=A的數據來計算avg(val)。get

DolphinDB的window join支持任意聚合函數,既支持內置的avg、beta、count、corr、covar、first、last、max、med、min、percentile、std、sum、sum二、var和wavg, 也能夠支持用戶自定義的聚合函數;聚合函數的參數能夠是一個,也能夠是多個;參數既能夠是表中的某一列,也能夠是一個計算字段。數據分析

和不一樣的聚合函數結合,能夠知足不少業務場景的須要。試想這樣一個場景,有兩個表t1和t2,它們的內容以下:

t1=table(1 3 5 7 2 as id, 2012.06.12 2013.06.26 2014.06.14 2015.06.23 2016.06.19 as date)
t2=table(1 2 6 7 8 as id,5 2 4 7 9 as val,2014.10.20 2015.02.05 2016.08.15 2017.12.23 2018.06.23 as date)

如今要找出t2中與t1的id對應,而且時間在t1時間以後的第一條記錄。使用DolphinDB能夠很是方便地實現:

wj(t1,t2,1:(365*100),<first(val)>,`id`date)
id date       first_val
-- ---------- ---------
1  2012.06.12 5        
3  2013.06.26          
5  2014.06.14          
7  2015.06.23 7        
2  2016.06.19

這裏咱們設置的數據窗口是1:36500,即100年。這是爲了防止t2中每條數據date2的間隔過大,數據沒有落在數據窗口中的狀況出現。在傳統數據庫中,如SQL Server,須要經過自定義函數來實現。代碼以下:

create table t1(id int,date date)
insert into t1 values(1,'2012-06-12')
insert into t1 values(3,'2013-06-26')
insert into t1 values(5,'2014-06-14')
insert into t1 values(7,'2015-06-23')
insert into t1 values(2,'2016-06-19')
go
create table t2(id int,val int,date date)
insert into t2 values(1,5,'2014-10-20')
insert into t2 values(2,2,'2015-02-05')
insert into t2 values(6,4,'2016-08-15')
insert into t2 values(7,7,'2017-12-23')
insert into t2 values(8,9,'2018-06-23')
go

create function [dbo].[getRight]
(
	@curid int,
	@curdate date
)
returns int
as
begin
	declare @reV int
	select top 1 @reV = val from t2 where id=@curid and date>=@curdate
	return @reV
end
go

select id,date,dbo.getRight(id,date) as 'first' from t1

SQL Server的性能較差,DolphinDB大約比SQL Server快300倍。

pandas的rolling函數只能處理等時間間隔的數據,不能處理非等時間間隔的數據。DolphinDB和kdb+則均可解決。下面咱們隨機生成一個一千萬行的表來測試DolphinDB和kdb+中window join的性能。測試使用的機器配置以下:

CPU:Intel(R) Core(TM) i7-7700 CPU @3.60GHz 3.60 GHz

內存:16GB

OS:Windows 10

DolphinDB腳本以下:

n=10000000
t=select * from table(rand(2012.06.12T12:00:00.000..2012.06.30T12:00:00.000,n) as time,rand(`A`B`C`D`E,n) as sym,rand(100.0,n) as x) order by time 
timer wj(t,t,-6:0,<avg(x)>,`sym`time)

kdb+腳本以下:

n:10000000
t:`sym`time xasc ([]time:2012.06.12T12:00 + (n ? 1000000);sym:n ? `A`B`C`D`E;x:n ? 100.0)
update `p#sym from `t
f:`sym`time
w:-6 0+\:t.time
\t wj1[w;f;t;(t;(avg;`x))]

DolphinDB耗時456毫秒,kdb+耗時 16,398毫秒。咱們調整時間窗口的長度,測試DolphinDB和kdb+的表現如何。時間窗口爲60毫秒,DolphinDB耗時455毫秒,kdb+耗時21,521毫秒;時間窗口爲600毫秒,DolphinDB耗時500毫秒,kdb+耗時73,649毫秒。能夠看到,DolphinDB window join的性能與窗口長度無關,而kdb+ wj1中的性能與窗口的長度有關,窗口越長,耗時越長。這是由於DolphinDB對內置的聚合函數avg作了優化,在window join中的計算速度與窗口無關。這些優化的聚合函數包括avg、beta、count、corr、covar、first、last、max、med、min、percentile、std、sum、sum二、var和wavg。

相關文章
相關標籤/搜索