File size: 2,471 Bytes
8fe5582
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import numpy as np


def softmax(x: np.ndarray, axis=1) -> np.ndarray:
    """
    Computes softmax array along the specified axis.
    """
    e_x = np.exp(x)
    return e_x / e_x.sum(axis=axis, keepdims=True)


def calibrate_sentiment_score(
    sentiment: float,
    thresh_neg: float,
    thresh_pos: float,
    zero: float = 0,
) -> float:
    if thresh_neg != (zero - 1) / 2:
        alpha_neg = -(3 * zero - 1 - 4 * thresh_neg) / (2 * zero - 2 - 4 * thresh_neg) / 2
        if -1 < alpha_neg and alpha_neg < 0:
            raise ValueError(f"Incorrect value: {thresh_neg=} is too far from -0.5!")
    if thresh_pos != (zero + 1) / 2:
        alpha_pos = -(4 * thresh_pos - 1 - 3 * zero) / (2 + 2 * zero - 4 * thresh_pos) / 2
        if 0 < alpha_pos and alpha_pos < 1:
            raise ValueError(f"Incorrect value: {thresh_pos=} is too far from 0.5!")
    if sentiment < 0:
        return (2 * zero - 2 - 4 * thresh_neg) * sentiment**2 + (3 * zero - 1 - 4 * thresh_neg) * sentiment + zero
    elif sentiment > 0:
        return (2 + 2 * zero - 4 * thresh_pos) * sentiment**2 + (4 * thresh_pos - 1 - 3 * zero) * sentiment + zero
    return zero


def calibrate_sentiment(
    sentiments: np.ndarray[float],
    thresh_neg: float,
    thresh_pos: float,
    zero: float,
) -> np.ndarray[np.float64]:
    result = np.array(
        [
            calibrate_sentiment_score(sentiment, thresh_neg=thresh_neg, thresh_pos=thresh_pos, zero=zero)
            for sentiment in sentiments
        ]
    )
    return result.astype(np.float64)


def scale_value(value, in_min, in_max, out_min, out_max):
    if in_min <= value <= in_max:
        scaled_value = (value - in_min) / (in_max - in_min) * (out_max - out_min) + out_min
        return scaled_value.round(3)
    else:
        raise ValueError(f"Input value must be in the range [{in_min}, {in_max}]")



def get_sentiment(
    logits: np.ndarray,
    thresh_neg: float,
    thresh_pos: float,
    zero: float,
):
    probabilities = softmax(logits, axis=1)
    sentiments = np.matmul(probabilities, np.arange(5)) / 2 - 1
    score = calibrate_sentiment(
        sentiments=sentiments,
        thresh_neg=thresh_neg,
        thresh_pos=thresh_pos,
        zero=zero,
    )[0]
    if score < -0.33:
        return scale_value(score, -1, -0.33, 0, 1), "NEGATIVE"
    elif score < 0.33:
        return scale_value(score, -0.33, 0.33, 0, 1), "NEUTRAL"
    else:
        return scale_value(score, 0.33, 1, 0, 1), "POSITIVE"