Answer
Is R-squared useful or misleading?
The short answer
Both, depending on the question. R-squared tells you what share of the variation in your outcome the model accounts for in this sample. It does not tell you whether the model is correct, whether the relationship is linear, or how precise your predictions are, and it depends heavily on how widely the predictor happens to vary. Use it as a descriptive summary alongside residual plots and the residual standard error, not as a score of model quality.
What R-squared actually measures
For a linear regression with an intercept, R-squared is one minus the ratio of the residual sum of squares to the total sum of squares. In words: of all the variation in y around its mean, what fraction is accounted for by the fitted values? It runs from 0 to 1 and, for simple regression, equals the squared correlation between x and y.
That is a statement about this sample, not about the truth of the model. Two very different things feed into it: how strongly y responds to x, and how much x itself varies. In the population, for a straight-line model with slope b, the share of variance explained is b² Var(x) / (b² Var(x) + σ²), where σ² is the noise variance. Hold the slope and the noise fixed and widen the range of x, and R-squared climbs toward 1. Narrow the range, and it sinks toward 0, even though the model is exactly right in both cases.
Three ways it misleads
- It rewards spread in the predictor. A study that samples a wide range of doses, ages or incomes will report a higher R-squared than one that samples a narrow band, with the same underlying relationship. Comparing R-squared across studies with different designs compares the designs as much as the models.
- It can be high for the wrong model. When
yis a smooth curve inx, a straight line often tracks most of the variation and scores well above 0.9, while leaving systematic errors that a residual plot shows at once. - It never goes down when you add terms. Ordinary R-squared can only stay the same or rise as predictors are added, even pure noise. With
puseless predictors andnobservations, it rises by about p/(n - 1) of the unexplained share on average.
A low R-squared is not a failure either. In fields where outcomes are driven by many small influences, such as behavior or health, a correct model with a precisely estimated effect can explain only a few percent of the variance. Whether that effect matters depends on its size and its confidence interval, not on R-squared.
See it in R and Python
The code below makes each problem concrete with base R: the same straight line with a wide and a narrow range of x, a straight line fitted to a curve, and ten pure-noise predictors added to a model. The Python tab does the same analysis with NumPy.
R
set.seed(13314)
n <- 200
# 1. Same line, same noise, different spread of x
x_wide <- runif(n, 0, 20)
x_narrow <- runif(n, 0, 2)
y_wide <- 1 + 0.5 * x_wide + rnorm(n, sd = 1)
y_narrow <- 1 + 0.5 * x_narrow + rnorm(n, sd = 1)
fw <- lm(y_wide ~ x_wide)
fn <- lm(y_narrow ~ x_narrow)
summ <- function(f) c(slope = coef(f)[[2]], se = coef(summary(f))[2, 2],
sigma = sigma(f), R2 = summary(f)$r.squared)
round(rbind(wide = summ(fw), narrow = summ(fn)), 3)
# 2. A straight line fitted to a curve can still score a high R2
x <- runif(n, 1, 10)
y <- x^2 + rnorm(n, sd = 2)
lin <- lm(y ~ x)
quad <- lm(y ~ x + I(x^2))
round(c(R2_linear = summary(lin)$r.squared, R2_quadratic = summary(quad)$r.squared,
sigma_linear = sigma(lin), sigma_quadratic = sigma(quad)), 3)
# 3. Pure-noise predictors still push R2 up; adjusted R2 does not follow
noise <- matrix(rnorm(n * 10), n, 10)
f0 <- lm(y_narrow ~ x_narrow)
f1 <- lm(y_narrow ~ x_narrow + noise)
round(rbind(
one_predictor = c(R2 = summary(f0)$r.squared, adjR2 = summary(f0)$adj.r.squared),
plus_10_noise = c(R2 = summary(f1)$r.squared, adjR2 = summary(f1)$adj.r.squared)
), 3)Python
import numpy as np
rng = np.random.default_rng(13314)
n = 200
def fit(y, *cols):
# OLS with intercept; returns coefficients, their SEs, sigma, R2 and adjusted R2
X = np.column_stack([np.ones(len(y)), *cols])
beta, *_ = np.linalg.lstsq(X, y, rcond=None)
resid = y - X @ beta
df = len(y) - X.shape[1]
s2 = resid @ resid / df
se = np.sqrt(np.diag(s2 * np.linalg.inv(X.T @ X)))
r2 = 1 - resid @ resid / np.sum((y - y.mean()) ** 2)
adj = 1 - (1 - r2) * (len(y) - 1) / df
return beta, se, np.sqrt(s2), r2, adj
# 1. Same line, same noise, different spread of x
x_wide, x_narrow = rng.uniform(0, 20, n), rng.uniform(0, 2, n)
y_wide = 1 + 0.5 * x_wide + rng.normal(0, 1, n)
y_narrow = 1 + 0.5 * x_narrow + rng.normal(0, 1, n)
for name, (y, x) in {"wide": (y_wide, x_wide), "narrow": (y_narrow, x_narrow)}.items():
b, se, s, r2, _ = fit(y, x)
print(f"{name:7s} slope={b[1]:.3f} se={se[1]:.3f} sigma={s:.3f} R2={r2:.3f}")
# 2. A straight line fitted to a curve can still score a high R2
x = rng.uniform(1, 10, n)
y = x**2 + rng.normal(0, 2, n)
lin, quad = fit(y, x), fit(y, x, x**2)
print(f"R2 linear={lin[3]:.3f} quadratic={quad[3]:.3f}; sigma linear={lin[2]:.3f} quadratic={quad[2]:.3f}")
# 3. Pure-noise predictors still push R2 up; adjusted R2 does not follow
noise = rng.normal(size=(n, 10))
f0, f1 = fit(y_narrow, x_narrow), fit(y_narrow, x_narrow, noise)
print(f"one predictor: R2={f0[3]:.3f} adjR2={f0[4]:.3f}")
print(f"plus 10 noise: R2={f1[3]:.3f} adjR2={f1[4]:.3f}")The figures below come from one seeded run of the R code. Python uses a different random number generator, so its figures differ slightly, but the pattern is the same.
- Spread of x. Both datasets follow the same line (slope 0.5, noise SD 1), and both fits recover a residual SD close to 1 (1.005 and 1.019). Yet R-squared is 0.888 with the wide range and 0.027 with the narrow one.
- Why the narrow one is so low. In theory the values would be about 0.89 and 0.08; the narrow sample came out lower because its estimated slope (0.294) fell short of 0.5 by chance. Its standard error (0.125, against 0.013) shows the real cost of a narrow design: an imprecise slope, not a wrong model.
- Curvature. The straight line fitted to a quadratic curve reaches an R-squared of 0.951. The quadratic model reaches 0.996, but the telling number is the residual SD: 6.363 for the line against 1.930 for the curve, close to the true noise SD of 2. A residual plot shows the line's U-shaped misfit at once.
- Noise predictors. Adding ten columns of random numbers raised R-squared from 0.027 to 0.077. Adjusted R-squared, which charges for each extra term, barely moved (0.022 to 0.023). It corrects for the extra terms on average, so in another sample it may drift a little up or down.
When R-squared is useful
- Comparing models for the same outcome on the same data. Here the spread of
xandyis fixed, so a gain in R-squared is a real gain in fit. Use adjusted R-squared, AIC or cross-validation when the models have different numbers of terms. - Describing how much of the outcome is left unexplained. An R-squared of 0.3 says that most of the variation comes from things outside the model, which is worth knowing when you plan predictions for individuals.
- Checking effect size in context. Within a well-defined population and design, R-squared (or its change when a predictor is added) is a reasonable effect size to report alongside the coefficients.
For judging whether the model is right, look at residual plots. For judging how precise predictions will be, look at the residual standard error, which is in the units of y. For judging whether an effect is real and how large it is, look at the coefficient and its confidence interval. If you are choosing between models with different numbers of predictors, our page on AIC vs BIC covers the penalized alternatives.
How to report R-squared in APA style (7th edition)
Report R-squared (or adjusted R-squared) as part of the model results, not as the headline. Italicize R, give two decimals, and drop the leading zero because it cannot exceed 1. Using the wide-range example above:
"A simple linear regression showed that y increased with x, b = 0.51, SE = 0.01, and the model accounted for most of the variance in y, R² = .89."
For models with several predictors, report adjusted R² as well, and when a block of predictors is added, report the change (ΔR²) with its F test. In a regression table, put R² and adjusted R² in the bottom rows under the coefficients.
Related tools and guides
- APA 7 formatter for regression
- AIC vs BIC: which model selection criterion should you use?
- Which statistical test should I use?
- Coefficient of determination (Wikipedia)
More answered questions
- Centering vs standardizing predictors in regression: when to do which?
- Logit vs probit: what is the difference, and which should you use?
- AIC vs BIC: which model selection criterion should you use?
Working with your own data?
General answers only go so far. Send us your situation and we'll reply by email within two business days.
Ask your questionWritten by AskStats with AI assistance. This is general information, not advice for your specific data or study. When the results matter, check your approach with a qualified statistician.