EasyMetrics & Evaluation

Implement R² Score (Coefficient of Determination)

Metrics & Evaluation

Easy

Problem

Compute the coefficient of determination for one-dimensional regression targets and predictions:

R^2 = 1 - \frac{\sum_i (y_i - \hat{y}_i)^2}{\sum_i (y_i - \bar{y})^2}

Here, y_i is a target, \hat{y}_i is its prediction, and \bar{y} is the mean target. When every target is equal, return 1.0 if every prediction matches its target and 0.0 otherwise. Return the score as a Python float.

Theory

R-squared (R^2), also called the coefficient of determination, measures how well a regression model explains the variance in the target variable.

Intuition: "What proportion of the target's variance is explained by the model?"

An R^2 of 0.85 means 85% of the variance in the target is explained by the model, and 15% remains unexplained.


The Formula

R^2 = 1 - \frac{SS_{\text{res}}}{SS_{\text{tot}}}

where:

Residual Sum of Squares (unexplained variance):

SS_{\text{res}} = \sum_{i=1}^{n} (y_i - \hat{y}_i)^2

Total Sum of Squares (total variance):

SS_{\text{tot}} = \sum_{i=1}^{n} (y_i - \bar{y})^2


Understanding the Components

SS_{\text{tot}}: The total variance in the data. This is what you would get if you just predicted the mean for everything.

SS_{\text{res}}: The variance that remains after using the model. This is the squared error of your predictions.

R^2: The fraction of variance your model explains:

R^2 = 1 - \frac{\text{unexplained variance}}{\text{total variance}} = \frac{\text{explained variance}}{\text{total variance}}


Interpreting R-squared

R^2 = 1: Perfect fit. The model explains all variance. SS_{\text{res}} = 0.

R^2 = 0: The model is no better than predicting the mean. SS_{\text{res}} = SS_{\text{tot}}.

R^2 < 0: The model is worse than predicting the mean. This happens when predictions are very poor.

Typical interpretations:

Context matters. In some fields (physics), R^2 > 0.99 is expected. In others (social sciences), R^2 = 0.3 might be excellent.


Worked Example

Actual values: y = [3, 5, 7, 9, 11]

Predicted values: \hat{y} = [2.5, 5.5, 6.5, 9.5, 10]

Step 1: Compute mean of actual values

\bar{y} = (3 + 5 + 7 + 9 + 11) / 5 = 7

Step 2: Compute SS_{\text{tot}}

(3-7)^2 + (5-7)^2 + (7-7)^2 + (9-7)^2 + (11-7)^2

= 16 + 4 + 0 + 4 + 16 = 40

Step 3: Compute SS_{\text{res}}

(3-2.5)^2 + (5-5.5)^2 + (7-6.5)^2 + (9-9.5)^2 + (11-10)^2

= 0.25 + 0.25 + 0.25 + 0.25 + 1 = 2

Step 4: Compute R^2

R^2 = 1 - \frac{2}{40} = 1 - 0.05 = 0.95

The model explains 95% of the variance.


R-squared Can Be Negative

Unlike correlation (bounded -1 to 1), R^2 has no lower bound.

If SS_{\text{res}} > SS_{\text{tot}}, then R^2 < 0.

When does this happen?

Example:

Actual: [10, 20, 30]

Predicted: [100, 200, 300] (way off)

The residuals are huge compared to predicting the mean, giving negative R^2.


R-squared vs. Correlation

For simple linear regression (one feature), R^2 equals the square of the Pearson correlation:

R^2 = r^2

For multiple regression, this relationship does not hold directly. R^2 can be computed even when there is no single correlation coefficient.


Adjusted R-squared

Plain R^2 always increases when you add more features, even if they add noise. Adjusted R^2 penalizes for extra features:

R^2_{\text{adj}} = 1 - \frac{(1 - R^2)(n - 1)}{n - p - 1}

where:

Adjusted R^2 decreases if a new feature does not improve the model enough to justify its inclusion.


R-squared vs. MSE/RMSE

MSE (Mean Squared Error):

\text{MSE} = \frac{1}{n} \sum_i (y_i - \hat{y}_i)^2 = \frac{SS_{\text{res}}}{n}

Relationship:

R^2 = 1 - \frac{n \times \text{MSE}}{SS_{\text{tot}}}

Key difference:


Limitations of R-squared

Does not indicate prediction quality: A high R^2 does not mean predictions are accurate in absolute terms. If the target has huge variance, even R^2 = 0.9 can have large errors.

Does not detect bias: A model can have high R^2 but systematically over- or under-predict.

Sensitive to outliers: Both SS_{\text{tot}} and SS_{\text{res}} are based on squared values, amplifying outlier effects.

Always increases with features: More features always increase R^2 (use adjusted R^2 to counter this).

Not meaningful for some models: For non-linear models, R^2 can be misleading. Some practitioners avoid it for neural networks.


When to Use R-squared

Linear regression: R^2 is the standard metric for evaluating linear models.

Comparing models: R^2 provides a normalized score (unlike MSE which depends on scale).

Explaining to stakeholders: "The model explains 80% of the variance" is intuitive.


When to Use Other Metrics

Absolute error matters: Use MAE or RMSE to understand actual prediction errors.

Outliers are a concern: Use MAE (less sensitive) or robust metrics.

Comparing across datasets: R^2 is relative to each dataset's variance. Two datasets with same MSE can have very different R^2.

Model selection: Use cross-validated metrics to avoid overfitting.


Computing R-squared

Step 1: Compute mean of targets: \bar{y} = \frac{1}{n} \sum y_i

Step 2: Compute SS_{\text{tot}} = \sum (y_i - \bar{y})^2

Step 3: Compute SS_{\text{res}} = \sum (y_i - \hat{y}_i)^2

Step 4: R^2 = 1 - SS_{\text{res}} / SS_{\text{tot}}

Handle edge case: if SS_{\text{tot}} = 0 (all targets are identical), R^2 is undefined.

Examples

Example 1

Input
y_true = [3, 4, 5], y_pred = [2.9, 4.1, 5.0]
Output
0.99
Explanation
The residual sum of squares is 0.02 and the total sum of squares is 2, so the score is 1 - 0.02 / 2.

Example 2

Input
y_true = [1, 1, 1], y_pred = [1, 1, 1]
Output
1.0

Example 3

Input
y_true = [1, 1, 1], y_pred = [0, 2, 1]
Output
0.0

Hints

  1. Use np.sum((y_true - y_pred) ** 2) for the residual sum of squares.
  2. Check whether the total sum of squares is zero before applying the fraction.

Requirements

Constraints

Starter Code

import numpy as np

def r2_score(y_true: list, y_pred: list) -> float:
    """
    Returns the coefficient of determination as a Python float.
    """
    # Write code here
    pass

Test Cases

CaseMatches
Close fitExample 1public
Constant perfectExample 2public
Constant imperfectExample 3public