code: def execute(cls, ctx, op):
      restore_func(ctx, op)
      in_data = ctx[op.inputs[0].key]
      out = op.outputs[0]
      if not in_data:
          if op.output_types[0] == OutputType.dataframe:
              ctx[op.outputs[0].key] = build_empty_df(
                  op.outputs[0].dtypes
              )
          elif op.output_types[0] == OutputType.series:
              ctx[op.outputs[0].key] = build_empty_series(
                  op.outputs[0].dtype, name=out.name
              )
          else:
              raise ValueError(
                  "Chunk can not be empty except for dataframe/series, "
                  "please specify output types"
              )
          return
  
      applied = in_data.apply(op.func, *op.args, **op.kwds)
  
      if isinstance(applied, pd.DataFrame):
          # when there is only one group, pandas tend to return a DataFrame, while
          # we need to convert it into a compatible series
          if op.output_types[0] == OutputType.series:
              assert len(applied.index) == 1
              applied_idx = pd.MultiIndex.from_arrays(
                  [
                      [applied.index[0]] * len(applied.columns),
                      applied.columns.tolist(),
                  ]
              )
              applied_idx.names = [applied.index.name, None]
              applied = pd.Series(
                  np.array(applied.iloc[0]),
                  applied_idx,
                  name=applied.columns.name,
              )
          else:
              applied.columns.name = None
      ctx[out.key] = applied
  
imports: import numpy
  import pandas
  from ...None import opcodes
  from ...core import OutputType
  from ...core.context import get_context
  from ...core.custom_log import redirect_custom_log
  from ...serialization.serializables import AnyField, BoolField, TupleField, DictField, FunctionField, StringField
  from ...core.operand import OperatorLogicKeyGeneratorMixin
  from ...utils import enter_current_session, quiet_stdio, get_func_token, tokenize
  from ..operands import DataFrameOperandMixin, DataFrameOperand
  from ..utils import auto_merge_chunks, build_empty_df, build_empty_series, parse_index, validate_output_types, make_dtypes, make_dtype, clean_up_func, restore_func
label_desc: Use image node_id 3 for calling the GroupByApply obj's underlying member method code with example usage: obj.execute(cls, ctx, op) without return types