ryanjgallagher / shifterator

Interpretable data visualizations for understanding how texts differ at the word level
Apache License 2.0
273 stars 29 forks source link

Tsallis entropy graphing #28

Closed pverspeelt closed 2 years ago

pverspeelt commented 2 years ago

When you use the entropy function with an alpha < 1 the data on the graph is flipped, compared to all the other functions. Using alpha = 1 or alpha > 1 will show the graph corresponding the input. In the cookbook you solved this by swithing the titles of the graph around, see Cookbook Tsallis Entropy, but for a casual user who always uses the same order of input values, this is not immediately obvious. The only reason I spotted this is because I'm translating this into R code and was paying close attention to how individual words are calculated and shown on the graphs.

See how the value of "A" switches when alpha is smaller than 1.

import shifterator as sh

text1 = {"A": 10, "B": 10, "C": 10, "D": 10, "E": 10, "F": 10, "G": 10}
text2 = {"B": 10, "C": 10, "D": 10, "E": 10, "F": 10, "G": 10, "H": 10}

# switches text1 and text2 when plotting (text1 on the right, value "A")
entropy_shift_incorrect = sh.EntropyShift(type2freq_1 = text1,
                                type2freq_2 = text2,
                                base = 2,
                                alpha = 0.8)

entropy_shift_incorrect.get_shift_graph(system_names = ["text1", "text2"])

# shows text1 and text2 correctly when plotting (text1 on the left, value "A") conform other shifts and graphs
entropy_shift_correct = sh.EntropyShift(type2freq_1 = text1,
                                type2freq_2 = text2,
                                base = 2,
                                alpha = 1.2)

entropy_shift_correct.get_shift_graph(system_names = ["text1", "text2"])

# shows text1 and text2 correctly when plotting (text1 on the left, value "A") conform other shifts and graphs
entropy_shift2 = rs.EntropyShift(type2freq_1 = text1,
                                type2freq_2 = text2)

entropy_shift2.get_shift_graph(system_names = ["text1", "text2"])

A simple solution is to multiply the values in get_entropy_type_scores by -1 when alpha is smaller than 1. Something like below should do the trick. (or take the absolute value if this is the case). Unless I'm missing something about the explainability of the Tsallis calculation.

    if alpha == 1:
        if p_1 > 0:
            score_1 = -log(p_1, base)
        if p_2 > 0:
            score_2 = -log(p_2, base)
    elif alpha > 1:
        if p_1 > 0:
            score_1 = p_1 ** (alpha - 1) / (alpha - 1)
        if p_2 > 0:
            score_2 = p_2 ** (alpha - 1) / (alpha - 1)
    elif alpha > 0:
        if p_1 > 0:
            score_1 = -p_1 ** (alpha - 1) / (alpha - 1)
        if p_2 > 0:
            score_2 = -p_2 ** (alpha - 1) / (alpha - 1)
ryanjgallagher commented 2 years ago

I believe the flipping is "expected" behavior. What was wrong though was what was flipping, and this led me finding a notable bug where I was missing negative signs on both score_1 and score_2 (5617c7101d9376aed8d2ba6d6b3a762bded6b40a). So what you should see now is that alpha = 1 and alpha = 0.8 are consistent in terms of direction, while alpha = 1.2 shows the flipping.

It's a bit tough to think intuitively about why it flips, but it has to do with the alpha - 1 term that's in the denominator. Because that term goes from negative to positive as alpha goes from below 1 to above 1, the overall entropy seems to go from positive to negative (given 5617c7101d9376aed8d2ba6d6b3a762bded6b40a). A and H are always contributing to those entropies in some direction. Because the overall direction of the entropies flips with alpha, I believe that's why the directions of A and H flip when everything else is held the constant.