class_docstr: Doubly Robust (DR) estimator:
      reference: https://arxiv.org/abs/1103.4601 (deterministic reward model)
                 https://arxiv.org/abs/1612.01205 (distributed reward model)
code: def _evaluate(
      self,
      input: BanditsEstimatorInput,
      train_samples: Sequence[LogSample],
      eval_samples: Sequence[LogSample],
      force_train: bool = False,
      **kwargs,
  ) -> Optional[EstimatorResult]:
      logger.info("OPE DR Evaluating")
      self._train_model(train_samples, force_train)
      log_avg = RunningAverage()
      tgt_avg = RunningAverage()
      tgt_vals = []
      gt_avg = RunningAverage()
      for sample in eval_samples:
          log_avg.add(sample.log_reward)
          dm_action_reward, dm_scores, dm_probs = self._calc_dm_reward(
              input.action_space, sample
          )
          dm_reward = torch.dot(
              dm_scores.reshape(-1), dm_probs.reshape(-1)
          ).item()
          tgt_result = 0.0
          weight = 0.0
          if sample.log_action.value is not None:
              weight = (
                  0.0
                  if sample.log_action_probabilities[sample.log_action]
                  < PROPENSITY_THRESHOLD
                  else sample.tgt_action_probabilities[
                      sample.log_action
                  ]
                  / sample.log_action_probabilities[sample.log_action]
              )
              weight = self._weight_clamper(weight)
              assert dm_action_reward is not None
              assert dm_reward is not None
              tgt_result += (
                  sample.log_reward - dm_action_reward
              ) * weight + dm_reward
          else:
              tgt_result = dm_reward
          tgt_avg.add(tgt_result)
          tgt_vals.append(tgt_result)
          gt_avg.add(sample.ground_truth_reward)
      (
          tgt_score_normalized,
          tgt_std_err,
          tgt_std_err_normalized,
      ) = self._compute_metric_data(
          torch.tensor(tgt_vals), log_avg.average
      )
      return EstimatorResult(
          log_reward=log_avg.average,
          estimated_reward=tgt_avg.average,
          ground_truth_reward=gt_avg.average,
          estimated_weight=tgt_avg.count,
          estimated_reward_normalized=tgt_score_normalized,
          estimated_reward_std_error=tgt_std_err,
          estimated_reward_normalized_std_error=tgt_std_err_normalized,
      )
  
imports: import logging
  import time
  from abc import ABC, abstractmethod
  from dataclasses import dataclass
  from typing import Optional, Sequence, Tuple, Union
  import numpy
  import torch
  from reagent.ope.estimators.estimator import Estimator, EstimatorResult
  from reagent.ope.estimators.types import Action, ActionDistribution, ActionSpace, Reward, Trainer, TrainingData, Values
  from reagent.ope.utils import Clamper, RunningAverage
  from torch import Tensor
label_desc: Use image node_id 2 for calling the DoublyRobustEstimator obj's underlying member method code with example usage: obj._evaluate(input, train_samples, eval_samples, force_train) and returns: EstimatorResult