Source code for ctapipe.core.feature_generator

"""
Generate Features.
"""
from collections import ChainMap

from .component import Component
from .expression_engine import ExpressionEngine
from .traits import List, Tuple, Unicode

__all__ = [
    "FeatureGenerator",
    "FeatureGeneratorException",
]


def _shallow_copy_table(table):
    """
    Make a shallow copy of the table.

    Data of the existing columns will be shared between shallow
    copies, but adding / removing columns won't be seen in
    the original table.
    """
    # automatically return Table or QTable depending on input
    return table.__class__({col: table[col] for col in table.colnames}, copy=False)


class FeatureGeneratorException(TypeError):
    """Signal a problem with a user-defined selection criteria function"""


[docs]class FeatureGenerator(Component): """ Generate features for astropy.table.Table. Raises Exceptions in two cases: 1. If a feature already exists in the table 2. If a feature cannot be built with the given expression """ features = List( Tuple(Unicode(), Unicode()), help=( "List of 2-Tuples of Strings: ('new_feature_name', 'expression to generate feature'). " "You can use ``numpy`` as ``np`` and ``astropy.units`` as ``u``. " "Several math functions are usable without the ``np``-prefix. " "Use ``feature.quantity.to_value(unit)`` to create features without units." ), ).tag(config=True) def __init__(self, config=None, parent=None, **kwargs): super().__init__(config=config, parent=parent, **kwargs) self.engine = ExpressionEngine(expressions=self.features) self._feature_names = [name for name, _ in self.features]
[docs] def __call__(self, table, **kwargs): """ Apply feature generation to the input table. This method returns a shallow copy of the input table with the new features added. Existing columns will share the underlying data, however the new columns won't be visible in the input table. """ table = _shallow_copy_table(table) lookup = ChainMap(table, kwargs) for result, name in zip(self.engine(lookup), self._feature_names): if name in table.colnames: raise FeatureGeneratorException(f"{name} is already a column of table.") try: table[name] = result except Exception as err: raise err return table
def __len__(self): return len(self.features)