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, ...], ..., [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, ...], ..., [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)\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)
    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)
            self.fit_on_batch(xi_batch, xv_batch, y_batch)
        train_result = self.evaluate(xi_train, xv_train, y_train)
        self.train_result.append(train_result[0])
        if has_valid:
            valid_result = self.evaluate(xi_valid, xv_valid, y_valid)
            self.valid_result.append(valid_result[0])
        if ((self.verbose > 0) and ((epoch % self.verbose) == 0)):
            if has_valid:
                print(('[%d] train-loss=%.4f, valid-loss=%.4f [%.1f s]' % ((epoch + 1), train_result[0], valid_result[0], (time() - t1))))
            else:
                print(('[%d] train-loss=%.4f [%.1f s]' % ((epoch + 1), train_result[0], (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)
            ckp1 = (abs((train_result - best_train_score)) < 0.001)
            ckp2 = (self.greater_is_better and (train_result > best_train_score))
            ckp3 = ((not self.greater_is_better) and (train_result < best_train_score))
            if (ckp1 or ckp2 or ckp3):
                break
:param xi_train: [[ind1_1, ind1_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, ...], ..., [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)
: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, ...], ..., [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, ...], ..., [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)\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)
    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)
            self.fit_on_batch(xi_batch, xv_batch, y_batch)
        train_result = self.evaluate(xi_train, xv_train, y_train)
        self.train_result.append(train_result[0])
        if has_valid:
            valid_result = self.evaluate(xi_valid, xv_valid, y_valid)
            self.valid_result.append(valid_result[0])
        if ((self.verbose > 0) and ((epoch % self.verbose) == 0)):
            if has_valid:
                print(('[%d] train-loss=%.4f, valid-loss=%.4f [%.1f s]' % ((epoch + 1), train_result[0], valid_result[0], (time() - t1))))
            else:
                print(('[%d] train-loss=%.4f [%.1f s]' % ((epoch + 1), train_result[0], (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)
            ckp1 = (abs((train_result - best_train_score)) < 0.001)
            ckp2 = (self.greater_is_better and (train_result > best_train_score))
            ckp3 = ((not self.greater_is_better) and (train_result < best_train_score))
            if (ckp1 or ckp2 or ckp3):
                break