class_docstr: Double Ensemble Model
code: def fit(self, dataset: DatasetH):
      df_train, df_valid = dataset.prepare(
          ["train", "valid"],
          col_set=["feature", "label"],
          data_key=DataHandlerLP.DK_L,
      )
      if df_train.empty or df_valid.empty:
          raise ValueError(
              "Empty data from dataset, please check your dataset config."
          )
      x_train, y_train = df_train["feature"], df_train["label"]
      # initialize the sample weights
      N, F = x_train.shape
      weights = pd.Series(np.ones(N, dtype=float))
      # initialize the features
      features = x_train.columns
      pred_sub = pd.DataFrame(
          np.zeros((N, self.num_models), dtype=float),
          index=x_train.index,
      )
      # train sub-models
      for k in range(self.num_models):
          self.sub_features.append(features)
          self.logger.info(
              "Training sub-model: ({}/{})".format(
                  k + 1, self.num_models
              )
          )
          model_k = self.train_submodel(
              df_train, df_valid, weights, features
          )
          self.ensemble.append(model_k)
          # no further sample re-weight and feature selection needed for the last sub-model
          if k + 1 == self.num_models:
              break
  
          self.logger.info("Retrieving loss curve and loss values...")
          loss_curve = self.retrieve_loss_curve(
              model_k, df_train, features
          )
          pred_k = self.predict_sub(model_k, df_train, features)
          pred_sub.iloc[:, k] = pred_k
          pred_ensemble = (
              pred_sub.iloc[:, : k + 1] * self.sub_weights[0 : k + 1]
          ).sum(axis=1) / np.sum(self.sub_weights[0 : k + 1])
          loss_values = pd.Series(
              self.get_loss(
                  y_train.values.squeeze(), pred_ensemble.values
              )
          )
  
          if self.enable_sr:
              self.logger.info("Sample re-weighting...")
              weights = self.sample_reweight(
                  loss_curve, loss_values, k + 1
              )
  
          if self.enable_fs:
              self.logger.info("Feature selection...")
              features = self.feature_selection(df_train, loss_values)
  
imports: import lightgbm
  import numpy
  import pandas
  from typing import Text, Union
  from ...model.base import Model
  from ...data.dataset import DatasetH
  from ...data.dataset.handler import DataHandlerLP
  from ...model.interpret.base import FeatureInt
  from ...log import get_module_logger
label_desc: Use image node_id 2 for calling the DEnsembleModel obj's underlying member method code with example usage: obj.fit(dataset) without return types