summaryrefslogtreecommitdiff
path: root/lib/lineartree/_criterion.py
blob: 46472856e506478232eaca6a415e5f38820f16f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python3
# Copyright (c) 2021 Marco Cerliani, MIT License <https://github.com/cerlymarco/linear-tree>

import numpy as np


SCORING = {
    "linear": lambda y, yh: y - yh,
    "square": lambda y, yh: np.square(y - yh),
    "absolute": lambda y, yh: np.abs(y - yh),
    "exponential": lambda y, yh: 1 - np.exp(-np.abs(y - yh)),
    "poisson": lambda y, yh: yh.clip(1e-6) - y * np.log(yh.clip(1e-6)),
    "hamming": lambda y, yh, classes: (y != yh).astype(int),
    "entropy": lambda y, yh, classes: np.sum(
        list(
            map(
                lambda c: -(y == c[1]).astype(int) * np.log(yh[:, c[0]]),
                enumerate(classes),
            )
        ),
        axis=0,
    ),
}


def _normalize_score(scores, weights=None):
    """Normalize scores according to weights"""

    if weights is None:
        return scores.mean()
    else:
        return np.mean(np.dot(scores.T, weights) / weights.sum())


def mse(model, X, y, weights=None, **largs):
    """Mean Squared Error"""

    pred = model.predict(X)
    scores = SCORING["square"](y, pred)

    return _normalize_score(scores, weights)


def rmse(model, X, y, weights=None, **largs):
    """Root Mean Squared Error"""

    return np.sqrt(mse(model, X, y, weights, **largs))


def mae(model, X, y, weights=None, **largs):
    """Mean Absolute Error"""

    pred = model.predict(X)
    scores = SCORING["absolute"](y, pred)

    return _normalize_score(scores, weights)


def poisson(model, X, y, weights=None, **largs):
    """Poisson Loss"""

    if np.any(y < 0):
        raise ValueError(
            "Some value(s) of y are negative which is"
            " not allowed for Poisson regression."
        )

    pred = model.predict(X)
    scores = SCORING["poisson"](y, pred)

    return _normalize_score(scores, weights)


def hamming(model, X, y, weights=None, **largs):
    """Hamming Loss"""

    pred = model.predict(X)
    scores = SCORING["hamming"](y, pred, None)

    return _normalize_score(scores, weights)


def crossentropy(model, X, y, classes, weights=None, **largs):
    """Cross Entropy Loss"""

    pred = model.predict_proba(X).clip(1e-5, 1 - 1e-5)
    scores = SCORING["entropy"](y, pred, classes)

    return _normalize_score(scores, weights)