code: def generate_statistics_from_dataframe(
      dataframe: DataFrame,
      stats_options: options.StatsOptions = options.StatsOptions(),
      n_jobs: int = 1,
  ) -> statistics_pb2.DatasetFeatureStatisticsList:
      """Compute data statistics for the input pandas DataFrame.
  
      This is a utility function for users with in-memory data represented
      as a pandas DataFrame.
  
      This function supports only DataFrames with columns of primitive string or
      numeric types. DataFrames with multivalent features or holding non-string
      object types are not supported.
  
      Args:
        dataframe: Input pandas DataFrame.
        stats_options: `tfdv.StatsOptions` for generating data statistics.
        n_jobs: Number of processes to run (defaults to 1). If -1 is provided,
          uses the same number of processes as the number of CPU cores.
  
      Returns:
        A DatasetFeatureStatisticsList proto.
      """
      if not isinstance(dataframe, DataFrame):
          raise TypeError(
              "dataframe argument is of type {}. Must be a "
              "pandas DataFrame.".format(type(dataframe).__name__)
          )
  
      stats_generators = cast(
          List[stats_generator.CombinerStatsGenerator],
          stats_impl.get_generators(stats_options, in_memory=True),
      )
      if n_jobs < -1 or n_jobs == 0:
          raise ValueError(
              "Invalid n_jobs parameter {}. Should be either "
              " -1 or >= 1.".format(n_jobs)
          )
  
      if n_jobs == -1:
          n_jobs = multiprocessing.cpu_count()
      n_jobs = max(min(n_jobs, multiprocessing.cpu_count()), 1)
  
      if n_jobs == 1:
          merged_partial_stats = _generate_partial_statistics_from_df(
              dataframe, stats_options, stats_generators
          )
      else:
          # TODO(b/144580609): Consider using Beam for inmemory mode as well.
          splits = np.array_split(dataframe, n_jobs)
          partial_stats = Parallel(n_jobs=n_jobs)(
              delayed(_generate_partial_statistics_from_df)(
                  splits[i], stats_options, stats_generators
              )
              for i in range(n_jobs)
          )
          merged_partial_stats = [
              gen.merge_accumulators(stats)
              for gen, stats in zip(
                  stats_generators, zip(*partial_stats)
              )
          ]
      return stats_impl.extract_statistics_output(
          merged_partial_stats, stats_generators
      )
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import copy
  import csv
  import gzip
  import io
  import multiprocessing
  import os
  import tempfile
  from typing import Any, List, Optional, Text, cast
  import apache_beam
  from apache_beam.io.filesystem import CompressionTypes
  from apache_beam.options.pipeline_options import PipelineOptions
  from joblib import delayed
  from joblib import Parallel
  import numpy
  from pandas import DataFrame
  import pyarrow
  import tensorflow
  from tensorflow_data_validation import constants
  from tensorflow_data_validation import types
  from tensorflow_data_validation.api import stats_api
  from tensorflow_data_validation.coders import csv_decoder
  from tensorflow_data_validation.statistics import stats_impl
  from tensorflow_data_validation.statistics import stats_options
  from tensorflow_data_validation.statistics.generators import stats_generator
  from tensorflow_data_validation.utils import stats_util
  from tfx_bsl.arrow import table_util
  from tfx_bsl.tfxio import tf_example_record
  from tensorflow_metadata.proto.v0 import schema_pb2
  from tensorflow_metadata.proto.v0 import statistics_pb2
label_desc: Use image node_id 3 for calling a global function with example usage: generate_statistics_from_dataframe(dataframe, stats_options, n_jobs) and returns: stats_impl