code: def _tile_multinomial(cls, op: "DataFrameSample", in_df, weights):
      out_data = op.outputs[0]
      input_dfs = [in_df]
      size = op.size
  
      weight_chunks = itertools.repeat(None)
      if isinstance(op.weights, ENTITY_TYPE):
          input_dfs.append(weights)
          weight_chunks = weights.chunks
  
      chunks = []
      new_nsplits = list(in_df.nsplits)
      rs = op.random_state
      seeds = gen_random_seeds(len(in_df.chunks), op.random_state)
      if weights is None:
          # weights is None, use nsplits to sample num of instances for each chunk
          probs = np.array(in_df.nsplits[op.axis])
          probs = 1.0 * probs / probs.sum()
          chunk_sizes = rs.multinomial(size, probs)
          new_nsplits[op.axis] = tuple(
              int(s) for s in chunk_sizes if s > 0
          )
  
          chunk_idx = 0
          for data_chunk, chunk_size, seed in zip(
              in_df.chunks, chunk_sizes, seeds
          ):
              if chunk_size == 0:
                  continue
  
              chunk_op = op.copy().reset_key()
              chunk_op._random_state = None
              chunk_op._seed = seed
              chunk_op._size = int(chunk_size)
  
              params = data_chunk.params
              params["index_value"] = parse_index(
                  params["index_value"].to_pandas()[:0]
              )
              new_shape = list(data_chunk.shape)
              new_shape[op.axis] = int(chunk_size)
              params["shape"] = tuple(new_shape)
  
              idx_list = [0] * data_chunk.ndim
              idx_list[op.axis] = chunk_idx
              params["index"] = tuple(idx_list)
  
              chunks.append(chunk_op.new_chunk([data_chunk], **params))
              chunk_idx += 1
      else:
          mn_seed = gen_random_seeds(1, op.random_state)[0]
  
          # weights is specified, use weights to sample num of instances for each chunk
          chunk_weights = yield from recursive_tile(
              weights.to_tensor().map_chunk(
                  lambda x: x.sum(keepdims=True)
              )
          )
          chunk_weights_chunk = TensorConcatenate(
              dtype=chunk_weights.dtype
          ).new_chunk(
              chunk_weights.chunks,
              shape=(len(chunk_weights.chunks),),
              index=(0,),
          )
          chunk_samples = TensorMapChunk(
              func=lambda x: np.random.RandomState(mn_seed).multinomial(
                  size, x / x.sum()
              )
          ).new_chunk(
              [chunk_weights_chunk],
              shape=(len(chunk_weights.chunks),),
              index=(0,),
          )
          new_nsplits[op.axis] = (np.nan,) * len(chunk_weights.chunks)
          for chunk_idx, (data_chunk, weight_chunk, seed) in enumerate(
              zip(in_df.chunks, weight_chunks, seeds)
          ):
              input_chunks = [data_chunk]
  
              chunk_op = op.copy().reset_key()
              chunk_op._size = None
              chunk_op._random_state = None
              chunk_op._seed = seed
              chunk_op._chunk_samples = chunk_samples
              if weight_chunk is not None:
                  chunk_op._weights = weight_chunk
                  input_chunks.append(weight_chunk)
  
              params = data_chunk.params
              params["index_value"] = parse_index(
                  params["index_value"].to_pandas()[:0]
              )
              new_shape = list(data_chunk.shape)
              new_shape[op.axis] = np.nan
              params["shape"] = tuple(new_shape)
  
              idx_list = [0] * data_chunk.ndim
              idx_list[op.axis] = chunk_idx
              params["index"] = tuple(idx_list)
  
              chunks.append(
                  chunk_op.new_chunk(
                      input_chunks + [chunk_samples], **params
                  )
              )
  
      params = out_data.params
      new_shape = list(in_df.shape)
      new_shape[op.axis] = size
      params["shape"] = tuple(new_shape)
  
      df_op = op.copy().reset_key()
      return df_op.new_tileables(
          input_dfs, chunks=chunks, nsplits=tuple(new_nsplits), **params
      )
  
imports: import copy
  import itertools
  import numpy
  from ...None import opcodes
  from ...core import ENTITY_TYPE, get_output_types, recursive_tile
  from ...serialization.serializables import BoolField, AnyField, Int8Field, Int64Field, Float64Field, KeyField
  from ...tensor import searchsorted
  from ...tensor.base import TensorMapChunk
  from ...tensor.merge import TensorConcatenate
  from ...tensor.random import RandomState, RandomStateField
  from ...tensor.utils import normalize_chunk_sizes, gen_random_seeds
  from ...utils import has_unknown_shape, ceildiv
  from ..operands import DataFrameOperandMixin, DataFrameOperand
  from ..utils import validate_axis, parse_index
label_desc: Use image node_id 14 for calling the DataFrameSample obj's underlying member method code with example usage: obj._tile_multinomial(cls, op, in_df, weights) and returns: df_op