操作案例
這一節(jié)我們進行大型數(shù)據(jù)的案例演示,這里利用腳本創(chuàng)建一個10000000行的數(shù)據(jù)表。我們可以創(chuàng)建一個文本文檔,并命名為trades.q,里面的腳本內(nèi)容為創(chuàng)建一個trades表,具體如下:
mktrades:{[tickers; sz]
dt:2015.01.01+sz?31;
tm:sz?24:00:00.000;
sym:sz?tickers;
qty:10*1+sz?1000;
px:90.0+(sz?2001)%100;
t:([] dt; tm; sym; qty; px);
t:`dt`tm xasc t;
t:update px:6*px from t where sym=`goog;
t:update px:2*px from t where sym=`ibm;
t}
trades:mktrades[`aapl`goog`ibm; 10000000]
trades表的具體內(nèi)容如下:
q)trades
dt tm sym qty px
----------------------------------------
2015.01.01 00:00:01.129 aapl 6410 99.18
2015.01.01 00:00:02.099 aapl 5200 93.82
2015.01.01 00:00:02.670 ibm 6840 196.92
2015.01.01 00:00:02.885 goog 7400 610.98
2015.01.01 00:00:03.396 aapl 8460 97.14
2015.01.01 00:00:03.834 aapl 3980 107.63
2015.01.01 00:00:04.047 ibm 2220 206.14
2015.01.01 00:00:04.096 goog 3320 575.52
2015.01.01 00:00:04.435 ibm 7390 202.38
2015.01.01 00:00:04.551 ibm 3630 216.04
2015.01.01 00:00:04.772 aapl 3990 90.15
2015.01.01 00:00:05.014 aapl 970 98.43
2015.01.01 00:00:05.190 goog 2080 628.56
2015.01.01 00:00:05.254 goog 6720 641.22
2015.01.01 00:00:05.263 goog 8990 577.38
2015.01.01 00:00:05.795 goog 8000 621.72
2015.01.01 00:00:07.135 goog 4790 658.98
2015.01.01 00:00:08.103 ibm 5150 183.56
2015.01.01 00:00:08.121 goog 4060 568.02
2015.01.01 00:00:08.237 aapl 2640 101.79
..
另外我們再創(chuàng)建一個股票信息表instr,該表記錄了每支股票的基本信息。包括股票代碼,公司名稱,行業(yè)分類等字段。具體如下:
q)instr:([sym:`symbol$()] name:`symbol$(); industry:`symbol$())
q)`instr upsert (`ibm; `$"International Business Machines"; `$"Computer Services")
`instr
q)`instr upsert (`msft; `$"Microsoft"; `$"Software")
`instr
q)`instr upsert (`goog; `$"Google"; `$"Search")
`instr
q)`instr upsert (`aapl; `$"Apple"; `$"Electronics")
`instr
q)instr
sym | name industry
----| -------------------------------------------------
ibm | International Business Machines Computer Services
msft| Microsoft Software
goog| Google Search
aapl| Apple Electronics
q)update `instr$sym from `trades /這時我們需要將股票信息表與股票交易表的股票代碼對應(yīng)起來,
因此我們將股票信息表的sym字段(主鍵)更新為股票交易表的sym字段的外鍵,建立兩個表之間的對應(yīng)聯(lián)系
`trades
q)meta trades /查詢股票交易表的結(jié)構(gòu)信息,有一個表instr的sym字段作為外鍵
c | t f a
---| ---------
dt | d s
tm | t
sym| s instr
qty| j
px | f
q)meta instr
c | t f a
--------| -----
sym | s
name | s
industry| s
1. 基本查詢
首先是對一個表的有多少條數(shù)據(jù)記錄的一個統(tǒng)計,這里有好幾種方式來進行查詢統(tǒng)計,分別如下:
q)count trades
10000000
q)exec count i from trades /這里的i為前面介紹的虛擬列
10000000
q)select count i from trades
x
--------
10000000
q)exec count i from trades where sym=`ibm
3329912
q)select count i from trades where sym=`ibm
x
-------
3329912
q)select count i by sym from trades
sym | x
----| -------
aapl| 3333508
goog| 3336580
ibm | 3329912
q)() xkey select count i by sym from trades / xkey是將主鍵變?yōu)槠胀ǖ淖侄?sym x
------------
aapl 3333508
goog 3336580
ibm 3329912
現(xiàn)在我們想查詢一下aapl這支股票在2015.01.05這一天的所有交易記錄。則可以使用條件查詢where語句。
q)select from trades where dt=2015.01.05, sym=`aapl
dt tm sym qty px
----------------------------------------
2015.01.05 00:00:01.680 aapl 3420 99.62
2015.01.05 00:00:02.113 aapl 5270 104.25
2015.01.05 00:00:02.151 aapl 7750 90.93
2015.01.05 00:00:02.360 aapl 2180 102.86
2015.01.05 00:00:02.461 aapl 8900 95.35
2015.01.05 00:00:03.537 aapl 7330 104.03
2015.01.05 00:00:04.406 aapl 8400 96.76
2015.01.05 00:00:05.013 aapl 7600 90.46
2015.01.05 00:00:05.015 aapl 8240 107.35
2015.01.05 00:00:06.652 aapl 2910 90.39
2015.01.05 00:00:06.686 aapl 7020 108.23
2015.01.05 00:00:07.806 aapl 7550 98.62
2015.01.05 00:00:08.832 aapl 7520 104.62
2015.01.05 00:00:09.468 aapl 3760 102.01
2015.01.05 00:00:09.877 aapl 8880 105.8
2015.01.05 00:00:11.006 aapl 7510 103.09
2015.01.05 00:00:14.255 aapl 3820 104.78
2015.01.05 00:00:15.386 aapl 2910 99.84
2015.01.05 00:00:15.814 aapl 3610 90.9
2015.01.05 00:00:15.895 aapl 7100 105.39
..
現(xiàn)在我們還想查詢一下goog這支股票在某天某個時間段內(nèi)的股票交易數(shù)據(jù),具體操作如下:
q)select from trades where sym=`goog, dt=2015.01.05, tm within 12:00:00 13:00:00
dt tm sym qty px
----------------------------------------
2015.01.05 12:00:01.255 goog 8460 578.1
2015.01.05 12:00:01.393 goog 4960 579.12
2015.01.05 12:00:05.226 goog 6140 594.54
2015.01.05 12:00:06.974 goog 1750 613.74
2015.01.05 12:00:07.007 goog 6980 618.18
2015.01.05 12:00:08.872 goog 3690 655.08
2015.01.05 12:00:09.877 goog 4520 644.04
2015.01.05 12:00:10.696 goog 8010 604.26
2015.01.05 12:00:10.862 goog 730 552.6
2015.01.05 12:00:13.299 goog 1520 540.42
2015.01.05 12:00:13.582 goog 1700 651.72
2015.01.05 12:00:14.863 goog 3180 651.12
2015.01.05 12:00:14.940 goog 9550 550.68
2015.01.05 12:00:15.150 goog 3080 603.9
2015.01.05 12:00:15.238 goog 1350 579.54
2015.01.05 12:00:16.309 goog 8330 585.3
2015.01.05 12:00:16.475 goog 2640 618.48
2015.01.05 12:00:16.647 goog 9660 622.26
2015.01.05 12:00:16.702 goog 5950 590.34
2015.01.05 12:00:17.351 goog 8120 625.56
..
上述的within的使用,我們也可以利用變量的形式,這樣我們就可以通過變量來靈活的查詢一些時間段的交易數(shù)據(jù)了。
q)noon:12:00:00
q)thirteen00:13:00:00
q)select from trades where sym=`goog, tm within (noon;thirteen00)
dt tm sym qty px
----------------------------------------
2015.01.01 12:00:00.316 goog 4320 597.66
2015.01.01 12:00:00.374 goog 7370 552.66
2015.01.01 12:00:03.617 goog 1150 640.02
2015.01.01 12:00:04.193 goog 4190 622.8
2015.01.01 12:00:06.546 goog 290 655.2
2015.01.01 12:00:07.248 goog 6650 553.62
2015.01.01 12:00:08.245 goog 9780 557.34
2015.01.01 12:00:09.378 goog 6900 571.74
2015.01.01 12:00:09.515 goog 3920 554.82
2015.01.01 12:00:09.600 goog 5740 608.22
2015.01.01 12:00:09.750 goog 5530 653.16
2015.01.01 12:00:09.756 goog 2900 590.64
2015.01.01 12:00:10.203 goog 90 605.22
2015.01.01 12:00:10.517 goog 1830 591.78
2015.01.01 12:00:11.619 goog 1820 654.06
2015.01.01 12:00:12.528 goog 9290 603.96
2015.01.01 12:00:12.557 goog 4340 571.68
2015.01.01 12:00:12.665 goog 7530 571.32
2015.01.01 12:00:13.229 goog 8180 555.6
2015.01.01 12:00:13.383 goog 170 580.92
..
現(xiàn)在我們還需要查詢aapl這支股票每天交易的最高價格,因此需要對dt進行分組,然后通過max的聚合函數(shù)來進行分組查詢。
q)select maxpx: max px by dt from trades where sym=`aapl
/(由于我們在利用腳本創(chuàng)建交易表的時候px使用的是均勻分布函數(shù)隨機生成的,因此每天的最高價格是恒定的)
dt | maxpx
----------| -----
2015.01.01| 110
2015.01.02| 110
2015.01.03| 110
2015.01.04| 110
2015.01.05| 110
2015.01.06| 110
2015.01.07| 110
2015.01.08| 110
2015.01.09| 110
2015.01.10| 110
2015.01.11| 110
2015.01.12| 110
2015.01.13| 110
2015.01.14| 110
2015.01.15| 110
2015.01.16| 110
2015.01.17| 110
2015.01.18| 110
2015.01.19| 110
2015.01.20| 110
..
現(xiàn)在我們查詢一下每支股票在交易表中的最低價和最高價分別是多少,這里我們可以通過交易表的外鍵從股票信息表中先去獲得每支股票對應(yīng)的公司全稱,然后進行分組,最后來進行聚合查詢,找出最小值和最大值
q)select lo: min px, hi: max px by sym.name from trades
name | lo hi
-------------------------------| -------
Apple | 90 110
Google | 540 660
International Business Machines| 180 220
我們還可以查詢一下某支股票的總的交易量和平均交易量,平均交易量是交易表中的所有交易總和除以交易記錄的總數(shù)
q)select totq: sum qty, avgq: avg qty by sym from trades where sym in `ibm`goog
sym | totq avgq
----| --------------------
goog| 16703515390 5006.179
ibm | 16667961470 5005.526
對于股票交易數(shù)據(jù),可能我們比較感興趣的是每天的最高價,最低價,開盤價和收盤價個,因此我們可以通過每天進行分組,然后查詢每天對應(yīng)的四個價格。
q)select hi: max px, lo: min px, open: first px, close: last px by dt from trades where sym=`goog
dt | hi lo open close
----------| ---------------------
2015.01.01| 660 540 610.98 568.92
2015.01.02| 660 540 565.08 615
2015.01.03| 660 540 623.7 629.82
2015.01.04| 660 540 642.72 650.58
2015.01.05| 660 540 627.54 571.68
2015.01.06| 660 540 647.76 553.68
2015.01.07| 660 540 547.74 638.76
2015.01.08| 660 540 596.04 647.52
2015.01.09| 660 540 584.7 657.78
2015.01.10| 660 540 562.86 619.44
2015.01.11| 660 540 575.04 587.22
2015.01.12| 660 540 649.2 587.52
2015.01.13| 660 540 651.12 563.1
2015.01.14| 660 540 651.18 649.56
2015.01.15| 660 540 588.6 644.16
2015.01.16| 660 540 614.4 622.5
2015.01.17| 660 540 643.2 629.46
2015.01.18| 660 540 659.82 615.9
2015.01.19| 660 540 632.1 627.96
2015.01.20| 660 540 651 590.58
..
我們也可以通過定義一個自己的函數(shù)來進行查詢,這里定義了一個favg的函數(shù),該函數(shù)的功能為一個特殊的加權(quán)平均。
q)favg:{(sum x*1+til ctx)%ctx*ctx:count x}
q)select favgpx: favg px by sym from trades /使用自定義函數(shù)進行查詢操作
sym | favgpx
----| --------
aapl| 50.00125
goog| 300.0098
ibm | 100.0079
2. 內(nèi)容查詢
現(xiàn)在我們對交易表進行一些高級的內(nèi)容查詢與操作,這里常見的就是數(shù)學(xué)上的操作了。畢竟是金融數(shù)據(jù),那更多的也是做統(tǒng)計與分析。
首先是我們對交易表trades的數(shù)據(jù)對每天的交易數(shù)據(jù)根據(jù)交易量與交易價格做一個加權(quán)平均,具體如下:
q)select vwap: qty wavg px by dt from trades where sym=`ibm
dt | vwap
----------| --------
2015.01.01| 200.0045
2015.01.02| 199.9817
2015.01.03| 200.0193
2015.01.04| 199.9379
2015.01.05| 199.9636
2015.01.06| 200.0109
2015.01.07| 199.9824
2015.01.08| 200.0055
2015.01.09| 199.951
2015.01.10| 199.985
2015.01.11| 200.0282
2015.01.12| 200.0326
2015.01.13| 200.0374
2015.01.14| 200.0502
2015.01.15| 200.0283
2015.01.16| 200.0439
2015.01.17| 199.9993
2015.01.18| 199.9977
2015.01.19| 200.0171
2015.01.20| 199.9833
..
q)select vwap: qty wavg px by dt, 100 xbar tm from trades where sym=`ibm
/這里100 xbar tm表示在tm字段中以100為單位步長來進行統(tǒng)計分組
dt tm | vwap
-----------------------| --------
2015.01.01 00:00:02.600| 196.92
2015.01.01 00:00:04.000| 206.14
2015.01.01 00:00:04.400| 202.38
2015.01.01 00:00:04.500| 216.04
2015.01.01 00:00:08.100| 183.56
2015.01.01 00:00:08.600| 210.06
2015.01.01 00:00:10.000| 209
2015.01.01 00:00:11.100| 193.6189
2015.01.01 00:00:12.000| 182.24
2015.01.01 00:00:12.400| 181.94
2015.01.01 00:00:12.700| 190.52
2015.01.01 00:00:13.900| 199.22
2015.01.01 00:00:14.000| 204.22
2015.01.01 00:00:14.400| 184.42
2015.01.01 00:00:15.400| 207.2981
2015.01.01 00:00:16.200| 188.4
2015.01.01 00:00:16.500| 206.68
2015.01.01 00:00:16.900| 200.92
2015.01.01 00:00:21.100| 207.2
2015.01.01 00:00:21.600| 207.94
..
前面我們介紹過fby,fby其實你就可以理解為我們需要查詢很多字段,但是只能用其中一個字段進行分組查詢,而且其他字段也涉及一些其他操作,如找出最大值,最小值或者做一些信息統(tǒng)計,這時我們只能用fby,用by分組查詢的結(jié)果是不對的。這里我們使用sym字段進行分組,但是需要對px字段進行加權(quán)平均,同時進行比較操作。具體如下:
q)select from trades where px<2*(favg;px) fby sym
dt tm sym qty px
----------------------------------------
2015.01.01 00:00:01.129 aapl 6410 99.18
2015.01.01 00:00:02.099 aapl 5200 93.82
2015.01.01 00:00:02.670 ibm 6840 196.92
2015.01.01 00:00:03.396 aapl 8460 97.14
2015.01.01 00:00:04.096 goog 3320 575.52
2015.01.01 00:00:04.772 aapl 3990 90.15
2015.01.01 00:00:05.014 aapl 970 98.43
2015.01.01 00:00:05.263 goog 8990 577.38
2015.01.01 00:00:08.103 ibm 5150 183.56
2015.01.01 00:00:08.121 goog 4060 568.02
2015.01.01 00:00:09.888 goog 2830 540.72
2015.01.01 00:00:10.048 aapl 3830 99.15
2015.01.01 00:00:10.683 aapl 4420 92.14
2015.01.01 00:00:10.848 goog 5740 595.86
2015.01.01 00:00:10.994 aapl 6180 91.17
2015.01.01 00:00:11.126 ibm 8520 188.3
2015.01.01 00:00:12.051 ibm 6740 182.24
2015.01.01 00:00:12.494 ibm 2160 181.94
2015.01.01 00:00:12.790 ibm 5330 190.52
2015.01.01 00:00:13.978 ibm 7790 199.22
..
q)show atrades:select avgqty:avg qty, avgpx:avg px by sym, dt from trades /查詢每支股票每天的數(shù)據(jù),返回每天的平均交易量與價格
sym dt | avgqty avgpx
---------------| -----------------
aapl 2015.01.01| 4989.021 99.97649
aapl 2015.01.02| 5004.019 100.0455
aapl 2015.01.03| 5011.448 99.99385
aapl 2015.01.04| 5002.787 99.9908
aapl 2015.01.05| 5000.981 100.0157
aapl 2015.01.06| 5004.591 100.0176
aapl 2015.01.07| 4995.854 100.0034
aapl 2015.01.08| 5015.4 99.9729
aapl 2015.01.09| 5001.951 99.98638
aapl 2015.01.10| 5006.982 99.95917
aapl 2015.01.11| 5024.328 99.97282
aapl 2015.01.12| 5004.368 100.0091
aapl 2015.01.13| 5008.056 100.019
aapl 2015.01.14| 4995.221 100.0486
aapl 2015.01.15| 5016.942 99.99451
aapl 2015.01.16| 5015.834 100.0232
aapl 2015.01.17| 5001.7 99.96238
aapl 2015.01.18| 5005.672 99.99492
aapl 2015.01.19| 4998.789 100.0035
aapl 2015.01.20| 5007.235 100.0249
..
q)deltas0:{first[x] -': x} /利用前面我們介紹的each-previous(':)來返回所給數(shù)據(jù)的一個增量
q)select dt, avgpx by sym from atrades where 0< deltas0 avgpx
/這里我們查詢的是atrades表(每支股票的每天的平均交易與平均價格的數(shù)據(jù))中的那些股票有上漲的數(shù)據(jù)(只要滿足后一條數(shù)據(jù)比前一條大,不是連續(xù)的一直增長)

