code: def groupby(
      df,
      by=None,
      level=None,
      as_index=True,
      sort=True,
      group_keys=_default_group_keys,
  ):
      if not as_index and df.op.output_types[0] == OutputType.series:
          raise TypeError("as_index=False only valid with DataFrame")
  
      output_types = (
          [OutputType.dataframe_groupby]
          if df.ndim == 2
          else [OutputType.series_groupby]
      )
      if isinstance(by, (SERIES_TYPE, pd.Series)):
          if isinstance(by, pd.Series):
              by = asseries(by)
          by = [by]
      elif df.ndim > 1 and by is not None and not isinstance(by, list):
          by = [by]
      op = DataFrameGroupByOperand(
          by=by,
          level=level,
          as_index=as_index,
          sort=sort,
          group_keys=group_keys
          if group_keys is not no_default
          else None,
          output_types=output_types,
      )
      return op(df)
  
imports: import itertools
  from functools import partial
  import numpy
  import pandas
  from ...None import opcodes
  from ...core import ENTITY_TYPE, Entity, OutputType
  from ...core.operand import OperandStage, MapReduceOperand
  from ...lib.groupby_wrapper import wrapped_groupby
  from ...serialization.serializables import BoolField, Int32Field, AnyField
  from ...utils import lazy_import, pd_release_version, no_default
  from ..align import align_dataframe_series, align_series_series
  from ..initializer import Series
  from ..core import SERIES_TYPE, SERIES_CHUNK_TYPE
  from ..utils import build_concatenated_rows_frame, hash_dataframe_on, build_df, build_series, parse_index, is_cudf
  from ..operands import DataFrameOperandMixin, DataFrameShuffleProxy
label_desc: Use image node_id 1 for calling a global function with example usage: groupby(df, by, level, as_index, sort, group_keys) and returns: op