code: def infer_categorical_features(
      df: pd.DataFrame,
      max_categorical_ratio: float = 0.01,
      max_categories: int = None,
      columns: t.Optional[t.List[Hashable]] = None,
  ) -> t.List[Hashable]:
      """Infers which features are categorical by checking types and number of unique values.
  
      Parameters
      ----------
      df : pd.DataFrame
          dataframe for which to infer categorical features
      max_categorical_ratio : float , default: 0.01
      max_categories : int , default: None
      columns : t.Optional[t.List[Hashable]] , default: None
  
      Returns
      -------
      List[Hashable]
          list of categorical features
      """
      categorical_dtypes = df.select_dtypes(include="category")
  
      if len(categorical_dtypes.columns) > 0:
          return list(categorical_dtypes.columns)
  
      if columns is not None:
          dataframe_columns = ensure_hashable_or_mutable_sequence(
              columns
          )
      else:
          dataframe_columns = df.columns
  
      if max_categories is None:
          return [
              column
              for column in dataframe_columns
              if is_categorical(
                  t.cast(pd.Series, df[column]), max_categorical_ratio
              )
          ]
      else:
          return [
              column
              for column in dataframe_columns
              if is_categorical(
                  t.cast(pd.Series, df[column]),
                  max_categorical_ratio,
                  max_categories,
                  max_categories,
                  max_categories,
              )
          ]
  
file_path: deepchecks/deepchecks/utils/type_inference.py
imports: import typing
  import numpy
  import pandas
  from pandas.core.dtypes.common import is_datetime64_any_dtype, is_float_dtype, is_numeric_dtype
  from typing_extensions import Literal
  from deepchecks.utils.logger import get_logger
  from deepchecks.utils.typing import Hashable
  from deepchecks.utils.validation import ensure_hashable_or_mutable_sequence
label_desc: Use image node_id 2 for calling a global function with example usage: infer_categorical_features(df, max_categorical_ratio, max_categories, columns) and returns: list, unknown, unknown