q)select 2#dt, 2#avgpx by sym from atrades where 0<deltas0 avgpx /由于返回的結(jié)果每個字段內(nèi)容太多,因為我們用2#操作來只顯示每個字段的每條記錄中的前兩條數(shù)據(jù)(可以與上面一條數(shù)據(jù)進行對比一下)。
sym | dt avgpx
----| ---------------------------------------
aapl| 2015.01.02 2015.01.05 100.0455 100.0157
goog| 2015.01.01 2015.01.04 599.9548 599.9773
ibm | 2015.01.02 2015.01.03 199.9966 200.043
下面的一些操作就是常見的統(tǒng)計類的操作,可以仔細理解一下。
q)dntrades:select dt,tm,qty,px by sym from trades
q)dntrades

q)dntrades~`sym xasc `sym xgroup trades
1b
q)select 2#dt, 2#tm, 2#qty, 2#px by sym from trades

q)select sym, cnt: count each dt, avgpx: avg each px from dntrades
sym cnt avgpx
---------------------
aapl 3333508 100.0015
goog 3336580 600.0047
ibm 3329912 200.0113
q)select sym, favgpx: favg each px from dntrades
sym favgpx
-------------
aapl 50.00125
goog 300.0098
ibm 100.0079
q)select sym, vwap:qty wavg' px from dntrades
sym vwap
-------------
aapl 100.0014
goog 600.0047
ibm 200.0067
q)select max px-mins px by sym from trades
/對于股票數(shù)據(jù),我們很多時候也會關(guān)注股票的最高價和最低價,下面就是我們查詢一直股票在交易記錄中的最高價與最低價的一個差值
sym | px
----| ---
aapl| 20
goog| 120
ibm | 40
q)select min px-maxs px by sym from trades /與上面一樣,
sym | px
----| ----
aapl| -20
goog| -120
ibm | -40
3. 數(shù)據(jù)透視表
在Excel中,數(shù)據(jù)透視表其實就是把表的一個版面布置進行改變,以便按照不同方式分析數(shù)據(jù),也可以重新安排行號、列標(biāo)和頁字段。其實就是表現(xiàn)有表一個重新布局操作(練習(xí)這個之前我們可以先去看看Excel的數(shù)據(jù)透視表的具體邏輯和操作,可以參考這個:https://baijiahao.baidu.com/s?id=1612743724635387723&wfr=spider&for=pc)。比如我們在Q中有下面一表t(包含了周幾week,姓名name,銷售量sales):
q)show t:([]week:1 2 3 2 3; name:`zhangsan`lisi`zhangsan`wangwu`lisi; sales:100 200 300 400 500)
week name sales
-------------------
1 zhangsan 100
2 lisi 200
3 zhangsan 300
2 wangwu 400
3 lisi 500
但是我們好像看不出這張表的整體數(shù)據(jù)情況一下,我們想一眼就能看出每個人對應(yīng)的一個每天的一個具體銷量,比如如下的形式:
week| zhangsan lisi wangwu
----| --------------------
1 | 100
2 | 200 400
3 | 300 500
這樣我們就能夠一下看出這張表的數(shù)據(jù)結(jié)構(gòu)信息,如zhangsan在周一(1)和周三(3)的銷售量分別是100和300,在周二(2)沒有銷售數(shù)據(jù)。跟Excel一樣,直觀的展現(xiàn)出來。這種操作在Q中也叫數(shù)據(jù)透視表。具體操作如下:
q) N:exec distinct name from t /首先我們需要確定name字段去重后有哪些人
q)N
`zhangsan`lisi`wangwu /這是去重后的信息
q)exec name!sales by week from t /然后我們需要把每個人和他每天的一個銷量對應(yīng)起來,并且人和銷量轉(zhuǎn)換成字典對應(yīng)的形式,并用天來分組
1| (,`zhangsan)!,100
2| `lisi`wangwu!200 400
3| `zhangsan`lisi!300 500
q)exec N#name!sales by week:week from t
/這個時候我們用去重后的人的信息作為表的新的字段,然后name!sales去匹配新的字段并更新,沒有匹配上的直接用空值表示,則得到如下信息
week| zhangsan lisi wangwu
----| --------------------
1 | 100
2 | 200 400
3 | 300 500
當(dāng)然上述操作我們也可以使用前面介紹的函數(shù)式查詢,就是利用如下形式來操作:
?[t;c;b;a] / select 與 exec查詢操作方式
![t;c;b;a] / update 與 delete查詢操作方式
N:exec distinct name from t 可以轉(zhuǎn)換為:
N:?[t; (); (); (distinct; `name)]exec N#name!sales by week:week from t 可以轉(zhuǎn)換為:
?[t;(); (1#week)!1#week; (#;N;(!;name;`sales))]
當(dāng)然了,我們也可以將上面的函數(shù)式查詢寫成一個函數(shù)形式,后面對于同樣的表,我們只需要傳遞參數(shù)即可:
q) dopivot:{[t; kn; pn; vn]
P:?[t; (); (); (distinct; pn)];
?[t;(); (1#kn)!1#kn; (#;`P;(!;pn;vn))]}
q)dopivot[t; `week; `name; `sales] /通過傳遞參數(shù)的形式來生成數(shù)據(jù)透視表
week| zhangsan lisi wangwu
----| --------------------
1 | 100
2 | 200 400
3 | 300 500
同樣我們現(xiàn)在有下面一張簡單的表tn,他的p字段是一個復(fù)雜的字段,包含symbol數(shù)據(jù)和int數(shù)據(jù):
q)tn:([] k:1 2 3 2 3; p:(`a1;2;`a1;3;2); v:100 200 300 400 500)
q)tn
k p v
---------
1 `a1 100
2 2 200
3 `a1 300
2 3 400
3 2 500
這時我們也可以做數(shù)據(jù)透視表,但是使用之前的形式就不可以了:
q)dopivot[t; `k; `p; `v]
'type
/我們使用上面的形式就會報錯,因為數(shù)據(jù)類型不匹配,
這個時候我們就需要對tn表的一個p字段進行處理一下,都轉(zhuǎn)換成symbol形式,
2我們可以轉(zhuǎn)換為`X_2的形式,3為`X_3,具體轉(zhuǎn)換方式如下,我們也可以寫成函數(shù)的形式:
q)mkNames:{
x:(::),x;
x:1_x:@[x; where not 10h=type each x; string];
`$@[x; where not any x[;0] within/: ("AZ";"az"); "X_",]}
mkNames函數(shù)中,我們使用的是隱式傳遞參數(shù)的形式,這里的參數(shù)就是x,第一行的目的是將傳進來的數(shù)據(jù)轉(zhuǎn)換成列表的形式(至于為什么要把::放在最前面我也沒看懂為啥,等我后面弄懂了修改這里吧,如果有懂了的小伙伴可以分享給我一下),第二行的目的是將x列表中不是字符串的形式轉(zhuǎn)換為字符轉(zhuǎn),第三行的意思是將x(此時為字符串式的列表)中那些不包含字母的字符串轉(zhuǎn)換為“X_原數(shù)據(jù)”的形式。
接下來我們就可以寫可以處理復(fù)雜字段的函數(shù)式生成數(shù)據(jù)透視表的函數(shù)了,具體如下:
q)dopivot:{[t; kn; pn; vn]
t:![t; (); 0b; (1#pn)!enlist (`mkNames; pn)];
P:?[t; (); (); (distinct; pn)];
?[t;(); (1#kn)!1#kn; (#;`P;(!;pn;vn))]}
該函數(shù)的后面兩行與前面我們寫的dopivot的形式一樣,只是在前面多加了一行t:![t; (); 0b; (1#pn)!enlist (`mkNames; pn)];這一行的目的就是講pn字段轉(zhuǎn)換為a1 X_2 X_3這種形式。
q)dopivot1[tn; `k; `p; `v] /最后就可以利用該函數(shù)生成新的數(shù)據(jù)透視表了
k| a1 X_2 X_3
-| -----------
1| 100
2| 200 400
3| 300 500
下面我們又有一張新表tr,同樣可以利用dopivot函數(shù)生成數(shù)據(jù)透視表:
q)tr:([]k:1 2 3 2 3 1; p:`a1`a2`a1`a3`a2`a1; v:100 200 300 400 500 1000)
q)tr
k p v
---------
1 a1 100
2 a2 200
3 a1 300
2 a3 400
3 a2 500
1 a1 1000
q)dopivot1[tr;`k;`p;`v]
k| a1 a2 a3
-| -----------
1| 100
2| 200 400
3| 300 500
但是通過對比,我們發(fā)現(xiàn)生成的數(shù)據(jù)透視表少了一條數(shù)據(jù),由于k為1時,對應(yīng)的a1有兩條v的數(shù)據(jù),但是只能在數(shù)據(jù)透視表中放一個數(shù)據(jù)(不能放復(fù)雜的列表),因此只選擇了放第一次匹配上的數(shù)據(jù)100,然后就將1000這條數(shù)據(jù)進行了省略。但是我們可以選擇將這兩條數(shù)據(jù)加起來處理,具體處理方式如下:
q)dopivot2:{[t; agg; kn; pn; vn]
t:![t; (); 0b; (1#pn)!enlist (`mkNames; pn)];
t:?[t; (); (kn,pn)!kn,pn; (1#vn)!enlist (agg;vn)];
P:?[t; (); (); (distinct; pn)];
?[t; (); (1#kn)!1#kn; (#;`P;(!;pn;vn))]}
在函數(shù)dopivot2中,我們又對傳進來的表t進行了處理,t:?[t; (); (kn,pn)!kn,pn; (1#vn)!enlist (agg;vn)];是將pn字段中相同的記錄中對應(yīng)的vn數(shù)據(jù)加起來。
q)dopivot2[tr;sum;`k;`p;`v] /最后我們生產(chǎn)的數(shù)據(jù)透視表如下,可以看書對a1數(shù)據(jù)的加處理:
k| a1 a2 a3
-| ------------
1| 1100
2| 200 400
3| 300 500