1. 程式人生 > 其它 >高頻資料處理技巧:資料庫非等間隔的時間序列處理

高頻資料處理技巧:資料庫非等間隔的時間序列處理

技術標籤:時序資料庫使用教程高頻交易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),如此類推。

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

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)。

DolphinDB的window join支援任意聚合函式,既支援內建的avg、beta、count、corr、covar、first、last、max、med、min、percentile、std、sum、sum2、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 [email protected] and date>[email protected]
	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、sum2、var和wavg。

DolphinDB database 下載:www.dolphindb.cn