code: def _get_marginalized_statistics(
      self, feature_vector: numpy.ndarray
  ) -> Tuple[float, float]:
      assert feature_vector.size == self._n_features
  
      marginalized_features = numpy.isnan(feature_vector)
      active_features = ~marginalized_features
  
      # Reduce search space cardinalities to 1 for non-active features.
      search_spaces = self._search_spaces.copy()
      search_spaces[marginalized_features] = [0.0, 1.0]
  
      # Start from the root and traverse towards the leafs.
      active_nodes = [0]
      active_search_spaces = [search_spaces]
  
      node_indices = []
      active_leaf_search_spaces = []
  
      while len(active_nodes) > 0:
          node_index = active_nodes.pop()
          search_spaces = active_search_spaces.pop()
  
          feature = self._get_node_split_feature(node_index)
          if (
              feature >= 0
          ):  # Not leaf. Avoid unnecessary call to `_is_node_leaf`.
              # If node splits on an active feature, push the child node that we end up in.
              response = feature_vector[feature]
              if not numpy.isnan(response):
                  if response <= self._get_node_split_threshold(
                      node_index
                  ):
                      next_node_index = self._get_node_left_child(
                          node_index
                      )
                      next_subspace = (
                          self._get_node_left_child_subspaces(
                              node_index, search_spaces
                          )
                      )
                  else:
                      next_node_index = self._get_node_right_child(
                          node_index
                      )
                      next_subspace = (
                          self._get_node_right_child_subspaces(
                              node_index, search_spaces
                          )
                      )
  
                  active_nodes.append(next_node_index)
                  active_search_spaces.append(next_subspace)
                  continue
  
              # If subtree starting from node splits on an active feature, push both child nodes.
              # Here, we use `any` for list because `ndarray.any` is slow.
              if any(
                  self._subtree_active_features[node_index][
                      active_features
                  ].tolist()
              ):
                  for child_node_index in self._get_node_children(
                      node_index
                  ):
                      active_nodes.append(child_node_index)
                      active_search_spaces.append(search_spaces)
                  continue
  
          # If node is a leaf or the subtree does not split on any of the active features.
          node_indices.append(node_index)
          active_leaf_search_spaces.append(search_spaces)
  
      statistics = self._statistics[node_indices]
      values = statistics[:, 0]
      weights = statistics[:, 1]
      active_features_cardinalities = _get_cardinality_batched(
          active_leaf_search_spaces
      )
      weights = weights / active_features_cardinalities
  
      value = numpy.average(values, weights=weights)
      weight = weights.sum()
  
      return value, weight
  
imports: from __future__ import annotations
  from functools import lru_cache
  import itertools
  from typing import List
  from typing import Set
  from typing import Tuple
  from typing import TYPE_CHECKING
  from typing import Union
  import numpy
label_desc: Use image node_id 4 for calling the _FanovaTree obj's underlying member method code with example usage: obj._get_marginalized_statistics(feature_vector) and returns: value,  weight