code: def _construct_lgb_datasets(
      self,
      training_set: "Dataset",  # noqa: F821
      validation_set: Optional["Dataset"] = None,  # noqa: F821
      test_set: Optional["Dataset"] = None,  # noqa: F821
  ) -> Tuple[lgb.Dataset, List[lgb.Dataset], List[str]]:
      X_train = training_set.to_scalar_df(
          self.model.input_features.values()
      )
      y_train = training_set.to_scalar_df(
          self.model.output_features.values()
      )
  
      # create dataset for lightgbm
      # keep raw data for continued training https://github.com/microsoft/LightGBM/issues/4965#issuecomment-1019344293
      try:
          lgb_train = lgb.Dataset(
              X_train, label=y_train, free_raw_data=False
          ).construct()
      except lgb.basic.LightGBMError as e:
          if re.search(r"special JSON characters", str(e)):
              raise ValueError(
                  "Some column names in the training set contain invalid characters. Please ensure column names only "
                  "contain alphanumeric characters and underscores, then try training again."
              ) from e
          else:
              raise
  
      eval_sets = [lgb_train]
      eval_names = [LightGBMTrainer.TRAIN_KEY]
      if validation_set is not None:
          X_val = validation_set.to_scalar_df(
              self.model.input_features.values()
          )
          y_val = validation_set.to_scalar_df(
              self.model.output_features.values()
          )
          try:
              lgb_val = lgb.Dataset(
                  X_val,
                  label=y_val,
                  reference=lgb_train,
                  free_raw_data=False,
              ).construct()
          except lgb.basic.LightGBMError as e:
              if re.search(r"special JSON characters", str(e)):
                  raise ValueError(
                      "Some column names in the validation set contain invalid characters. Please ensure column "
                      "names only contain alphanumeric characters and underscores, then try training again."
                  ) from e
              else:
                  raise
          eval_sets.append(lgb_val)
          eval_names.append(LightGBMTrainer.VALID_KEY)
      else:
          # TODO(joppe): take X% from train set as validation set
          pass
  
      if test_set is not None:
          X_test = test_set.to_scalar_df(
              self.model.input_features.values()
          )
          y_test = test_set.to_scalar_df(
              self.model.output_features.values()
          )
          try:
              lgb_test = lgb.Dataset(
                  X_test,
                  label=y_test,
                  reference=lgb_train,
                  free_raw_data=False,
              ).construct()
          except lgb.basic.LightGBMError as e:
              if re.search(r"special JSON characters", str(e)):
                  raise ValueError(
                      "Some column names in the test set contain invalid characters. Please ensure column "
                      "names only contain alphanumeric characters and underscores, then try training again."
                  )
              else:
                  raise
          eval_sets.append(lgb_test)
          eval_names.append(LightGBMTrainer.TEST_KEY)
  
      return lgb_train, eval_sets, eval_names
  
imports: import logging
  import os
  import re
  import signal
  import sys
  import threading
  import time
  from typing import Any, Dict, List, Optional, Tuple, Union
  import lightgbm
  import torch
  from torch.utils.tensorboard import SummaryWriter
  from ludwig.constants import BINARY, CATEGORY, MINIMIZE, MODEL_GBM, NUMBER, TEST, TRAINING, VALIDATION
  from ludwig.distributed import init_dist_strategy
  from ludwig.distributed.base import DistributedStrategy, LocalStrategy
  from ludwig.features.feature_utils import LudwigFeatureDict
  from ludwig.globals import is_progressbar_disabled, TRAINING_CHECKPOINTS_DIR_PATH, TRAINING_PROGRESS_TRACKER_FILE_NAME
  from ludwig.models.gbm import GBM
  from ludwig.models.predictor import Predictor
  from ludwig.modules.metric_modules import get_improved_fn, get_initial_validation_value
  from ludwig.modules.metric_registry import get_metric_objective
  from ludwig.progress_bar import LudwigProgressBar
  from ludwig.schema.trainer import BaseTrainerConfig, GBMTrainerConfig
  from ludwig.trainers.base import BaseTrainer
  from ludwig.trainers.registry import register_ray_trainer, register_trainer
  from ludwig.types import ModelConfigDict
  from ludwig.utils import time_utils
  from ludwig.utils.checkpoint_utils import CheckpointManager
  from ludwig.utils.defaults import default_random_seed
  from ludwig.utils.gbm_utils import get_single_output_feature, get_targets, log_loss_objective, logits_to_predictions, multiclass_objective, store_predictions, store_predictions_ray, TrainLogits
  from ludwig.utils.metric_utils import get_metric_names, TrainerMetric
  from ludwig.utils.metrics_printed_table import print_metrics_table
  from ludwig.utils.misc_utils import set_random_seed
  from ludwig.utils.trainer_utils import append_metrics, get_latest_metrics_dict, get_new_progress_tracker, ProgressTracker
label_desc: Use image node_id 16 for calling the LightGBMTrainer obj's underlying member method code with example usage: obj._construct_lgb_datasets(training_set, validation_set, test_set) and returns: lgb_train,  eval_sets,  eval_names