← Назад к вопросам

Что такое R-squared (коэффициент детерминации)?

1.6 Junior🔥 231 комментариев
#Машинное обучение#Метрики и оценка моделей

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

R-squared (Коэффициент детерминации)

R-squared (R²) — это метрика, которая показывает, какую часть вариации целевой переменной объясняет модель. Это наиболее используемая метрика для оценки качества регрессионных моделей. R² принимает значения от 0 до 1 (или от 0% до 100%), где 1 означает идеальное предсказание, а 0 означает, что модель не лучше, чем предсказание среднего значения.

Математическое определение

R-squared вычисляется как отношение объяснённой вариации к общей вариации:

R² = 1 - (SS_res / SS_tot)

Где:

  • SS_res (Sum of Squares of Residuals) — сумма квадратов остатков (необъяснённая вариация)
  • SS_tot (Total Sum of Squares) — общая сумма квадратов (полная вариация)

Детальная формула:

SS_res = Сумма((y_true - y_pred)²)
SS_tot = Сумма((y_true - y_mean)²)

R² = 1 - (SS_res / SS_tot)
     = (SS_tot - SS_res) / SS_tot
     = SS_exp / SS_tot

Где SS_exp — объяснённая вариация.

Практический пример вычисления

import numpy as np
from sklearn.metrics import r2_score

# Истинные значения
y_true = np.array([3, -0.5, 2, 7])

# Предсказания модели
y_pred = np.array([2.5, 0.0, 2, 8])

# Вычисляем вручную
y_mean = np.mean(y_true)
ss_res = np.sum((y_true - y_pred) ** 2)  # (3-2.5)² + (-0.5-0)² + (2-2)² + (7-8)²
ss_tot = np.sum((y_true - y_mean) ** 2)  # (3-2.875)² + (-0.5-2.875)² + ...

print(f"SS_res = {ss_res}")  # 2.5
print(f"SS_tot = {ss_tot}")  # 42.75

r2 = 1 - (ss_res / ss_tot)
print(f"R² (вручную) = {r2:.4f}")  # 0.9415

# Используя scikit-learn
r2_sklearn = r2_score(y_true, y_pred)
print(f"R² (scikit-learn) = {r2_sklearn:.4f}")  # 0.9415

Интерпретация R-squared

Значение R²Интерпретация
0.9-1.0Отличная модель, объясняет 90-100% вариации
0.7-0.9Хорошая модель, объясняет 70-90% вариации
0.5-0.7Приемлемая модель, объясняет 50-70% вариации
0.3-0.5Слабая модель, объясняет 30-50% вариации
< 0.3Очень слабая модель
Отрицательный R²Модель хуже, чем просто предсказание среднего

Пример с разными моделями

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import r2_score

# Генерируем данные
np.random.seed(42)
X = np.linspace(0, 10, 100).reshape(-1, 1)
y = 2 * X.ravel() + np.random.normal(0, 2, 100)

# Модель 1: Линейная регрессия
lr = LinearRegression()
lr.fit(X, y)
y_pred_lr = lr.predict(X)
r2_lr = r2_score(y, y_pred_lr)

# Модель 2: Полиномиальная регрессия (2 степень)
poly2 = PolynomialFeatures(degree=2)
X_poly2 = poly2.fit_transform(X)
lr_poly2 = LinearRegression()
lr_poly2.fit(X_poly2, y)
y_pred_poly2 = lr_poly2.predict(X_poly2)
r2_poly2 = r2_score(y, y_pred_poly2)

# Модель 3: Полиномиальная регрессия (10 степень — переобучение)
poly10 = PolynomialFeatures(degree=10)
X_poly10 = poly10.fit_transform(X)
lr_poly10 = LinearRegression()
lr_poly10.fit(X_poly10, y)
y_pred_poly10 = lr_poly10.predict(X_poly10)
r2_poly10 = r2_score(y, y_pred_poly10)

print(f"R² линейная модель: {r2_lr:.4f}")
print(f"R² полиномиальная (2 степень): {r2_poly2:.4f}")
print(f"R² полиномиальная (10 степень): {r2_poly10:.4f}")

# Визуализация
plt.figure(figsize=(15, 5))

plt.subplot(1, 3, 1)
plt.scatter(X, y, alpha=0.5, label='Истинные данные')
plt.plot(X, y_pred_lr, 'r-', linewidth=2, label='Линейная регрессия')
plt.title(f'Линейная модель (R² = {r2_lr:.4f})')
plt.legend()

plt.subplot(1, 3, 2)
plt.scatter(X, y, alpha=0.5, label='Истинные данные')
plt.plot(X, y_pred_poly2, 'g-', linewidth=2, label='Полином 2 степени')
plt.title(f'Полином 2 степени (R² = {r2_poly2:.4f})')
plt.legend()

plt.subplot(1, 3, 3)
plt.scatter(X, y, alpha=0.5, label='Истинные данные')
plt.plot(X, y_pred_poly10, 'orange', linewidth=2, label='Полином 10 степени')
plt.title(f'Полином 10 степени (R² = {r2_poly10:.4f})')
plt.legend()

