q functions and operators¶
This page documents the KDB-X Python implementations of a selection of keywords and operators available in q.
The functions listed here are accessible in KDB-X Python as attributes of pykx.q, or as attributes of pykx.QConnection instances. Refer to the q reference card in the q docs for more details about these functions as they are used in a q process. This page documents using them in Python via KDB-X Python.
These functions take and return q objects, which are wrapped in KDB-X Python as pykx.K objects. Any arguments of other types are converted appropriately. Refer to the KDB-X Python wrappers documentation for more information about pykx.K objects.
By Category¶
Some keywords listed on the q reference card are unavailable in this API:
-
select,exec,updateanddeleteare not q functions, but a part of the q language itself -
functions that have names which would result in syntax errors in Python, such as
notandor
The unavailable functions can still be used in KDB-X Python by executing q code with pykx.q, i.e. pykx.q('not') instead of pykx.q.not. For the qSQL functions (select, exec, update, and delete) use KDB-X Python qSQL.
Environment¶
getenv¶
Get the value of an environment variable.
>>> pykx.q.getenv('EDITOR')
pykx.CharVector(q('"nvim"'))
gtime¶
UTC equivalent of local timestamp.
>>> import datetime
>>> pykx.q.gtime(datetime.datetime.fromisoformat('2022-05-22T12:23:45.123'))
pykx.TimestampAtom(q('2022.05.22D16:23:45.123000000'))
ltime¶
Local equivalent of UTC timestamp.
>>> import datetime
>>> pykx.q.ltime(datetime.datetime.fromisoformat('2022-05-22T12:23:45.123'))
pykx.TimestampAtom(q('2022.05.22D08:23:45.123000000'))
setenv¶
Set the value of an environment variable.
>>> pykx.q.setenv('RTMP', b'/home/user/temp')
>>> pykx.q.getenv('RTMP')
pykx.CharVector(q('"/home/user/temp"'))
Interpret¶
eval¶
Evaluate parse trees.
>>> pykx.q.eval([pykx.q('+'), 2, 3])
pykx.LongAtom(q('5'))
parse¶
Parse a char vector into a parse tree, which can be evaluated with pykx.q.eval.
>>> pykx.q.parse(b'{x * x}')
pykx.Lambda(q('{x * x}'))
>>> pykx.q.parse(b'2 + 3')
pykx.List(pykx.q('
+
2
3
'))
reval¶
Restricted evaluation of a parse tree.
Behaves similar to eval except the evaluation is blocked from modifying state for any handle context other than 0.
>>> pykx.q.reval(pykx.q.parse(b'til 10'))
pykx.LongVector(q('0 1 2 3 4 5 6 7 8 9'))
show¶
Print the string representation of the given q object.
Note: show bypasses typical Python output redirection.
The q function show prints directly to file descriptor 1, so typical Python output redirection methods, e.g. contextlib.redirect_stdout, will not affect it.
>>> pykx.q.show(range(5))
0
1
2
3
4
pykx.Identity(q('::'))
system¶
Execute a system command.
Where x is a string representing a system command and any parameters to it, executes the command and returns any result.
>>> pykx.q.system(b'pwd')
pykx.List(q('"/home/user"'))
value¶
Returns the value of x.
| Input Type | Output Type |
|---|---|
| dictionary | value of the dictionary |
| symbol atom | value of the variable it names |
| enumeration | corresponding symbol vector |
| string | result of evaluating it in current context |
| list | result of evaluating list as a parse tree |
| projection | list: function followed by argument/s |
| composition | list of composed values |
| derived function | argument of the iterator |
| operator | internal code |
| view | list of metadata |
| lambda | structure |
| file symbol | content of datafile |
>>> pykx.q.value(pykx.q('`q`w`e!(1 2; 3 4; 5 6)'))
pykx.List(q('
1 2
3 4
5 6
'))
IO¶
dsave¶
Write global tables to disk as splayed, enumerated, indexed q tables.
>>> from pathlib import Path
>>> pykx.q['t'] = kx.Table(data={'x': [1, 2, 3], 'y': [10, 20, 30]})
>>> pykx.q.dsave(Path('v'), 't')
pykx.SymbolAtom(q('`t'))
get¶
Read or memory-map a variable or q data file.
>>> pykx.q['a'] = 10
>>> pykx.q.get('a')
pykx.LongAtom(q('10'))
hclose¶
Where x is a connection handle, closes the connection, and destroys the handle.
>>> pykx.q.hclose(pykx.q('3i'))
hcount¶
Size of a file in bytes.
>>> pykx.q.hcount('example.txt')
pykx.LongAtom(q('11'))
hdel¶
Where x is a file symbol atom, deletes the file or folder (if empty), and returns x.
>>> pykx.q.hdel('example.txt')
hopen¶
Open a connection to a file or process.
>>> pykx.q.hopen('example.txt')
pykx.IntAtom(q('3i'))
hsym¶
Convert symbols to handle symbols, which can be used for I/O as file descriptors or handles.
>>> pykx.q.hsym('10.43.23.197')
pykx.SymbolAtom(q('`:10.43.23.197'))
load¶
Load binary data from a file.
>>> pykx.q['t'] = pykx.Table([[1, 10], [2, 20], [3, 30]], columns=['x', 'y'])
>>> pykx.q('t')
pykx.Table(pykx.q('
x y
----
1 10
2 20
3 30
'))
>>> pykx.q.save('t') # Save t to disk
pykx.SymbolAtom(pykx.q('`:t'))
>>> pykx.q('delete t from `.') # Delete t from memory
pykx.SymbolAtom(pykx.q('`.'))
>>> pykx.q('t') # t is not longer defined
Traceback (most recent call last):
pykx.exceptions.QError: t
>>> pykx.q.load('t') # Load t from disk
pykx.SymbolAtom(pykx.q('`t'))
>>> pykx.q('t')
pykx.Table(pykx.q('
x y
----
1 10
2 20
3 30
'))
read0¶
Read text from a file or process handle.
>>> pykx.q.read0('example.txt')
pykx.List(q('
"Hello"
"World"
'))
read1¶
Read bytes from a file or named pipe.
>>> pykx.q.read1('example.txt')
pykx.ByteVector(q('0x48656c6c6f0a576f726c64'))
rload¶
Load a splayed table from a directory.
>>> pykx.q.rload('t')
>>> pykx.q('t')
pykx.Table(q('
x y
----
1 10
2 20
3 30
'))
rsave¶
Write a table splayed to a directory.
>>> pykx.q['t'] = pykx.Table([[1, 10], [2, 20], [3, 30]])
>>> pykx.q.rsave('t')
pykx.SymbolAtom(q('`:t/'))
save¶
Write global data to file or splayed to a directory.
>>> pykx.q['t'] = pykx.Table([[1, 10], [2, 20], [3, 30]])
>>> pykx.q.save('t')
pykx.SymbolAtom(q('`:t'))
set¶
Assign a value to a global variable.
Persist an object as a file or directory.
| Types | Result |
|---|---|
| pykx.q.set(nam, y) | set global nam to y |
| pykx.q.set(fil, y) | write y to a file |
| pykx.q.set(dir, y) | splay y to a directory |
| pykx.q.set([fil, lbs, alg, lvl], y) | write y to a file, compressed |
| pykx.q.set([dir, lbs, alg, lvl], y) | splay y to a directory, compressed |
| pykx.q.set([dir, dic], y) | splay y to a directory, compressed |
Where
| Abbreviation | K type | Explanation |
|---|---|---|
| alg | integer atom | compression algorithm |
| dic | dictionary | compression specifications |
| dir | filesymbol | directory in the filesystem |
| fil | filesymbol | file in the filesystem |
| lbs | integer atom | logical block size |
| lvl | integer atom | compression level |
| nam | symbol atom | valid q name |
| t | table | |
| y | (any) | any q object |
Compression parameters alg, lbs, and lvl
Compression specification dictionary
>>> pykx.q.set('a', 42)
pykx.SymbolAtom(q('`a'))
>>> pykx.q('a')
pykx.LongAtom(q('42'))
Iterate¶
each¶
Iterate over list and apply a function to each element.
>>> pykx.q.each(pykx.q.count, [b'Tis', b'but', b'a', b'scratch'])
pykx.LongVector(q('3 3 1 7'))
>>> pykx.q.each(pykx.q.sums, [[2, 3, 4], [[5, 6], [7, 8]], [9, 10, 11, 12]])
pykx.List(q('
2 5 9
((5;6);12 14)
9 19 30 42
'))
over¶
The keywords over and scan are covers for the accumulating iterators, Over and Scan. It is good style to use over and scan with unary and binary values.
Just as with Over and Scan, over and scan share the same syntax and perform the same computation; but while scan returns the result of each evaluation, over returns only the last.
>>> pykx.q.over(pykx.q('*'), [1, 2, 3, 4, 5])
pykx.LongAtom(q('120'))
peach¶
each and peach perform the same computation and return the same result, but peach will parallelize the work across available threads.
>>> pykx.q.peach(pykx.q.count, [b'Tis', b'but', b'a', b'scratch'])
pykx.LongVector(q('3 3 1 7'))
>>> pykx.q.peach(pykx.q.sums, [[2, 3, 4], [[5, 6], [7, 8]], [9, 10, 11, 12]])
pykx.List(q('
2 5 9
((5;6);12 14)
9 19 30 42
'))
prior¶
Applies a function to each item of x and the item preceding it, and returns a result of the same length.
>>> pykx.q.prior(pykx.q('+'), [1, 2, 3, 4, 5])
pykx.LongVector(pykx.q('1 3 5 7 9'))
>>> pykx.q.prior(lambda x, y: x + y, pykx.LongVector([1, 2, 3, 4, 5]))
pykx.LongVector(pykx.q('0N 3 5 7 9'))
scan¶
The keywords over and scan are covers for the accumulating iterators, Over and Scan. It is good style to use over and scan with unary and binary values.
Just as with Over and Scan, over and scan share the same syntax and perform the same computation; but while scan returns the result of each evaluation, over returns only the last.
>>> pykx.q.scan(pykx.q('+'), [1, 2, 3, 4, 5])
pykx.LongVector(q('1 3 6 10 15'))
Join¶
aj¶
Performs an as-of join across temporal columns in tables. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.
The resulting time column is the value of the boundary used in the first table.
>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
... 'time': np.array([36061, 36063, 36064], dtype='timedelta64[s]'),
... 'sym': ['msft', 'ibm', 'ge'], 'qty': [100, 200, 150]
... })
>>> df2 = pd.DataFrame({
... 'time': np.array([36060, 36060, 36060, 36062], dtype='timedelta64[s]'),
... 'sym': ['ibm', 'msft', 'msft', 'ibm'], 'qty': [100, 99, 101, 98]
... })
>>> pykx.q.aj(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time sym qty
-----------------------------
0D10:01:01.000000000 msft 101
0D10:01:03.000000000 ibm 98
0D10:01:04.000000000 ge 150
'))
aj0¶
Performs an as-of join across temporal columns in tables. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.
The resulting time column is the actual time of the last value in the second table.
>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
... 'time': np.array([36061, 36063, 36064], dtype='timedelta64[s]'),
... 'sym': ['msft', 'ibm', 'ge'], 'qty': [100, 200, 150]
... })
>>> df2 = pd.DataFrame({
... 'time': np.array([36060, 36060, 36060, 36062], dtype='timedelta64[s]'),
... 'sym': ['ibm', 'msft', 'msft', 'ibm'], 'qty': [100, 99, 101, 98]
... })
>>> pykx.q.aj0(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time sym qty
-----------------------------
0D10:01:00.000000000 msft 101
0D10:01:02.000000000 ibm 98
0D10:01:04.000000000 ge 150
'))
ajf¶
Performs an as-of join across temporal columns in tables with null values being filled. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.
The resulting time column is the value of the boundary used in the first table.
>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
... 'time': np.array([1, 1], dtype='timedelta64[s]'),
... 'sym': ['a', 'b'],
... 'p': pykx.LongVector([0, 1]),
... 'n': ['r', 's']
... })
>>> df2 = pd.DataFrame({
... 'time': np.array([1, 1], dtype='timedelta64[s]'),
... 'sym':['a', 'b'],
... 'p': pykx.q('1 0N')
... })
>>> pykx.q.ajf(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time sym p n
----------------------------
0D00:00:01.000000000 a 1 r
0D00:00:01.000000000 b 1 s
'))
ajf0¶
Performs an as-of join across temporal columns in tables with null values being filled. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.
The resulting time column is the actual time of the last value in the second table.
>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
... 'time': np.array([1, 1], dtype='timedelta64[s]'),
... 'sym':['a', 'b'],
... 'p': pykx.LongVector([0, 1]),
... 'n': ['r', 's']
... })
>>> df2 = pd.DataFrame({
... 'time': np.array([1, 1], dtype='timedelta64[s]'),
... 'sym': ['a', 'b'],
... 'p': pykx.q('1 0N')
... })
>>> pykx.q.ajf0(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time sym p n
----------------------------
0D00:00:01.000000000 a 1 r
0D00:00:01.000000000 b 1 s
'))
asof¶
Performs an as-of join across temporal columns in tables. The last column the second table must be temporal and correspond to a column in the first table argument. The return is the data from the first table is the last time that is less than or equal to the time in the second table per key. The time column will be removed from the output.
>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
... 'time': np.array([1, 2, 3, 4], dtype='timedelta64[s]'),
... 'sym': ['a', 'a', 'b', 'b'], 'p': pykx.LongVector([2, 4, 6, 8])})
>>> df2 = pd.DataFrame({'sym':['b'], 'time': np.array([3], dtype='timedelta64[s]')})
>>> pykx.q.asof(df1, df2)
pykx.Table(q('
p
-
6
'))
ej¶
Equi join. The result has one combined record for each row in the second table that matches the first table on the columns specified in the first function parameter.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['a', 'a', 'b', 'a', 'c', 'b', 'c', 'a'], 'p': pykx.LongVector([2, 4, 6, 8, 1, 3, 5, 7])})
>>> df2 = pd.DataFrame({'sym':['a', 'b'], 'w': ['alpha', 'beta']})
>>> pykx.q.ej('sym', df1, df2)
pykx.Table(q('
sym p w
-----------
a 2 alpha
a 4 alpha
b 6 beta
a 8 alpha
b 3 beta
a 7 alpha
'))
ij¶
Inner join. The result has one combined record for each row in the first table that matches the second table on the columns specified in the first function parameter.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> df2 = pykx.q.xkey('sym', df2)
>>> pykx.Table(df1)
pykx.Table(q('
sym p
------
IBM 7
FDP 8
FDP 6
FDP 5
IBM 2
MSFT 5
'))
>>> df2
pykx.KeyedTable(q('
sym | ex MC
----| --------
IBM | N 1000
MSFT| CME 250
'))
>>> pykx.q.ij(df1, df2)
pykx.Table(q('
sym p ex MC
---------------
IBM 7 N 1000
IBM 2 N 1000
MSFT 5 CME 250
'))
ijf¶
Inner join nulls filled. The result has one combined record for each row in the first table that matches the second table on the columns specified in the first function parameter.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> b = pykx.q.xkey('sym', df2)
>>> pykx.Table(df1)
pykx.Table(q('
sym p
------
IBM 7
FDP 8
FDP 6
FDP 5
IBM 2
MSFT 5
'))
>>> df2
pykx.KeyedTable(q('
sym | ex MC
----| --------
IBM | N 1000
MSFT| CME 250
'))
>>> pykx.q.ijf(df1, df2)
pykx.Table(q('
sym p ex MC
---------------
IBM 7 N 1000
IBM 2 N 1000
MSFT 5 CME 250
'))
lj¶
Left join. For each record in the first table, the result has one record with the columns of second table joined to columns of the first using the primary keys of the second table, if no value is present in the second table the record will contain null values in the place of the columns of the second table.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> b = pykx.q.xkey('sym', df2)
>>> pykx.Table(df2)
pykx.Table(q('
sym p
------
IBM 7
FDP 8
FDP 6
FDP 5
IBM 2
MSFT 5
'))
>>> df1
pykx.KeyedTable(q('
sym | ex MC
----| --------
IBM | N 1000
MSFT| CME 250
'))
>>> pykx.q.lj(df1, df2)
pykx.Table(q('
sym p ex MC
---------------
IBM 7 N 1000
FDP 8
FDP 6
FDP 5
IBM 2 N 1000
MSFT 5 CME 250
'))
ljf¶
Left join nulls filled. For each record in the first table, the result has one record with the columns of second table joined to columns of the first using the primary keys of the second table, if no value is present in the second table the record will contain null values in the place of the columns of the second table.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> b = pykx.q.xkey('sym', df2)
>>> pykx.Table(df1)
pykx.Table(q('
sym p
------
IBM 7
FDP 8
FDP 6
FDP 5
IBM 2
MSFT 5
'))
>>> df1
pykx.KeyedTable(q('
sym | ex MC
----| --------
IBM | N 1000
MSFT| CME 250
'))
>>> pykx.q.ljf(df1, df2)
pykx.Table(q('
sym p ex MC
---------------
IBM 7 N 1000
FDP 8
FDP 6
FDP 5
IBM 2 N 1000
MSFT 5 CME 250
'))
pj¶
Plus join. For each record in the first table, the result has one record with the columns of second table joined to columns of the first using the primary keys of the second table, if a value is present it is added to the columns of the first table, if no value is present the columns are left unchanged and new columns are set to 0.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'a': pykx.LongVector([1, 2, 3]), 'b':['x', 'y', 'z'], 'c': pykx.LongVector([10, 20, 30])})
>>> pykx.Table(df1)
pykx.Table(q('
a b c
------
1 x 10
2 y 20
3 z 30
'))
>>> df2 = pd.DataFrame({
... 'a': pykx.LongVector([1, 3]),
... 'b':['x', 'z'],
... 'c': pykx.LongVector([1, 2]),
... 'd': pykx.LongVector([10, 20])
... })
>>> df2 = pykx.q.xkey(pykx.SymbolVector(['a', 'b']), df2)
pykx.KeyedTable(q('
a b| c d
---| ----
1 x| 1 10
3 z| 2 20
'))
>>> pykx.q.pj(df1, df2)
pykx.Table(q('
a b c d
---------
1 x 11 10
2 y 20 0
3 z 32 20
'))
uj¶
Union join. Where the first table and the second table are both keyed or both unkeyed tables, returns the union of the columns, filled with nulls where necessary. If the tables have matching key columns then the records in the second table will be used to update the first table, if the tables are not keyed then the records from the second table will be joined onto the end of the first table.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> df1
sym p
0 IBM 7
1 FDP 8
2 FDP 6
3 FDP 5
4 IBM 2
5 MSFT 5
>>> df2
sym ex MC
0 IBM N 1000
1 MSFT CME 250
>>> pykx.q.uj(df1, df2)
pykx.Table(q('
sym p ex MC
---------------
IBM 7
FDP 8
FDP 6
FDP 5
IBM 2
MSFT 5
IBM N 1000
MSFT CME 250
'))
ujf¶
Union join nulls filled. Where the first table and the second table are both keyed or both unkeyed tables, returns the union of the columns, filled with nulls where necessary. If the tables have matching key columns then the records in the second table will be used to update the first table, if the tables are not keyed then the records from the second table will be joined onto the end of the first table.
>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> df1
sym p
0 IBM 7
1 FDP 8
2 FDP 6
3 FDP 5
4 IBM 2
5 MSFT 5
>>> df2
sym ex MC
0 IBM N 1000
1 MSFT CME 250
>>> pykx.q.ujf(df1, df2)
pykx.Table(q('
sym p ex MC
---------------
IBM 7
FDP 8
FDP 6
FDP 5
IBM 2
MSFT 5
IBM N 1000
MSFT CME 250
'))
wj¶
Window join. Returns for each record in the table, a record with additional columns c0 and c1, which contain the results of the aggregation functions applied to values over the matching intervals defined in the first parameter of the function.
>>> import pandas as pd
>>> import numpy as np
>>> pykx.q('t: ([]sym:3#`ibm;time:10:01:01 10:01:04 10:01:08;price:100 101 105)')
pykx.Table(pykx.q('
sym time price
------------------
ibm 10:01:01 100
ibm 10:01:04 101
ibm 10:01:08 105
'))
>>> df_t = pd.DataFrame({
'sym': ['ibm', 'ibm', 'ibm'],
'time': np.array([36061, 36064, 36068], dtype='timedelta64[s]'),
'price': pykx.LongVector([100, 101, 105])
})
sym time price
0 ibm 0 days 10:01:01 100
1 ibm 0 days 10:01:04 101
2 ibm 0 days 10:01:08 105
>>> pykx.q('q:([]sym:`ibm; time:10:01:01+til 9; ask: (101 103 103 104 104 107 108 107 108); bid: (98 99 102 103 103 104 106 106 107))')
pykx.Table(pykx.q('
sym time ask bid
--------------------
ibm 10:01:01 101 98
ibm 10:01:02 103 99
ibm 10:01:03 103 102
ibm 10:01:04 104 103
ibm 10:01:05 104 103
ibm 10:01:06 107 104
ibm 10:01:07 108 106
ibm 10:01:08 107 106
ibm 10:01:09 108 107
'))
>>> f = pykx.SymbolVector(['sym', 'time'])
>>> w = pykx.q('-2 1+\:t.time')
>>> pykx.q.wj(w, f, df_t, pykx.q('(q;(max;`ask);(min;`bid))'))
pykx.Table(pykx.q('
sym time price ask bid
--------------------------
ibm 10:01:01 100 103 98
ibm 10:01:04 101 104 99
ibm 10:01:08 105 108 104
'))
wj1¶
Window join. Returns for each record in the table, a record with additional columns c0 and c1, which contain the results of the aggregation functions applied to values over the matching intervals defined in the first parameter of the function.
>>> import pandas as pd
>>> import numpy as np
>>> pykx.q('t: ([]sym:3#`ibm;time:10:01:01 10:01:04 10:01:08;price:100 101 105)')
pykx.Table(pykx.q('
sym time price
------------------
ibm 10:01:01 100
ibm 10:01:04 101
ibm 10:01:08 105
'))
>>> df_t = pd.DataFrame({
... 'sym': ['ibm', 'ibm', 'ibm'],
... 'time': np.array([36061, 36064, 36068], dtype='timedelta64[s]'),
... 'price': pykx.LongVector([100, 101, 105])
... })
sym time price
0 ibm 0 days 10:01:01 100
1 ibm 0 days 10:01:04 101
2 ibm 0 days 10:01:08 105
>>> pykx.q('q:([]sym:`ibm; time:10:01:01+til 9; ask: (101 103 103 104 104 107 108 107 108); bid: (98 99 102 103 103 104 106 106 107))')
pykx.Table(pykx.q('
sym time ask bid
--------------------
ibm 10:01:01 101 98
ibm 10:01:02 103 99
ibm 10:01:03 103 102
ibm 10:01:04 104 103
ibm 10:01:05 104 103
ibm 10:01:06 107 104
ibm 10:01:07 108 106
ibm 10:01:08 107 106
ibm 10:01:09 108 107
'))
>>> f = pykx.SymbolVector(['sym', 'time'])
>>> w = pykx.q('-2 1+\:t.time')
>>> pykx.q.wj(w, f, df_t, pykx.q('(q;(max;`ask);(min;`bid))'))
pykx.Table(pykx.q('
sym time price ask bid
--------------------------
ibm 10:01:01 100 103 98
ibm 10:01:04 101 104 99
ibm 10:01:08 105 108 104
'))
List¶
count¶
Count the items of a list or dictionary.
>>> pykx.q.count([1, 2, 3])
pykx.LongAtom(q('3'))
cross¶
Returns all possible combinations of x and y.
>>> pykx.q.cross([1, 2, 3], [4, 5, 6])
pykx.List(q('
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
'))
cut¶
Cut a list or table into sub-arrays.
>>> pykx.q.cut(3, range(10))
pykx.List(q('
0 1 2
3 4 5
6 7 8
,9
'))
enlist¶
Returns a list with its arguments as items.
>>> pykx.q.enlist(1, 2, 3, 4)
pykx.LongVector(q('1 2 3 4'))
fills¶
Replace nulls with preceding non-nulls.
>>> a = pykx.q('0N 1 2 0N 0N 2 3 4 5 0N 4')
>>> pykx.q.fills(a)
pykx.LongVector(q('0N 1 2 2 2 2 3 4 5 5 4'))
first¶
First item of a list
>>> pykx.q.first([1, 2, 3, 4, 5])
pykx.LongAtom(q('1'))
flip¶
Returns x transposed, where x may be a list of lists, a dictionary or a table.
>>> pykx.q.flip([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
pykx.List(q('
1 6
2 7
3 8
4 9
5 10
'))
group¶
Returns a dictionary in which the keys are the distinct items of x, and the values the indexes where the distinct items occur.
The order of the keys is the order in which they appear in x.
>>> pykx.q.group(b'mississippi')
pykx.Dictionary(q('
m| ,0
i| 1 4 7 10
s| 2 3 5 6
p| 8 9
'))
inter¶
Intersection of two lists or dictionaries.
>>> pykx.q.inter([1, 2, 3], [2, 3, 4])
pykx.LongVector(q('2 3'))
last¶
Last item of a list
>>> pykx.q.last([1, 2, 3])
pykx.LongAtom(q('3'))
mcount¶
Returns the x-item moving counts of the non-null items of y. The first x items of the result are the counts so far, and thereafter the result is the moving count.
>>> pykx.q.mcount(3, pykx.q('1 2 3 4 5 0N 6 7 8'))
pykx.IntVector(q('1 2 3 3 3 2 2 2 3i'))
next¶
Next items in a list.
>>> pykx.q.next([1, 2, 3, 4])
pykx.LongVector(q('2 3 4 0N'))
prev¶
Immediately preceding items in a list.
>>> pykx.q.prev([1, 2, 3, 4])
pykx.LongVector(q('0N 1 2 3'))
raze¶
Return the items of x joined, collapsing one level of nesting.
>>> pykx.q.raze([[1, 2], [3, 4]])
pykx.LongVector(q('1 2 3 4'))
reverse¶
Reverse the order of items of a list or dictionary.
>>> pykx.q.reverse([1, 2, 3, 4, 5])
pykx.List(q('
5
4
3
2
1
'))
rotate¶
Shift the items of a list to the left or right.
>>> pykx.q.rotate(2, [1, 2, 3, 4, 5])
pykx.LongVector(q('3 4 5 1 2'))
sublist¶
Select a sublist of a list.
>>> pykx.q.sublist(2, [1, 2, 3, 4, 5])
pykx.LongVector(q('1 2'))
sv¶
"Scalar from vector"
- join strings, symbols, or filepath elements
- decode a vector to an atom
>>> pykx.q.sv(10, [1, 2, 3, 4])
pykx.LongAtom(q('1234'))
til¶
First x natural numbers.
>>> pykx.q.til(10)
pykx.LongVector(q('0 1 2 3 4 5 6 7 8 9'))
union¶
Union of two lists.
>>> pykx.q.union([1, 2, 3, 3, 5], [2, 4, 6, 8])
pykx.LongVector(q('1 2 3 5 4 6 8'))
vs¶
"Vector from scalar"
- partition a symbol, string, or bytestream
- encode a vector from an atom, or a matrix from a vector
>>> pykx.q.vs(b',', b'one,two,three')
pykx.List(q('
"one"
"two"
"three"
'))
where¶
Copies of indexes of a list or keys of a dictionary.
>>> pykx.q.where(pykx.BooleanVector([True, False, True, True, False]))
pykx.LongVector(q('0 2 3'))
>>> pykx.q.where(pykx.q('1 0 0 1 0 1 1'))
pykx.LongVector(q('0 3 5 6'))
xprev¶
Nearby items in a list.
>>> pykx.q.xprev(2, [1, 2, 3, 4, 5, 6])
pykx.LongVector(q('0N 0N 1 2 3 4'))
There is no xnext function, but xprev with a negative number as its first argument can achieve this.
>>> pykx.q.xprev(-2, [1, 2, 3, 4, 5, 6])
pykx.LongVector(q('3 4 5 6 0N 0N'))
Logic¶
all¶
Everything is true.
>>> pykx.q.all([True, True, True, True])
pykx.BooleanAtom(q('1b'))
>>> pykx.q.all([True, True, False, True])
pykx.BooleanAtom(q('0b'))
any¶
Something is true.
>>> pykx.q.any([False, False, True, False])
pykx.BooleanAtom(q('1b'))
>>> pykx.q.any([False, False])
pykx.BooleanAtom(q('0b'))
Math¶
abs¶
Where x is a numeric or temporal, returns the absolute value of x. Null is returned if x is null.
>>> pykx.q.abs(-5)
pykx.LongAtom(q('5'))
acos¶
The arccosine of x; that is, the value whose cosine is x. The result is in radians and lies between 0 and π.
>>> pykx.q.acos(0.5)
pykx.FloatAtom(q('1.047198'))
asin¶
The arcsine of x; that is, the value whose sine is x. The result is in radians and lies between -π / 2 and π / 2. (The range is approximate due to rounding errors). Null is returned if the argument is not between -1 and 1.
>>> pykx.q.asin(0.5)
pykx.FloatAtom(q('0.5235988'))
atan¶
The arctangent of x; that is, the value whose tangent is x. The result is in radians and lies between -π / 2 and π / 2.
>>> pykx.q.atan(0.5)
pykx.FloatAtom(q('0.4636476'))
avg¶
Arithmetic mean.
>>> pykx.q.avg([1, 2, 3, 4, 7])
pykx.FloatAtom(q('3.4'))
avgs¶
Running mean.
>>> pykx.q.avgs([1, 2, 3, 4, 7])
pykx.FloatVector(q('1 1.5 2 2.5 3.4'))
ceiling¶
Round up.
>>> pykx.q.ceiling([-2.7, -1.1, 0, 1.1, 2.7])
pykx.LongVector(q('-2 -1 0 2 3'))
cor¶
Correlation.
>>> pykx.q.cor(pykx.LongVector([29, 10, 54]), pykx.LongVector([1, 3, 9]))
pykx.FloatAtom(q('0.7727746'))
cos¶
The cosine of x, taken to be in radians. The result is between -1 and 1, or null if the argument is null or infinity.
>>> pykx.q.cos(0.2)
pykx.FloatAtom(q('0.9800666'))
cov¶
Where x and y are conforming numeric lists returns their covariance as a floating-point number. Applies to all numeric data types and signals an error with temporal types, char and sym.
>>> pykx.q.cov(pykx.LongVector([29, 10, 54]), pykx.LongVector([1, 3, 9]))
pykx.FloatAtom(q('47.33333'))
deltas¶
Where x is a numeric or temporal vector, returns differences between consecutive pairs of its items.
>>> pykx.q.deltas(pykx.LongVector([1, 4, 9, 16]))
pykx.LongVector(q('1 3 5 7'))
dev¶
Standard deviation.
>>> pykx.q.dev(pykx.LongVector([10, 343, 232, 55]))
pykx.FloatAtom(q('134.3484'))
div¶
Integer division.
>>> pykx.q.div(7, 3)
pykx.LongAtom(q('2'))
ema¶
The cosine of x, taken to be in radians. The result is between -1 and 1, or null if the argument is null or infinity.
>>> pykx.q.ema(0.5, [1, 2, 3, 4, 5])
pykx.FloatVector(q('1 1.5 2.25 3.125 4.0625'))
exp¶
Raise e to a power.
>>> pykx.q.exp(1)
pykx.FloatAtom(q('2.718282'))
floor¶
Round down.
>>> pykx.q.floor([-2.7, -1.1, 0, 1.1, 2.7])
pykx.LongVector(q('-3 -2 0 1 2'))
inv¶
Matrix inverse.
>>> a = pykx.q('3 3# 2 4 8 3 5 6 0 7 1f')
pykx.List(q('
2 4 8
3 5 6
0 7 1
'))
>>> pykx.q.inv(a)
pykx.List(q('
-0.4512195 0.6341463 -0.195122
-0.03658537 0.02439024 0.1463415
0.2560976 -0.1707317 -0.02439024
'))
log¶
Natural logarithm.
>>> pykx.q.log([1, 2, 3])
pykx.FloatVector(q('0 0.6931472 1.098612'))
lsq¶
Least squares, matrix divide.
>>> a = pykx.q('1f+3 4#til 12')
pykx.List(q('
1 2 3 4
5 6 7 8
9 10 11 12
'))
>>> b = pykx.q('4 4#2 7 -2 5 5 3 6 1 -2 5 2 7 5 0 3 4f')
pykx.List(q('
2 7 -2 5
5 3 6 1
-2 5 2 7
5 0 3 4
'))
>>> pykx.q.lsq(a, b)
pykx.List(q('
-0.1233333 0.16 0.4766667 0.28
0.07666667 0.6933333 0.6766667 0.5466667
0.2766667 1.226667 0.8766667 0.8133333
'))
mavg¶
Moving averages.
>>> pykx.q.mavg(3, [1, 2, 3, 5, 7, 10])
pykx.FloatVector(q('1 1.5 2 3.333333 5 7.333333'))
max¶
Maximum.
>>> pykx.q.max([0, 7, 2, 4 , 1, 3])
pykx.LongAtom(q('7'))
maxs¶
Maximums.
>>> pykx.q.maxs([1, 2, 5, 4, 7, 1, 2])
pykx.LongVector(q('1 2 5 5 7 7 7'))
mdev¶
Moving deviations.
>>> pykx.q.mdev(3, [1, 2, 5, 4, 7, 1, 2])
pykx.FloatVector(q('0 0.5 1.699673 1.247219 1.247219 2.44949 2.624669'))
med¶
Median.
>>> pykx.q.med([1, 2, 3, 4, 4, 1, 2, 4, 5])
pykx.FloatAtom(q('3f'))
min¶
Minimum.
>>> pykx.q.min([7, 5, 2, 4, 6, 5, 1, 4])
pykx.LongAtom(q('1'))
mins¶
Minimums.
>>> pykx.q.mins([7, 5, 2, 4, 6, 5, 1, 4])
pykx.LongVector(q('7 5 2 2 2 2 1 1'))
mmax¶
Moving maximums.
>>> pykx.q.mmax(4, [7, 5, 2, 4, 6, 5, 1, 4])
pykx.LongVector(q('7 7 7 7 6 6 6 6'))
mmin¶
Moving minimums.
>>> pykx.q.mmin(4, pykx.LongVector([7, 5, 2, 4, 6, 5, 1, 4]))
pykx.LongVector(q('7 5 2 2 2 2 1 1'))
mmu¶
Matrix multiply, dot product.
>>> a = pykx.q('2 4#2 4 8 3 5 6 0 7f')
>>> a
pykx.List(q('
2 4 8 3
5 6 0 7
'))
>>> b = pykx.q('4 3#"f"$til 12')
>>> b
pykx.List(q('
0 1 2
3 4 5
6 7 8
9 10 11
'))
>>> pykx.q.mmu(a, b)
pykx.List(q('
87 104 121
81 99 117
'))
mod¶
Modulus.
>>> pykx.q.mod([1, 2, 3, 4, 5, 6, 7], 4)
pykx.LongVector(q('1 2 3 0 1 2 3'))
msum¶
Moving sums.
>>> pykx.q.msum(3, [1, 2, 3, 4, 5, 6, 7])
pykx.LongVector(q('1 3 6 9 12 15 18'))
neg¶
Negate.
>>> pykx.q.neg([2, 0, -1, 3, -5])
pykx.LongVector(q('-2 0 1 -3 5'))
prd¶
Product.
>>> pykx.q.prd([1, 2, 3, 4, 5])
pykx.LongAtom(q('120'))
prds¶
Cumulative products.
>>> pykx.q.prds([1, 2, 3, 4, 5])
pykx.LongVector(q('1 2 6 24 120'))
rand¶
Pick randomly.
>>> pykx.q.rand([1, 2, 3, 4, 5])
pykx.LongAtom(q('2'))
ratios¶
Ratios between items.
>>> pykx.q.ratios([1, 2, 3, 4, 5])
pykx.FloatVector(q('0n 2 1.5 1.333333 1.25'))
reciprocal¶
Reciprocal of a number.
>>> pykx.q.reciprocal([1, 0, 3])
pykx.FloatVector(q('1 0w 0.3333333'))
scov¶
Sample covariance.
>>> pykx.q.scov(pykx.LongVector([2, 3, 5, 7]), pykx.LongVector([4, 3, 0, 2]))
pykx.FloatAtom(q('-2.416667'))
sdev¶
Sample standard deviation.
>>> pykx.q.sdev(pykx.LongVector([10, 343, 232, 55]))
pykx.FloatAtom(q('155.1322'))
signum¶
Where x (or its underlying value for temporals) is
- null or negative, returns
-1i - zero, returns
0i - positive, returns
1i
>>> pykx.q.signum([-2, 0, 1, 3])
pykx.IntVector(q('-1 0 1 1i'))
sin¶
Sine.
>>> pykx.q.sin(0.5)
pykx.FloatAtom(q('0.4794255'))
sqrt¶
Square root.
>>> pykx.q.sqrt([-1, 0, 25, 50])
pykx.FloatVector(q('0n 0 5 7.071068'))
sum¶
Total.
>>> pykx.q.sum(pykx.LongVector([2, 3, 5, 7]))
pykx.LongAtom(q('17'))
sums¶
Cumulative total.
>>> pykx.q.sums(pykx.LongVector([2, 3, 5, 7]))
pykx.LongVector(q('2 5 10 17'))
svar¶
Sample variance.
>>> pykx.q.svar(pykx.LongVector([2, 3, 5, 7]))
pykx.FloatAtom(q('4.916667'))
tan¶
Tangent.
>>> pykx.q.tan(0.5)
pykx.FloatAtom(q('0.5463025'))
var¶
Variance.
>>> pykx.q.var(pykx.LongVector([2, 3, 5, 7]))
pykx.FloatAtom(q('3.6875'))
wavg¶
Weighted average.
>>> pykx.q.wavg([2, 3, 4], [1, 2 ,4])
pykx.FloatAtom(q('2.666667'))
within¶
Check bounds.
>>> pykx.q.within([1, 3, 10, 6, 4], [2, 6])
pykx.BooleanVector(q('01011b'))
wsum¶
Weighted sum.
>>> pykx.q.wsum([2, 3, 4], [1, 2, 4]) # equivalent to 2 * 1 + 3 * 2 + 4 * 4
pykx.LongAtom(q('24'))
xexp¶
Raise x to a power.
>>> pykx.q.xexp(2, 8)
pykx.FloatAtom(q('256f'))
xlog¶
Logarithm base x.
>>> pykx.q.xlog(2, 8)
pykx.FloatAtom(q('3f'))
Meta¶
attr¶
Attributes of an object, returns a Symbol Atom or Vector.
The possible attributes are:
| code | attribute |
|---|---|
| s | sorted |
| u | unique (hash table) |
| p | partitioned (grouped) |
| g | true index (dynamic attribute): enables constant time update and access for real-time tables |
>>> pykx.q.attr([1,2,3])
pykx.SymbolAtom(q('`'))
>>> pykx.q.attr(pykx.q('asc 1 2 3'))
pykx.SymbolAtom(q('`s'))
null¶
Is null.
>>> pykx.q.null(1)
pykx.BooleanAtom(q('0b'))
>>> pykx.q.null(float('NaN'))
pykx.BooleanAtom(q('1b'))
>>> pykx.q.null(None)
pykx.BooleanAtom(q('1b'))
tables¶
List of tables in a namespace.
>>> pykx.q('exampleTable: ([] a: til 10; b: 10?10)')
pykx.Identity(pykx.q('::'))
>>> pykx.q('exampleTable: ([] a: til 10; b: 10?10)')
pykx.Table(q('
a b
---
0 8
1 1
2 9
3 5
4 4
5 6
6 6
7 1
8 8
9 5
'))
>>> pykx.q.tables('.')
pykx.SymbolVector(q(',`exampleTable'))
type¶
Underlying k type of an object.
>>> pykx.q.type(1)
pykx.ShortAtom(q('-7h'))
>>> pykx.q.type([1, 2, 3])
pykx.ShortAtom(q('0h'))
>>> pykx.q.type(pykx.LongVector([1, 2, 3]))
pykx.ShortAtom(q('7h'))
view¶
Expression defining a view.
>>> pykx.q('v::2+a*3')
>>> pykx.q('a:5')
>>> pykx.q('v')
pykx.LongAtom(q('17'))
>>> pykx.q.view('v')
pykx.CharVector(q('"2+a*3"'))
views¶
List views defined in the default namespace.
>>> pykx.q('v::2+a*3')
>>> pykx.q('a:5')
>>> pykx.q('v')
pykx.LongAtom(q('17'))
>>> pykx.q.views()
pykx.SymbolVector(q(',`v'))
Queries¶
fby¶
Apply an aggregate to groups.
>>> d = pykx.q('data: 10?10')
pykx.LongVector(pykx.q('4 9 2 7 0 1 9 2 1 8'))
>>> group = pykx.SymbolVector(['a', 'b', 'a', 'b', 'c', 'd', 'c', 'd', 'd', 'c'])
pykx.SymbolVector(pykx.q('`a`b`a`b`c`d`c`d`d`c'))
>>> >>> pykx.q.fby(pykx.q('(sum; data)'), group)
pykx.LongVector(pykx.q('6 16 6 16 17 4 17 4 4 17'))
Sort¶
asc¶
Ascending sort.
>>> pykx.q.asc([4, 2, 5, 1, 0])
pykx.LongVector(q('`s#0 1 2 4 5'))
bin¶
Binary search.
>>> pykx.q.bin([0, 2, 4, 6, 8, 10], 5)
pykx.LongAtom(q('2'))
>>> pykx.q.bin([0, 2, 4, 6, 8, 10], [-10, 0, 4, 5, 6, 20])
pykx.LongVector(q('-1 0 2 2 3 5'))
binr¶
Binary search right.
>>> pykx.q.binr([0, 2, 4, 6, 8, 10], 5)
pykx.LongAtom(q('3'))
>>> pykx.q.binr([0, 2, 4, 6, 8, 10], [-10, 0, 4, 5, 6, 20])
pykx.LongVector(q('0 0 2 3 3 6'))
desc¶
Descending sort.
>>> pykx.q.desc([4, 2, 5, 1, 0])
pykx.LongVector(q('5 4 2 1 0'))
differ¶
Find where list items change value.
>>> pykx.q.differ([1, 1, 2, 3, 4, 4])
pykx.BooleanVector(q('101110b'))
distinct¶
Unique items of a list.
>>> pykx.q.distinct([1, 3, 1, 4, 5, 1, 2, 3])
pykx.LongVector(q('1 3 4 5 2'))
iasc¶
Ascending grade.
>>> pykx.q.iasc([4, 2, 5, 1, 0])
pykx.LongVector(q('4 3 1 0 2'))
idesc¶
Descending grade.
>>> pykx.q.idesc([4, 2, 5, 1, 0])
pykx.LongVector(q('2 0 1 3 4'))
rank¶
Position in the sorted list.
Where x is a list or dictionary, returns for each item in x the index of where it would occur in the sorted list or dictionary.
>>> pykx.q.rank([4, 2, 5, 1, 0])
pykx.LongVector(q('3 2 4 1 0'))
>>> pykx.q.rank({'c': 3, 'a': 4, 'b': 1})
pykx.LongVector(q('2 0 1'))
xbar¶
Round y down to the nearest multiple of x.
>>> pykx.q.xbar(5, 3)
pykx.LongAtom(q('0'))
>>> pykx.q.xbar(5, 5)
pykx.LongAtom(q('5'))
>>> pykx.q.xbar(5, 7)
pykx.LongAtom(q('5'))
>>> pykx.q.xbar(3, range(16))
pykx.LongVector(q('0 0 0 3 3 3 6 6 6 9 9 9 12 12 12 15'))
xrank¶
Group by value.
>>> pykx.q.xrank(3, range(6))
pykx.LongVector(q('0 0 1 1 2 2'))
>>> pykx.q.xrank(4, range(9))
pykx.LongVector(q('0 0 0 1 1 2 2 3 3'))
Table¶
cols¶
Column names of a table.
>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({
... 'time': numpy.array([1, 2, 3, 4], dtype='timedelta64[s]'),
... 'sym':['a', 'a', 'b', 'b'],
... 'p': pykx.LongVector([2, 4, 6, 8])
... })
>>> pykx.q.cols(df)
pykx.SymbolVector(q('`time`sym`p'))
csv¶
CSV delimiter.
A synonym for "," for use in preparing text for CSV files, or reading them.
>>> pykx.q.csv
pykx.CharAtom(q('","'))
fkeys¶
Foreign-key columns of a table.
>>> pykx.q('f:([x:1 2 3]y:10 20 30)')
pykx.Identity(q('::'))
>>> pykx.q('t: ([]a:`f$2 2 2; b: 0; c: `f$1 1 1)')
pykx.Identity(q('::'))
>>> pykx.q.fkeys('t')
pykx.Dictionary(q('
a| f
c| f
'))
insert¶
Insert or append records to a table.
>>> pykx.q('t: ([] a: `a`b`c; b: til 3)')
>>> pykx.q('t')
pykx.Table(q('
a b
---
a 0
b 1
c 2
'))
>>> pykx.q.insert('t', ['d', 3])
>>> pykx.q('t')
pykx.Table(q('
a b
---
a 0
b 1
c 2
d 3
'))
key¶
Where x is a dictionary (or the name of one), returns its keys.
>>> pykx.q.key({'a': 1, 'b': 2})
pykx.SymbolVector(q('`a`b'))
keys¶
Get the names of the key columns of a table.
>>> pykx.q['v'] = pykx.KeyedTable(data={'x': [4, 5, 6]}, index=[1, 2, 3])
>>> pykx.q('v')
pykx.KeyedTable(pykx.q('
idx| x
---| -
1 | 4
2 | 5
3 | 6
'))
>>> pykx.q.keys('v')
pykx.SymbolVector(q(',`idx'))
meta¶
Metadata for a table.
| Column | Information |
|---|---|
| c | column name |
| t | data type |
| f | foreign key (enums) |
| a | attribute |
>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({
... 'time': np.array([1, 2, 3, 4], dtype='timedelta64[s]'),
... 'sym': ['a', 'a', 'b', 'b'],
... 'p': pykx.LongVector([2, 4, 6, 8])
... })
>>> pykx.q.meta(df)
pykx.KeyedTable(q('
c | t f a
----| -----
time| n
sym | s
p | j
'))
ungroup¶
Where x is a table, in which some cells are lists, but for any row, all lists are of the same length, returns the normalized table, with one row for each item of a lists.
>>> a = pykx.Table([['a', [2, 3], 10], ['b', [5, 6, 7], 20], ['c', [11], 30]], columns=['s', 'x', 'q'])
>>> a
pykx.Table(pykx.q('
s x q
------------
a (2;3) 10
b (5;6;7) 20
c ,11 30
'))
>>> pykx.q.ungroup(a)
pykx.Table(q('
s x q
-------
a 2 10
a 3 10
b 5 20
b 6 20
b 7 20
c 11 30
'))
upsert¶
Add new records to a table.
>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b'], 'p': pykx.LongVector([2, 4, 6, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
-----
a 2
a 4
b 6
b 8
'))
>>> pykx.q.upsert(df, ['c', 10])
>>> pykx.Table(q('
sym p
------
a 2
a 4
b 6
b 8
c 10
'))
xasc¶
Sort a table in ascending order of specified columns.
>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a 10
a 4
b 6
b 2
c 0
c 8
'))
>>> pykx.q.xasc('p', df)
pykx.Table(q('
sym p
------
c 0
b 2
a 4
b 6
c 8
a 10
'))
xcol¶
Rename table columns.
>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a 10
a 4
b 6
b 2
c 0
c 8
'))
>>> pykx.q.xcol(pykx.SymbolVector(['Sym', 'Qty']), df)
pykx.Table(q('
Sym Qty
-------
a 10
a 4
b 6
b 2
c 0
c 8
'))
>>> pykx.q.xcol({'p': 'Qty'}, df)
pykx.Table(q('
sym Qty
-------
a 10
a 4
b 6
b 2
c 0
c 8
'))
xcols¶
Reorder table columns.
>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({
... 'time': np.array([1, 2, 3, 4], dtype='timedelta64[s]'),
... 'sym':['a', 'a', 'b', 'b'],
... 'p': pykx.LongVector([2, 4, 6, 8])
... })
>>> pykx.Table(df)
pykx.Table(q('
time sym p
--------------------------
0D00:00:01.000000000 a 2
0D00:00:02.000000000 a 4
0D00:00:03.000000000 b 6
0D00:00:04.000000000 b 8
'))
>>> pykx.q.xcols(pykx.SymbolVector(['p', 'sym', 'time']), df)
pykx.Table(q('
p sym time
--------------------------
2 a 0D00:00:01.000000000
4 a 0D00:00:02.000000000
6 b 0D00:00:03.000000000
8 b 0D00:00:04.000000000
'))
xdesc¶
Sorts a table in descending order of specified columns. The sort is by the first column specified, then by the second column within the first, and so on.
>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a 10
a 4
b 6
b 2
c 0
c 8
'))
>>> pykx.q.xdesc('p', df)
pykx.Table(q('
sym p
------
a 10
c 8
b 6
a 4
b 2
c 0
'))
xgroup¶
Groups a table by values in selected columns.
>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a 10
a 4
b 6
b 2
c 0
c 8
'))
>>> pykx.q.xgroup('sym', df)
pykx.KeyedTable(q('
sym| p
---| ----
a | 10 4
b | 6 2
c | 0 8
'))
xkey¶
Set specified columns as primary keys of a table.
>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a 10
a 4
b 6
b 2
c 0
c 8
'))
>>> pykx.q.xkey('p', df)
pykx.KeyedTable(q('
p | sym
--| ---
10| a
4 | a
6 | b
2 | b
0 | c
8 | c
'))
Text¶
like¶
Whether text matches a pattern.
>>> pykx.q.like('quick', b'qu?ck')
pykx.BooleanAtom(q('1b'))
>>> pykx.q.like('brown', b'br[ao]wn')
pykx.BooleanAtom(q('1b'))
>>> pykx.q.like('quick', b'quickish')
pykx.BooleanAtom(q('0b'))
lower¶
Shift case to lower case.
>>> pykx.q.lower('HELLO')
pykx.SymbolAtom(q('`hello'))
>>> pykx.q.lower(b'HELLO')
pykx.CharVector(q('"hello"'))
ltrim¶
Remove leading nulls from a list.
>>> pykx.q.ltrim(b' pykx ')
pykx.CharVector(q('"pykx "'))
md5¶
Message digest hash.
>>> pykx.q.md5(b'pykx')
pykx.ByteVector(q('0xfba0532951f022133f8e8b14b6ddfced'))
rtrim¶
Remove trailing nulls from a list.
>>> pykx.q.rtrim(b' pykx ')
pykx.CharVector(q('" pykx"'))
ss¶
String search.
>>> pykx.q.ss(b'a cat and a dog', b'a')
pykx.LongVector(q('0 3 6 10'))
ssr¶
String search and replace.
>>> pykx.q.ssr(b'toronto ontario', b'ont', b'x')
pykx.CharVector(q('"torxo xario"'))
string¶
Cast to string.
>>> pykx.q.string(2)
pykx.CharVector(q(',"2"'))
>>> pykx.q.string([1, 2, 3, 4, 5])
pykx.List(q('
,"1"
,"2"
,"3"
,"4"
,"5"
'))
trim¶
Remove leading and trailing nulls from a list.
>>> pykx.q.trim(b' pykx ')
pykx.CharVector(q('"pykx"'))
upper¶
Shift case to upper case.
>>> pykx.q.upper('hello')
pykx.SymbolAtom(q('`HELLO'))
>>> pykx.q.upper(b'hello')
pykx.CharVector(q('"HELLO"'))
Operators¶
drop¶
Drop items from a list, entries from a dictionary or rows from a table.
Examples:
Drop the first 3 items from a list
>>> import pykx as kx
>>> kx.q.drop(3, kx.q('1 2 3 4 5 6'))
pykx.LongVector(pykx.q('4 5 6'))
Drop the last 10 rows from a table
>>> import pykx as kx
>>> tab = kx.Table(data={
... 'x': kx.q.til(100),
... 'y': kx.random.random(100, 10.0)
... })
>>> kx.q.drop(-10, tab)
pykx.Table(pykx.q('
x y
------------
0 3.927524
1 5.170911
2 5.159796
3 4.066642
4 1.780839
..
'))
>>> len(kx.q.drop(-10, tab))
90
coalesce¶
Merge two keyed tables ignoring null objects
Example:
Coalesce two keyed tables one containing nulls
>> tab1 = kx.Table(data={
... 'x': kx.q.til(10),
... 'y': kx.random.random(10, 10.0)
... }).set_index('x')
>>> tab2 = kx.Table(data={
... 'x': kx.q.til(10),
... 'y':kx.random.random(10, [1.0, kx.FloatAtom.null, 10.0])
... }).set_index('x')
>>> kx.q.coalesce(tab1, tab2)
pykx.KeyedTable(pykx.q('
x| y z
-| ------------
0| 9.006991 10
1| 8.505909
2| 8.196014 10
3| 0.9982673 1
4| 8.187707
..
'))
fill¶
Replace nulls in lists, dictionaries or tables
Examples:
Replace null values in a list
>>> null_list = kx.random.random(10, [10, kx.LongAtom.null, 100])
>>> kx.q.fill(0, null_list)
Replace all null values in a table
>>> table = kx.Table(data={
... 'x': kx.random.random(10, [10.0, kx.FloatAtom.null, 100.0]),
... 'y': kx.random.random(10, [10.0, kx.FloatAtom.null, 100.0])
... })
>>> kx.q.fill(10.0, table)
take¶
Select leading or trailing items from a list or dictionary, named entries from a dictionary, or named columns from a table
Examples:
Retrieve the last 3 items from a list
>>> lst = kx.q.til(100)
>>> kx.q.take(-3, lst)
pykx.LongVector(pykx.q('97 98 99'))
Retrieve named columns from a table using take
>>> table = kx.Table(data={
... 'x': kx.random.random(5, 10.0),
... 'y': kx.random.random(5, 10.0),
... 'z': kx.random.random(5, 10.0),
... })
>>> kx.q.take(['x', 'y'], table)
pykx.Table(pykx.q('
x y
-----------------
6.916099 9.672398
2.296615 2.306385
6.919531 9.49975
4.707883 4.39081
6.346716 5.759051
'))
set_attribute¶
Set an attribute for a supplied list or dictionary, the supplied attribute must be one of: 's', 'u', 'p' or 'g'.
>>> kx.q.set_attribute('s', kx.q.til(10))
pykx.LongVector(pykx.q('`s#0 1 2 3 4 5 6 7 8 9'))
>>> kx.q.set_attribute('g', [2, 1, 2, 1])
pykx.LongVector(pykx.q('`g#2 1 2 1'))
join¶
Join atoms, lists, dictionaries or tables
>>> kx.q.join([1, 2, 3], [4, 5, 6])
pykx.LongVector(pykx.q('1 2 3 4 5 6'))
Join multiple dictionaries together
>>> kx.q.join({'x': 1, 'y': 2}, {'z': 3})
pykx.Dictionary(pykx.q('
x| 1
y| 2
z| 3
'))
Join multiple columns row wise
>>> t = kx.q('([]a:1 2 3;b:`a`b`c)')
>>> s = kx.q('([]a:10 11;b:`d`e)')
>>> kx.q.join(t, s)
pykx.Table(pykx.q('
a b
----
1 a
2 b
3 c
10 d
11 e
'))
find¶
Find the first occurrence of an item(s) in a list
>>> lst = [10, -8, 3, 5, -1, 2, 3]
>>> kx.q.find(lst, -8)
pykx.LongAtom(pykx.q('1'))
>>> kx.q.find(lst, [10, 3])
pykx.LongVector(pykx.q('0 2'))
enum_extend¶
Extend a defined variable enumeration
>>> kx.q['foo'] = ['a', 'b']
>>> kx.q.enum_extend('foo', ['a', 'b', 'c', 'a', 'b'])
pykx.EnumVector(pykx.q('`foo$`a`b`c`a`b'))
>>> kx.q['foo']
pykx.SymbolVector(pykx.q('`a`b`c'))
Extend a filepath enumeration
>>> import os
>>> from pathlib import Path
>>> kx.q['bar'] = ['c', 'd'] # about to be overwritten
>>> kx.q.enum_extend(Path('bar'), ['a', 'b', 'c', 'b', 'b', 'a'])
pykx.EnumVector(pykx.q('`bar$`a`b`c`b`b`a'))
>>> os.system('ls -l bar')
-rw-r--r-- 1 username staff 14 20 Aug 09:34 bar
>>> kx.q['bar']
pykx.SymbolVector(pykx.q('`a`b`c'))
roll¶
Generate a random list of values with duplicates, for this the first parameter must be positive.
>>> kx.q.roll(3, 10.0)
pykx.FloatVector(pykx.q('3.927524 5.170911 5.159796'))
>>> kx.q.roll(4, [1, 'a', 10.0])
pykx.List(pykx.q('
`a
1
`a
10f
'))
deal¶
Generate a random list of values without duplicates, for this the first parameter must be negative.
>>> kx.q.deal(-5, 5)
pykx.LongVector(pykx.q('1 3 2 0 4'))
>>> kx.q.deal(-3, ['the', 'quick', 'brown', 'fox'])
pykx.SymbolVector(pykx.q('`the`brown`quick'))
dict¶
Generate a dictionary by passing two lists of equal lengths
>>> kx.q.dict(['a', 'b', 'c'], [1, 2, 3])
pykx.Dictionary(pykx.q('
a| 1
b| 2
c| 3
'))
enkey¶
Create a keyed table by passing an integer to a simple table. This is similar to set_index
>>> simple_tab = kx.Table(data = {
... 'x': [1, 2, 3],
... 'y': [4, 5, 6]
... })
>>> kx.q.dict(1, simple_tab)
pykx.KeyedTable(pykx.q('
x| y
-| -
1| 4
2| 5
3| 6
'))
unkey¶
Remove the keys from a keyed table returning a simple table, this is similar to reset_index
with no arguments
>>> keyed_tab = kx.Table(data = {
... 'x': [1, 2, 3],
... 'y': [4, 5, 6]
... }).set_index(1)
>>> kx.q.unkey(0, keyed_tab)
pykx.Table(pykx.q('
x y
---
1 4
2 5
3 6
'))
enumeration¶
Enumerate a symbol list - First argument is a variable in q memory denoting a symbol list - Second argument is a vector of integers in the domain 0-length(first argument)
>>> kx.q['x'] = ['a', 'b', 'c', 'd']
>>> kx.q.enumeration('x', [1, 2, 3])
pykx.EnumVector(pykx.q('`x$`b`c`d'))
enumerate¶
Enumerate a list of symbols based on the symbols in a global q variable
>>> kx.q['d'] = ['a', 'b', 'c']
>>> y = ['a', 'b', 'c', 'b', 'a', 'b', 'c']
>>> kx.q.enumerate('d', y)
pykx.EnumVector(pykx.q('`d$`a`b`c`b`a`b`c'))
pad¶
Pad a supplied KDB-X Python string (Python bytes) to the length supplied by the user. In the case that you are padding the front of a string use a negative value.
>>> kx.q.pad(-5, b'abc')
pykx.CharVector(pykx.q('" abc"'))
>>> kx.q.pad(10, [b'test', b'string', b'length'])
pykx.List(pykx.q('
"test "
"string "
"length "
'))
cast¶
Convert to another datatype, this should be a single lower case character byte, or name of the type. See https://code.kx.com/q/ref/cast/ for the accepted list.
>>> long_vec = kx.q('til 10')
>>> kx.q.cast('short', long_vec)
pykx.ShortVector(pykx.q('0 1 2 3 4 5 6 7 8 9h'))
>>> kx.q.cast(b'b', long_vec)
pykx.BooleanVector(pykx.q('0111111111b'))
tok¶
Interpret a KDB-X Python string as a data value(s), this should use a single upper case character byte or a non-positive KDB-X Python short value. See https://code.kx.com/q/ref/tok/ for more information on accepted lists for casting
>>> kx.q.tok(b'F', b'3.14')
pykx.FloatAtom(pykx.q('3.14'))
>>> float_int = kx.toq(-9, kx.ShortAtom)
>>> kx.toq(int(1), kx.ShortAtom)
compose¶
Compose a unary value function with another.
>>> f = kx.q('{2*x}')
>>> ff = kx.q('{[w;x;y;z]w+x+y+z}')
>>> d = kx.q.compose(f, ff)
>>> d(1, 2, 3, 4)
pykx.LongAtom(pykx.q('20'))