@@ -2065,33 +2065,19 @@ def apply(
20652065 " are supported."
20662066 )
20672067
2068-
20692068 # Highest priority: try to map directly to an operator, for eg numpy
20702069 # ufuncs, or simple arithmetic/logic operators.
20712070 bf_op = python_ops .python_callable_to_op (func )
20722071 if bf_op and isinstance (bf_op , ops .UnaryOp ):
20732072 return self ._apply_unary_op (bf_op )
20742073
2075- # "compat": try by row, and then fall back to passing whole series if that fails
2076- if by_row :
2077- try :
2078- return self ._apply_by_row (func )
2079- except Exception as ex :
2080- raise ValueError (
2081- "You have passed a function as-is. If your intention is to "
2082- "apply this function in a vectorized way (i.e. to the "
2083- "entire Series as a whole, and you are sure that it "
2084- "performs only the operations that are implemented for a "
2085- "Series (e.g. a chain of arithmetic/logical operations, "
2086- "such as `def foo(s): return s % 2 == 1`), please also "
2087- "specify `by_row=False`. If your function contains "
2088- "arbitrary code, it can only be applied to every element "
2089- "in the Series individually, in which case you must "
2090- "convert it to a BigFrames BigQuery function using "
2091- "`bigframes.pandas.udf`, "
2092- "or `bigframes.pandas.remote_function` before passing."
2093- )
2074+ if by_row :
2075+ from bigframes ._config import options
20942076
2077+ enable_transpile = options .experiments .enable_python_transpiler
2078+ return self ._apply_by_row (
2079+ func , args = args , transpile_enabled = enable_transpile
2080+ )
20952081 try :
20962082 return func (self ) # type: ignore
20972083 except Exception as ex :
@@ -2102,20 +2088,44 @@ def apply(
21022088 ex .message += f"\n { _bigquery_function_recommendation_message } "
21032089 raise
21042090
2105- def _apply_by_row (self , func : typing .Callable , args : typing .Tuple = ()) -> Series :
2106- from bigframes ._config import options
2091+ def _apply_by_row (
2092+ self ,
2093+ func : typing .Callable ,
2094+ args : typing .Tuple = (),
2095+ transpile_enabled : bool = False ,
2096+ ) -> Series :
2097+ """
2098+ Apply callable or deployed udf row-wise on the series.
2099+ """
2100+ if not callable (func ):
2101+ raise ValueError (
2102+ "Expected a callable function. If you meant to use a BigQuery function, please wrap it with bigframes.pandas.udf(...)"
2103+ )
2104+ try :
2105+ expr = ops .func_to_expr (func )
2106+ # We get this message even if transpiler could have in theory translated it.
2107+ except Exception :
2108+ raise ValueError (
2109+ "You have passed a functi1on as-is. If your intention is to "
2110+ "apply this function in a vectorized way (i.e. to the "
2111+ "entire Series as a whole, and you are sure that it "
2112+ "performs only the operations that are implemented for a "
2113+ "Series (e.g. a chain of arithmetic/logical operations, "
2114+ "such as `def foo(s): return s % 2 == 1`), please also "
2115+ "specify `by_row=False`. If your function contains "
2116+ "arbitrary code, it can only be applied to every element "
2117+ "in the Series individually, in which case you must "
2118+ "convert it to a BigFrames BigQuery function using "
2119+ "`bigframes.pandas.udf`, "
2120+ "or `bigframes.pandas.remote_function` before passing."
2121+ )
21072122
2108- if isinstance (func , bigframes .functions .Udf ) or (
2109- options .experiments .enable_python_transpiler and callable (func )
2110- ):
2111- # We are working with bigquery function at this point
2112- result_series = self ._apply_callable_expr (ops .func_to_expr (func ), args )
2113- # TODO(jialuo): Investigate why `_apply_nary_op` drops the series
2114- # `name`. Manually reassigning it here as a temporary fix.
2115- result_series .name = self .name
2123+ result_series = self ._apply_callable_expr (expr , args )
2124+ # TODO(jialuo): Investigate why `_apply_nary_op` drops the series
2125+ # `name`. Manually reassigning it here as a temporary fix.
2126+ result_series .name = self .name
21162127
2117- return result_series
2118- raise ValueError (f"Cannot apply function { func } to Series { self } " )
2128+ return result_series
21192129
21202130 def combine (
21212131 self ,
@@ -2504,7 +2514,10 @@ def map(
25042514 map_df = map_df .set_index ("keys" )
25052515 elif callable (arg ):
25062516 # This is for remote function and managed funtion.
2507- return self .apply (arg )
2517+ from bigframes ._config import options
2518+
2519+ enable_transpile = options .experiments .enable_python_transpiler
2520+ return self ._apply_by_row (arg , transpile_enabled = enable_transpile )
25082521 else :
25092522 # Mirroring pandas, call the uncallable object
25102523 arg () # throws TypeError: object is not callable
0 commit comments