plt.tight_layout()
plt.show()

Отрицательный R-squared

R² может быть отрицательным, если модель предсказывает хуже, чем среднее значение:

# Пример плохой модели с отрицательным R²
from sklearn.linear_model import Ridge

# Создаём модель с очень высокой регуляризацией
ridge = Ridge(alpha=10000)
ridge.fit(X, y)
y_pred_ridge = ridge.predict(X)
r2_ridge = r2_score(y, y_pred_ridge)

print(f"R² модель с высокой регуляризацией: {r2_ridge:.4f}")
# Может быть отрицательным, если предсказания совсем неправильные

Adjusted R-squared

Adjusted R² (скорректированный R²) — это модификация R², которая штрафует за добавление новых признаков:

Adjusted R² = 1 - ((1 - R²) * (n - 1) / (n - p - 1))

Где:

  • n — количество наблюдений
  • p — количество признаков

Почему нужен Adjusted R²?

Обычный R² всегда растёт при добавлении новых признаков, даже если они не полезны. Adjusted R² штрафует за лишние признаки.

from sklearn.metrics import r2_score

def adjusted_r2(y_true, y_pred, n_features):
    n = len(y_true)
    r2 = r2_score(y_true, y_pred)
    adj_r2 = 1 - ((1 - r2) * (n - 1) / (n - n_features - 1))
    return adj_r2

# Пример
y_true = np.array([1, 2, 3, 4, 5])
y_pred = np.array([1.1, 2.1, 2.9, 4.2, 4.8])
n_features = 2

r2 = r2_score(y_true, y_pred)
adj_r2 = adjusted_r2(y_true, y_pred, n_features)

print(f"R²: {r2:.4f}")
print(f"Adjusted R²: {adj_r2:.4f}")

Ограничения R-squared

1. Не показывает направление ошибок

# Две разные модели могут иметь одинаковый R²
y_true = np.array([1, 2, 3, 4, 5])
y_pred1 = np.array([1.1, 2.1, 3.0, 3.9, 5.1])
y_pred2 = np.array([1.5, 2.5, 2.5, 4.5, 4.5])

print(f"R² модель 1: {r2_score(y_true, y_pred1):.4f}")
print(f"R² модель 2: {r2_score(y_true, y_pred2):.4f}")
# Обе могут быть высокие, но распределение ошибок разное

2. Может быть неправильно интерпретирован Высокий R² не означает причинно-следственную связь.

3. Зависит от масштаба данных Одна и та же модель может иметь разные R² на разных масштабах.

4. Не учитывает смещение (bias)

from sklearn.metrics import mean_absolute_error, mean_squared_error

y_true = np.array([1, 2, 3, 4, 5])
y_pred = np.array([2, 3, 4, 5, 6])  # Все предсказания смещены на +1

print(f"R²: {r2_score(y_true, y_pred):.4f}")  # Очень высокий
print(f"MAE: {mean_absolute_error(y_true, y_pred):.4f}")  # Но есть систематическое смещение

R² в scikit-learn

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.datasets import load_diabetes

# Загружаем данные
X, y = load_diabetes(return_X_y=True)

# Обучаем модель
model = LinearRegression()
model.fit(X, y)

# Способ 1: Используя метод score
r2_score1 = model.score(X, y)

# Способ 2: Используя функцию r2_score
y_pred = model.predict(X)
r2_score2 = r2_score(y, y_pred)

print(f"R² (method score): {r2_score1:.4f}")
print(f"R² (function r2_score): {r2_score2:.4f}")

Сравнение R² с другими метриками

from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_absolute_percentage_error

y_true = np.array([3, -0.5, 2, 7])
y_pred = np.array([2.5, 0.0, 2, 8])

print(f"R²: {r2_score(y_true, y_pred):.4f}")
print(f"MSE: {mean_squared_error(y_true, y_pred):.4f}")
print(f"RMSE: {np.sqrt(mean_squared_error(y_true, y_pred)):.4f}")
print(f"MAE: {mean_absolute_error(y_true, y_pred):.4f}")
print(f"MAPE: {mean_absolute_percentage_error(y_true, y_pred):.4f}")

Лучшие практики

1. Используй несколько метрик Never rely on R² alone. Используй вместе с MSE, MAE, RMSE.

2. Проверь на тестовых данных

X_train, X_test, y_train, y_test = train_test_split(X, y)
model.fit(X_train, y_train)
r2_train = model.score(X_train, y_train)
r2_test = model.score(X_test, y_test)
print(f"R² train: {r2_train:.4f}")
print(f"R² test: {r2_test:.4f}")
# Большая разница указывает на переобучение

3. Используй Adjusted R² при сравнении моделей Это предотвращает переусложнение модели.

4. Визуализируй остатки Высокий R² не гарантирует хорошую модель.

Заключение

R-squared — это фундаментальная метрика для оценки регрессионных моделей, показывающая, какую долю вариации в данных объясняет модель. Однако её следует использовать вместе с другими метриками и всегда проверять остатки и тестовую производительность.