%matplotlib inline

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn
seaborn.set_style('whitegrid')

def r2(actual, predicted):
    if isinstance(actual, list):
        actual = np.array(actual)
    if isinstance(predicted, list):
        predicted = np.array(predicted)
        
    plt.scatter(actual, predicted);
    plt.plot(actual, actual, 'r', alpha=0.5)
    plt.scatter(actual, actual, facecolors='none', edgecolor='r', linestyle='-')
    plt.axhline(y=actual.mean(), ls='dashed')
        
    mean = actual.mean()
    ss_total = ((actual - mean) ** 2).sum()
    ss_residual = ((actual - predicted) ** 2).sum()
    return 1 - ss_residual / ss_total

"""
Explanation: Coefficient of Determination (R2)
End of explanation
"""


actual = list(range(10))
actual

predicted = list(range(10))
r2(actual, predicted)

"""
Explanation: We'll get a perfect R2=1 if actual and predicted values are the same
End of explanation
"""


predicted = list(range(8)) + [9, 10]
predicted

r2(actual, predicted)

"""
Explanation: Now if we're a bit off on our predictions R2 will be still pretty high but not a perfect 1.
End of explanation
"""


predicted = list(range(8)) + [13, 15]
predicted

r2(actual, predicted)

"""
Explanation: Intuitively it makes sense that we get a worse R2 if the predictions are farther off.
End of explanation
"""


predicted = list(range(8)) + [100, 150]
predicted

"""
Explanation: Now here's the interesting situation: R2 can be negative.
End of explanation
"""


r2(actual, predicted)

"""
Explanation: This is because R2 is calculated relative to a hypothetical model that always predicts the mean of the actual values. Obviously we don't have access to the mean of actual values at the time of prediction but we do at evaluation time.
So looking at lines 12-13 in In[2] you can see that:
mean = actual.mean()
ss_total = ((actual - mean) ** 2).sum()
and then R2 is:
ss_residual = ((actual - predicted) ** 2).sum()
R2 = 1 - ss_residual / ss_total
So obviously if we're way off on our predictions we'll be worse than this hypothetical mean model.
End of explanation
"""


actual = [1] * 10

r2(actual, [1] * 10)

r2(actual, [-100] * 10)

actual = list(range(10))

r2(actual, [1] * 10)

"""
Explanation: Special cases
End of explanation
"""


r2(actual, [4.5] * 10)

"""
Explanation: Predicting exactly the same as mean everytime gives us an R2=0
End of explanation
"""


