def fit(self, Xi_train, Xv_train, y_train, Xi_valid=None, Xv_valid=None, y_valid=None, early_stopping=False, refit=False):
    '\n                :param Xi_train: [[ind1_1, ind1_2, ...], [ind2_1, ind2_2, ...], ..., [indi_1, indi_2, ..., indi_j, ...], ...]\n                                 indi_j is the feature index of feature field j of sample i in the training set\n                :param Xv_train: [[val1_1, val1_2, ...], [val2_1, val2_2, ...], ..., [vali_1, vali_2, ..., vali_j, ...], ...]\n                                 vali_j is the feature value of feature field j of sample i in the training set\n                                 vali_j can be either binary (1/0, for binary/categorical features) or float (e.g., 10.24, for numerical features)\n                :param y_train: label of each sample in the training set\n                :param Xi_valid: list of list of feature indices of each sample in the validation set\n                :param Xv_valid: list of list of feature values of each sample in the validation set\n                :param y_valid: label of each sample in the validation set\n                :param early_stopping: perform early stopping or not\n                :param refit: refit the model on the train+valid dataset or not\n                :return: None\n                '
    has_valid = (Xv_valid is not None)
    Xi_train = Xi_train.copy()
    Xv_train = Xv_train.copy()
    y_train = y_train.copy()
    for epoch in range(self.epoch):
        t1 = time()
        self.shuffle_in_unison_scary(Xi_train, Xv_train, y_train)
        total_batch = int((len(y_train) / self.batch_size))
        for i in range(total_batch):
            (Xi_batch, Xv_batch, y_batch) = self.get_batch(Xi_train, Xv_train, y_train, self.batch_size, i)
            (trian_out, train_loss) = self.fit_on_batch(Xi_batch, Xv_batch, y_batch)
            if ((i % 1000) == 0):
                print(('epoch:%d batch:%d train_loss=%.4f' % (epoch, i, train_loss)), file=sys.stderr)
        train_me = self.evaluate(Xi_train, Xv_train, y_train)
        self.train_result.append(train_me)
        if has_valid:
            valid_me = self.evaluate(Xi_valid, Xv_valid, y_valid)
            self.valid_result.append(valid_me)
        if ((self.verbose > 0) and ((epoch % self.verbose) == 0)):
            print(('[%d] [train] auc=%.4f acc=%.4f mse=%.4f precision_1=%.4f recall_1=%.4f [%.1f s]' % ((epoch + 1), train_me['auc'], train_me['acc'], train_me['mse'], train_me['precision_1'], train_me['recall_1'], (time() - t1))))
            if has_valid:
                print(('[%d] [valid] auc=%.4f acc=%.4f mse=%.4f precision_1=%.4f recall_1=%.4f [%.1f s]' % ((epoch + 1), valid_me['auc'], valid_me['acc'], valid_me['mse'], valid_me['precision_1'], valid_me['recall_1'], (time() - t1))))
        if (has_valid and early_stopping and self.training_termination(self.valid_result)):
            break
    if (has_valid and refit):
        if self.greater_is_better:
            best_valid_score = max(self.valid_result)
        else:
            best_valid_score = min(self.valid_result)
        best_epoch = self.valid_result.index(best_valid_score)
        best_train_score = self.train_result[best_epoch]
        Xi_train = (Xi_train + Xi_valid)
        Xv_train = (Xv_train + Xv_valid)
        y_train = (y_train + y_valid)
        for epoch in range(100):
            self.shuffle_in_unison_scary(Xi_train, Xv_train, y_train)
            total_batch = int((len(y_train) / self.batch_size))
            for i in range(total_batch):
                (Xi_batch, Xv_batch, y_batch) = self.get_batch(Xi_train, Xv_train, y_train, self.batch_size, i)
                self.fit_on_batch(Xi_batch, Xv_batch, y_batch)
            train_result = self.evaluate(Xi_train, Xv_train, y_train)
            if ((abs((train_result - best_train_score)) < 0.001) or (self.greater_is_better and (train_result > best_train_score)) or ((not self.greater_is_better) and (train_result < best_train_score))):
                break
:param Xi_train: [[ind1_1, ind1_2, ...], [ind2_1, ind2_2, ...], ..., [indi_1, indi_2, ..., indi_j, ...], ...]
                 indi_j is the feature index of feature field j of sample i in the training set
:param Xv_train: [[val1_1, val1_2, ...], [val2_1, val2_2, ...], ..., [vali_1, vali_2, ..., vali_j, ...], ...]
                 vali_j is the feature value of feature field j of sample i in the training set
                 vali_j can be either binary (1/0, for binary/categorical features) or float (e.g., 10.24, for numerical features)
