q functions and operators
This page documents the PyKX implementations of a selection of keywords and operators available in q.
The functions listed here are accessible in PyKX 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 PyKX.
These functions take and return q objects, which are wrapped in PyKX as pykx.K
objects. Any arguments of other types are converted appropriately. Refer to the PyKX 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
,update
anddelete
are 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
not
andor
The unavailable functions can still be used in PyKX 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 PyKX 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 values or global state.
>>> 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 PyKX 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 PyKX string as a data value(s), this should use a single upper case character byte or a non-positive PyKX 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.qkx.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'))