NOTICE

The upcoming release of Featuretools 1.0.0 contains several breaking changes. Users are encouraged to test this version prior to release by installing from GitHub:

pip install https://github.com/alteryx/featuretools/archive/woodwork-integration.zip

For details on migrating to the new version, refer to Transitioning to Featuretools Version 1.0. Please report any issues in the Featuretools GitHub repo or by messaging in Alteryx Open Source Slack.


Source code for featuretools.primitives.base.transform_primitive_base

import copy
import functools
import inspect

from featuretools.primitives.base.primitive_base import PrimitiveBase
from featuretools.primitives.base.utils import inspect_function_args


[docs]class TransformPrimitive(PrimitiveBase): """Feature for dataframe that is a based off one or more other features in that dataframe.""" # (bool) If True, feature function depends on all values of dataframe # (and will receive these values as input, regardless of specified instance ids) uses_full_dataframe = False def generate_name(self, base_feature_names): return u"%s(%s%s)" % ( self.name.upper(), u", ".join(base_feature_names), self.get_args_string(), ) def generate_names(self, base_feature_names): n = self.number_output_features base_name = self.generate_name(base_feature_names) return [base_name + "[%s]" % i for i in range(n)]
[docs]def make_trans_primitive(function, input_types, return_type, name=None, description=None, cls_attributes=None, uses_calc_time=False, commutative=False, number_output_features=1): '''Returns a new transform primitive class Args: function (function): Function that takes in a series and applies some transformation to it. input_types (list[ColumnSchema]): ColumnSchema of the inputs. return_type (ColumnSchema): ColumnSchema of returned feature. name (str): Name of the primitive. If no name is provided, the name of `function` will be used. description (str): Description of primitive. cls_attributes (dict[str -> anytype]): Custom attributes to be added to class. Key is attribute name, value is the attribute value. uses_calc_time (bool): If True, the cutoff time the feature is being calculated at will be passed to the function as the keyword argument 'time'. commutative (bool): If True, will only make one feature per unique set of base features. number_output_features (int): The number of output features (columns in the matrix) associated with this feature. Example: .. ipython :: python from featuretools.primitives import make_trans_primitive from woodwork.column_schema import ColumnSchema from woodwork.logical_types import Boolean def pd_is_in(array, list_of_outputs=None): if list_of_outputs is None: list_of_outputs = [] return pd.Series(array).isin(list_of_outputs) def isin_generate_name(self): return u"%s.isin(%s)" % (self.base_features[0].get_name(), str(self.kwargs['list_of_outputs'])) IsIn = make_trans_primitive( function=pd_is_in, input_types=[ColumnSchema()], return_type=ColumnSchema(logical_type=Boolean), name="is_in", description="For each value of the base feature, checks " "whether it is in a list that provided.", cls_attributes={"generate_name": isin_generate_name}) ''' if description is None: default_description = 'A custom transform primitive' doc = inspect.getdoc(function) description = doc if doc is not None else default_description # dictionary that holds attributes for class cls = {"__doc__": description} if cls_attributes is not None: cls.update(cls_attributes) # creates the new class and set name and types name = name or function.__name__ new_class = type(name, (TransformPrimitive,), cls) new_class.name = name new_class.input_types = input_types new_class.return_type = return_type new_class.commutative = commutative new_class.number_output_features = number_output_features new_class, default_kwargs = inspect_function_args(new_class, function, uses_calc_time) if len(default_kwargs) > 0: new_class.default_kwargs = default_kwargs def new_class_init(self, *args, **kwargs): self.kwargs = copy.deepcopy(self.default_kwargs) self.kwargs.update(kwargs) self.partial = functools.partial(function, **self.kwargs) self.partial.__name__ = name new_class.__init__ = new_class_init new_class.get_function = lambda self: self.partial else: # creates a lambda function that returns function every time new_class.get_function = lambda self, f=function: f return new_class