:param y_train: label of each sample in the training set
:param Xi_valid: list of list of feature indices of each sample in the validation set
:param Xv_valid: list of list of feature values of each sample in the validation set
:param y_valid: label of each sample in the validation set
:param early_stopping: perform early stopping or not
:param refit: refit the model on the train+valid dataset or not
:return: None
def fit(self, Xi_train, Xv_train, y_train, Xi_valid=None, Xv_valid=None, y_valid=None, early_stopping=False, refit=False):
    '\n                :param Xi_train: [[ind1_1, ind1_2, ...], [ind2_1, ind2_2, ...], ..., [indi_1, indi_2, ..., indi_j, ...], ...]\n                                 indi_j is the feature index of feature field j of sample i in the training set\n                :param Xv_train: [[val1_1, val1_2, ...], [val2_1, val2_2, ...], ..., [vali_1, vali_2, ..., vali_j, ...], ...]\n                                 vali_j is the feature value of feature field j of sample i in the training set\n                                 vali_j can be either binary (1/0, for binary/categorical features) or float (e.g., 10.24, for numerical features)\n                :param y_train: label of each sample in the training set\n                :param Xi_valid: list of list of feature indices of each sample in the validation set\n                :param Xv_valid: list of list of feature values of each sample in the validation set\n                :param y_valid: label of each sample in the validation set\n                :param early_stopping: perform early stopping or not\n                :param refit: refit the model on the train+valid dataset or not\n                :return: None\n                '
    has_valid = (Xv_valid is not None)
    Xi_train = Xi_train.copy()
    Xv_train = Xv_train.copy()
    y_train = y_train.copy()
    for epoch in range(self.epoch):
        t1 = time()
        self.shuffle_in_unison_scary(Xi_train, Xv_train, y_train)
        total_batch = int((len(y_train) / self.batch_size))
        for i in range(total_batch):
            (Xi_batch, Xv_batch, y_batch) = self.get_batch(Xi_train, Xv_train, y_train, self.batch_size, i)
            (trian_out, train_loss) = self.fit_on_batch(Xi_batch, Xv_batch, y_batch)
            if ((i % 1000) == 0):
                print(('epoch:%d batch:%d train_loss=%.4f' % (epoch, i, train_loss)), file=sys.stderr)
        train_me = self.evaluate(Xi_train, Xv_train, y_train)
        self.train_result.append(train_me)
        if has_valid:
            valid_me = self.evaluate(Xi_valid, Xv_valid, y_valid)
            self.valid_result.append(valid_me)
        if ((self.verbose > 0) and ((epoch % self.verbose) == 0)):
            print(('[%d] [train] auc=%.4f acc=%.4f mse=%.4f precision_1=%.4f recall_1=%.4f [%.1f s]' % ((epoch + 1), train_me['auc'], train_me['acc'], train_me['mse'], train_me['precision_1'], train_me['recall_1'], (time() - t1))))
            if has_valid:
                print(('[%d] [valid] auc=%.4f acc=%.4f mse=%.4f precision_1=%.4f recall_1=%.4f [%.1f s]' % ((epoch + 1), valid_me['auc'], valid_me['acc'], valid_me['mse'], valid_me['precision_1'], valid_me['recall_1'], (time() - t1))))
        if (has_valid and early_stopping and self.training_termination(self.valid_result)):
            break
    if (has_valid and refit):
        if self.greater_is_better:
            best_valid_score = max(self.valid_result)
        else:
            best_valid_score = min(self.valid_result)
        best_epoch = self.valid_result.index(best_valid_score)
        best_train_score = self.train_result[best_epoch]
        Xi_train = (Xi_train + Xi_valid)
        Xv_train = (Xv_train + Xv_valid)
        y_train = (y_train + y_valid)
        for epoch in range(100):
            self.shuffle_in_unison_scary(Xi_train, Xv_train, y_train)
            total_batch = int((len(y_train) / self.batch_size))
            for i in range(total_batch):
                (Xi_batch, Xv_batch, y_batch) = self.get_batch(Xi_train, Xv_train, y_train, self.batch_size, i)
                self.fit_on_batch(Xi_batch, Xv_batch, y_batch)
            train_result = self.evaluate(Xi_train, Xv_train, y_train)
            if ((abs((train_result - best_train_score)) < 0.001) or (self.greater_is_better and (train_result > best_train_score)) or ((not self.greater_is_better) and (train_result < best_train_score))):
                break