@@ -10175,6 +10175,101 @@ def register_polynomial_from_subframe(self, func_name, poly_spec,
1017510175 'coeff_select' : coeff_cols ,
1017610176 }
1017710177
10178+ def register_evaluator (self , name , evaluator , coord_columns ,
10179+ predictor_columns = None , overwrite = False ):
10180+ """
10181+ Register an evaluator (e.g., GroupByRegressionEvaluator) for use in alias expressions.
10182+
10183+ The evaluator becomes callable in alias expressions using the
10184+ coordinate column names as arguments. This is a thin wrapper around
10185+ register_function() that adapts the evaluator's dict-based interface
10186+ to the positional-array interface used by alias evaluation.
10187+
10188+ Registered function names are in a separate namespace from aliases
10189+ and DataFrame columns — no collision possible.
10190+
10191+ Parameters
10192+ ----------
10193+ name : str
10194+ Function name for alias expressions (e.g., 'corr_I1')
10195+ evaluator : object
10196+ Any object with .evaluate(positions: dict) -> np.ndarray or dict.
10197+ Typically GroupByRegressionEvaluator.
10198+ coord_columns : list of str
10199+ Column names that map to evaluator coordinate axes, in order.
10200+ These become the function arguments in alias expressions.
10201+ predictor_columns : list of str, optional
10202+ If evaluator returns dict of multiple predictors, select which
10203+ to return. If None and evaluator returns single predictor, uses it.
10204+ If None and evaluator returns multiple, raises ValueError.
10205+ overwrite : bool, default False
10206+ If True, allow replacing an existing registered function.
10207+
10208+ Raises
10209+ ------
10210+ TypeError
10211+ If evaluator has no .evaluate() method.
10212+ ValueError
10213+ If evaluator returns multiple predictors and predictor_columns not set.
10214+
10215+ Example
10216+ -------
10217+ >>> adf.register_evaluator('corr_I1', evaluator, ['xM', 'driftM', 'dsectorM'])
10218+ >>> adf.add_alias('dy_corr', 'corr_I1(xM, driftM, dsectorM)')
10219+ >>> adf.materialize_alias('dy_corr')
10220+
10221+ >>> # Composition with polynomial — via alias chaining:
10222+ >>> adf.add_alias('dy_total', 'polIter0(xM,driftM,dsectorM,tgSlp) + corr_I1(xM,driftM,dsectorM)')
10223+ """
10224+ col_names = list (coord_columns )
10225+
10226+ if not hasattr (evaluator , 'evaluate' ):
10227+ raise TypeError (
10228+ f"Evaluator must have .evaluate(positions) method, "
10229+ f"got { type (evaluator ).__name__ } "
10230+ )
10231+
10232+ # Capture in closure for alias evaluation
10233+ _evaluator = evaluator
10234+ _col_names = col_names
10235+ _name = name
10236+ _predictor_columns = predictor_columns
10237+
10238+ def _eval_func (* arrays ):
10239+ if len (arrays ) != len (_col_names ):
10240+ raise ValueError (
10241+ f"'{ _name } ' expects { len (_col_names )} arguments "
10242+ f"({ ', ' .join (_col_names )} ), got { len (arrays )} "
10243+ )
10244+ positions = {
10245+ col : np .asarray (arr , dtype = np .float64 )
10246+ for col , arr in zip (_col_names , arrays )
10247+ }
10248+ result = _evaluator .evaluate (positions )
10249+
10250+ if isinstance (result , dict ):
10251+ if _predictor_columns :
10252+ return result [_predictor_columns [0 ]]
10253+ elif len (result ) == 1 :
10254+ return next (iter (result .values ()))
10255+ else :
10256+ raise ValueError (
10257+ f"Evaluator '{ _name } ' returns multiple predictors "
10258+ f"{ list (result .keys ())} . Specify predictor_columns to select one."
10259+ )
10260+ return result
10261+
10262+ self .register_function (name , _eval_func , overwrite = overwrite )
10263+
10264+ # Store in schema (interface contract only — evaluator not serialized)
10265+ if not self ._schema .get ('registered_functions' ):
10266+ self ._schema ['registered_functions' ] = {}
10267+ self ._schema ['registered_functions' ][name ] = {
10268+ 'type' : 'evaluator' ,
10269+ 'coord_columns' : col_names ,
10270+ 'predictor_columns' : predictor_columns ,
10271+ }
10272+
1017810273 def draw_help (self , plot_type = None ):
1017910274 """
1018010275 Print dfdraw parameter documentation.
0 commit comments