Skip to main content

Section 10.2 Coefficient of Determination

Suppose you want to guess the weight of a penguin. If you know its flipper length, you can use the least squares fit to inform your guess, and the MSE quantifies the accuracy of your guesses, on average.
But what if you don’t know the flipper length -- what would you guess? It turns out that guessing the mean is the best strategy in the sense that it minimizes the MSE. If we always guess the mean, the prediction errors are the deviations from the mean.
Listing 10.2.1. Python Code
deviations = body_mass - np.mean(body_mass)
And the MSE is the mean squared deviation.
Listing 10.2.2. Python Code
$ np.mean(deviations**2)
np.float64(208890.28989956583)
You might remember that the mean squared deviation is the variance.
Listing 10.2.3. Python Code
$ np.var(body_mass)
np.float64(208890.28989956583)
So we can think of the variance of the masses as the MSE if we always guess the mean, and the variance of the residuals as the MSE if we use the regression line. If we compute the ratio of these variances and subtract it from 1, the result indicates how much the MSE is reduced if we use flipper lengths to inform our guesses.
The following function computes this value, which is technically called the coefficient of determination, but because it is denoted \(R^2\text{,}\) most people call it "R squared".
Listing 10.2.4. Python Code
def coefficient_of_determination(ys, residuals):
    return 1 - np.var(residuals) / np.var(ys)
In the example, \(R^2\) is about 0.22, which means that the fitted line reduces MSE by 22%.
Listing 10.2.5. Python Code
$ R2 = coefficient_of_determination(body_mass, residuals)
R2
np.float64(0.21921282646854912)
It turns out that there’s a relationship between the coefficient of determination, \(R^2\text{,}\) and the coefficient of correlation, \(r\text{.}\) As you might guess based on the notation, \(r^2 = R^2\text{.}\)
We can show that’s true by computing the square root of \(R^2\text{.}\)
Listing 10.2.6. Python Code
$ r = np.sqrt(R2)
r
np.float64(0.4682016942179397)
And comparing it to the correlation we computed earlier.
Listing 10.2.7. Python Code
$ corr = np.corrcoef(flipper_length, body_mass)[0, 1]
corr
np.float64(0.4682016942179394)
They are the same except for a small difference due to floating-point approximation.
The linregress function also computes this value and returns it as an attribute in the RegressionResult object.
Listing 10.2.8. Python Code
$ result.rvalue
np.float64(0.46820169421793933)
The coefficients of determination and correlation convey mostly the same information, but they are interpreted differently:
  • Correlation quantifies the strength of the relationship on a scale from -1 to 1.
  • \(R^2\) quantifies the ability of the fitted line to reduce MSE.
Also, \(R^2\) is always positive, so it doesn’t indicate whether the correlation is positive or negative.