SaQC Operators
So this is a suggestive MR/Issue for the upcoming SaQC
-future discussion.
Figured with __getitem__
, __setitem__
inplace, there are a lot of low hanging fruits available, that simplify saqc
operations. Namely, to add boolean and arithmetic operators to replace generic-lambda
and andGroup-orGroup
combos with easily readable/communicable operator counterparts.
So !857 adds the common boolean and arithmetic operators to saqc. This is far from optimally implemented and just meant to serve as basis for discussion/try-out.
The MR currently comprises:
-
logical operators:
-
&
->qc['foo'] & qc['bar']
: returnsSaQC
object with fieldfoo
and flagsmin(qc['foo'].flags, qc['bar'].flags)
-
|
->qc['foo'] & qc['bar']
: returnsSaQC
object with fieldfoo
and flagsmax(qc['foo'].flags, qc['bar'].flags)
-
~
-> shortcut for squeeze
-
-
arithmetic operators:
-
+
->qc['foo'] + qc['bar']
: returnsSaQC
object with fieldfoo
, dataqc['foo'].data + qc['bar'].data
and flagsmin(qc['foo'].flags, qc['bar'].flags)
-
-
->qc['foo'] - qc['bar']
: returnsSaQC
object with fieldfoo
, dataqc['foo'].data - qc['bar'].data
and flagsmin(qc['foo'].flags, qc['bar'].flags)
-
*
->qc['foo'] + qc['bar']
: returnsSaQC
object with fieldfoo
, dataqc['foo'].data * qc['bar'].data
and flagsmin(qc['foo'].flags, qc['bar'].flags)
-
+ f
,- f
,* f
,** f
-> for example:qc['foo'] + 7
: returnsSaQC
object with fieldfoo
, dataqc['foo'].data + 7
and flagsqc['foo'].flags
-
-
history (append) operators
-
<<
->qc['foo'] << qc['bar']
: returnsSaQC
object with field'foo'
data from'foo'
and history resulting from'bar'
history appended to'foo'
-
^
->qc['foo'] ^ qc['bar']
: returnsSaQC
object with field'foo'
data from'bar'
and history resulting from'bar'
history appended to'foo'
-
-
magical inplacy counterparts:
-
<<=
->qc['foo'] <<= qc['bar']
: shorthand/inplace forqc['foo'] = qc['foo'] << qc['bar']
-
&=
->qc['foo'] &= qc['bar']
: shorthand/inplace forqc['foo'] = qc['foo'] << (qc['foo'] & qc['bar']
) -
+=
->qc['foo'] += qc['bar']
: shorthand/inplace forqc['foo'] = qc['foo'] ^ (qc['foo'] + qc['bar']
) - ...
-
-
All operators also work for multifield
SaQC
objects - but necessitate that all the objects have the same number of fields and will than just loop over those fields pair wise and return the operator result for any two fields in a newSaQC
object. (The fields are just matched by order, not by name). -
The arithmetic operators already support operating with
pd.DataFrame
andnp.ndarray
objects. (but necessitate them to have equaling size: so no broadcasting, except for scalars.)
The implementation is made so, that consecutive operator calls wont blow up the history. So the calls:
qc['data0'] &= (qc['data1'] & qc.flagBar('data2')['data2']) | qc2['voltage']
qc['data1'] += 7*qc['data0']
Will only add one new history column to field 'data0'
(and 'data1'
).
Also, the inplace operators (<<=
, &=
, ...) actually work in conjunction with the implemented __setitem__
and __getitem__
operators. So above code actually results in qc
holding the results from the operations.
Some sandbox code:
import saqc
import pandas as pd
from saqc.lib.tools import periodicMask
mask_func = lambda x: ~periodicMask(x.index, '6:00:00', '18:00:00', True)
dat0 = pd.Series(range(100), name='data0', index=pd.date_range('2000', freq='4h', periods=100))
dat1 = pd.Series(0, name='data1', index=pd.date_range('2000', freq='4h', periods=100))
dat2 = pd.Series(range(-50,50), name='data2', index=pd.date_range('2000', freq='4h', periods=100))
scheme = saqc.DmpScheme()
qc = saqc.SaQC([dat0,dat1,dat2], scheme=scheme)
qc['data0'] += 1000.0
qc['data0'] <<= qc['data0'] & (qc['data2'].flagGeneric('data2', func=mask_func)
This for example results in the meta:
qc._history['data0'].meta
{'func': '(data0 + 1000.0)',
'args': (),
'kwargs': {'operand_0': {'dfilter': -inf, 'field': 'data0'},
'operand_1': {'value': '1000.0',
'type': "<class 'float'>",
'squeezed': True}}},
{'func': '(|(data0 + 1000.0)| & |data2|)',
'args': (),
'kwargs': {'operand_0': {'dfilter': -inf,
'field': 'data0',
'squeezed': True},
'operand_1': {'value': '1000.0',
'type': "<class 'float'>",
'squeezed': True},
'operand_2': {'squeezed': True}}}]