target_mapping = {'like': 1, 'view': 0.5, 'skip': -0.5, 'dislike': -1} reverse_mapping = {y: x for x, y in target_mapping.items()} label_weight = {'like': 0.5, 'view': 0.1, 'skip': -0.1, 'dislike': -10} if len(target_mapping) != len(reverse_mapping): raise ValueError("Invalid mapping") class CustomCbLoss: def calc_ders_range(self, approxes, targets, weights): assert len(approxes) == len(targets) if weights is not None: assert len(weights) == len(approxes) results = [] for t, p in zip(targets, approxes): results.append((label_weight[reverse_mapping[t]], 0)) return results def vc_metric(y_label, y_pred, weights=None): return sum(label_weight[reverse_mapping[l]] * p * (weights[i] if weights is not None else 1) for i, (l, p) in enumerate(zip(y_label, y_pred))) class VCCBMetric: def get_final_error(self, error, weight): return error / (weight + 1e-38) def is_max_optimal(self): return True def evaluate(self, approxes, targets, weights): return vc_metric(targets, approxes[0], weights), sum(weights) if weights is not None else len(approxes)