Примечание
Перейти к концу для скачивания полного примера кода. Или запустить этот пример в браузере с помощью JupyterLite или Binder
Общие ошибки при интерпретации коэффициентов линейных моделей
В линейных моделях целевое значение моделируется как линейная комбинация признаков (см. раздел «Линейные модели» в руководстве пользователя, для описания набора линейных моделей, доступных в scikit-learn). Коэффициенты в многомерных линейных моделях представляют собой взаимосвязь между заданным признаком \(X_i\) и целевым значением \(y\), при условии, что все остальные признаки остаются постоянными (условная зависимость). Это отличается от построения графика \(X_i\) против \(y\) и подгонки линейной зависимости: в этом случае при оценке учитываются все возможные значения других признаков (маргинальная зависимость).
Этот пример предоставит некоторые подсказки по интерпретации коэффициентов в линейных моделях, указывая на проблемы, возникающие, когда либо линейная модель не подходит для описания набора данных, либо когда признаки коррелированы.
Примечание
Обратите внимание, что признаки \(X\) и результат \(y\) обычно являются результатом неизвестного для нас процесса генерации данных. Модели машинного обучения обучаются на примере, чтобы приблизить неочевидную математическую функцию, связывающую \(X\) с \(y\). В результате любая интерпретация, сделанная относительно модели, может не обобщаться на реальный процесс генерации данных. Это особенно верно, когда модель имеет низкое качество или когда выборка данных не является репрезентативной для генеральной совокупности.
Мы будем использовать данные из “Общей переписи населения” 1985 года для прогнозирования заработной платы в зависимости от различных признаков, таких как опыт работы, возраст или образование.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy as sp import seaborn as sns
Набор данных: заработная плата
Мы получаем данные из OpenML. Обратите внимание, что установка параметра as_frame в значение True позволит получить данные в виде pandas DataFrame.
from sklearn.datasets import fetch_openml survey = fetch_openml(data_id=534, as_frame=True)
Затем мы определяем признаки X и целевые значения y: столбец WAGE является нашей целевой переменной (т.е. переменной, которую мы хотим предсказать).
X = survey.data[survey.feature_names] X.describe(include="all")
Обратите внимание, что набор данных содержит категориальные и числовые переменные. Это следует учитывать при последующей предобработке набора данных.
X.head()
Наша целевая переменная для предсказания: заработная плата. Заработная плата описывается как число с плавающей точкой в долларах в час.
y = survey.target.values.ravel() survey.target.head()
0 5.10 1 4.95 2 6.67 3 4.00 4 7.50 Name: WAGE, dtype: float64
Мы разделим выборку на обучающую и тестовую выборки. Только обучающая выборка будет использоваться в последующем исследовательском анализе. Это способ смоделировать реальную ситуацию, когда прогнозы выполняются на неизвестной цели, и мы не хотим, чтобы наш анализ и решения были предвзяты знанием тестовых данных.
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
Сначала давайте получим некоторые сведения, изучив распределения переменных и парные взаимосвязи между ними. Будут использованы только числовые переменные. На следующем графике каждая точка представляет собой образец.
train_dataset = X_train.copy() train_dataset.insert(0, "WAGE", y_train) _ = sns.pairplot(train_dataset, kind="reg", diag_kind="kde")

Внимательный взгляд на распределение WAGE показывает, что у него длинный хвост. По этой причине мы должны взять его логарифм, чтобы приблизительно преобразовать его в нормальное распределение (такие линейные модели, как ridge или lasso, лучше всего работают при нормальном распределении ошибки).
WAGE увеличивается при увеличении EDUCATION. Обратите внимание, что зависимость между WAGE и EDUCATION, представленная здесь, является маргинальной зависимостью, т.е. она описывает поведение конкретной переменной без сохранения других фиксированными.
Также EXPERIENCE и AGE сильно линейно коррелированы.
Этапы машинного обучения
Для разработки нашей системы машинного обучения мы сначала вручную проверяем тип данных, с которыми имеем дело:
survey.data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 534 entries, 0 to 533 Data columns (total 10 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 EDUCATION 534 non-null int64 1 SOUTH 534 non-null category 2 SEX 534 non-null category 3 EXPERIENCE 534 non-null int64 4 UNION 534 non-null category 5 AGE 534 non-null int64 6 RACE 534 non-null category 7 OCCUPATION 534 non-null category 8 SECTOR 534 non-null category 9 MARR 534 non-null category dtypes: category(7), int64(3) memory usage: 17.2 KB
Как видно ранее, набор данных содержит столбцы с разными типами данных, и нам необходимо применять специфическую предобработку для каждого типа данных. В частности, категориальные переменные не могут быть включены в линейную модель, если сначала не закодированы как целые числа. Кроме того, чтобы избежать того, что категориальные признаки обрабатывались как упорядоченные значения, нам необходимо выполнить их кодирование с помощью one-hot кодирования. Наш препроцессор будет:
- one-hot кодировать (т.е., генерировать столбец по категориям) категориальные столбцы, только для категориальных переменных, не являющихся бинарными;
- в качестве первого подхода (мы увидим позже, как нормализация числовых значений повлияет на наш обсуждение), сохранить числовые значения такими, как они есть.
from sklearn.compose import make_column_transformer
from sklearn.preprocessing import OneHotEncoder
categorical_columns = ["RACE", "OCCUPATION", "SECTOR", "MARR", "UNION", "SEX", "SOUTH"]
numerical_columns = ["EDUCATION", "EXPERIENCE", "AGE"]
preprocessor = make_column_transformer(
(OneHotEncoder(drop="if_binary"), categorical_columns),
remainder="passthrough",
verbose_feature_names_out=False, # avoid to prepend the preprocessor names
)
Для описания набора данных как линейной модели мы используем регрессор Ridge с очень маленькой регуляризацией и для моделирования логарифма WAGE.
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import Ridge
from sklearn.pipeline import make_pipeline
model = make_pipeline(
preprocessor,
TransformedTargetRegressor(
regressor=Ridge(alpha=1e-10), func=np.log10, inverse_func=sp.special.exp10
),
)
Обработка набора данных
Сначала мы подгоняем модель.
model.fit(X_train, y_train)
Затем мы проверяем производительность вычисленной модели, строя её предсказания на тестовом наборе и вычисляя, например, медианную абсолютную ошибку модели.
from sklearn.metrics import PredictionErrorDisplay, median_absolute_error
mae_train = median_absolute_error(y_train, model.predict(X_train))
y_pred = model.predict(X_test)
mae_test = median_absolute_error(y_test, y_pred)
scores = {
"MedAE on training set": f"{mae_train:.2f} $/hour",
"MedAE on testing set": f"{mae_test:.2f} $/hour",
}
_, ax = plt.subplots(figsize=(5, 5))
display = PredictionErrorDisplay.from_predictions(
y_test, y_pred, kind="actual_vs_predicted", ax=ax, scatter_kwargs={"alpha": 0.5}
)
ax.set_title("Ridge model, small regularization")
for name, score in scores.items():
ax.plot([], [], " ", label=f"{name}: {score}")
ax.legend(loc="upper left")
plt.tight_layout()

Полученная модель далека от хорошей модели, делающей точные прогнозы: это очевидно, когда смотрим на график выше, где хорошие прогнозы должны лежать на чёрной пунктирной линии.
В следующем разделе мы проанализируем коэффициенты модели. При этом мы должны помнить, что любое выводимое нами заключение относится к построенной модели, а не к истинному (реальному) генерирующему процессу данных.
Интерпретация коэффициентов: масштаб имеет значение
Прежде всего, мы можем взглянуть на значения коэффициентов регрессора, который мы подгоняли.
feature_names = model[:-1].get_feature_names_out()
coefs = pd.DataFrame(
model[-1].regressor_.coef_,
columns=["Coefficients"],
index=feature_names,
)
coefs
Коэффициент AGE выражен в «долларах/час на год жизни», а коэффициент EDUCATION — в «долларах/час на год образования». Это представление коэффициентов имеет преимущество в том, что оно чётко показывает практические предсказания модели: увеличение на 1 год возраста означает снижение на 0,030867 доллара/час, а увеличение на 1 год образования означает повышение на 0,054699 доллара/час. С другой стороны, категориальные переменные (например, UNION или SEX) — это безразмерные числа, принимающие значения 0 или 1. Их коэффициенты выражены в долларах/час. Тогда мы не можем сравнивать величину разных коэффициентов, так как у признаков разные естественные масштабы, а следовательно, и диапазоны значений, из-за разных единиц измерения. Это более заметно, если мы отобразим коэффициенты.
coefs.plot.barh(figsize=(9, 7))
plt.title("Ridge model, small regularization")
plt.axvline(x=0, color=".5")
plt.xlabel("Raw coefficient values")
plt.subplots_adjust(left=0.3)

Действительно, из графика выше наиболее важным фактором, определяющим WAGE, кажется переменная UNION, даже если наша интуиция подсказывает, что такие переменные, как EXPERIENCE, должны иметь большее влияние.
Взгляд на график коэффициентов для оценки важности признаков может быть вводящим в заблуждение, так как некоторые из них изменяются в небольшом масштабе, в то время как другие, например AGE, изменяются гораздо больше, на несколько десятилетий.
Это видно, если сравнить стандартные отклонения различных признаков.
X_train_preprocessed = pd.DataFrame(
model[:-1].transform(X_train), columns=feature_names
)
X_train_preprocessed.std(axis=0).plot.barh(figsize=(9, 7))
plt.title("Feature ranges")
plt.xlabel("Std. dev. of feature values")
plt.subplots_adjust(left=0.3)

Умножение коэффициентов на стандартное отклонение соответствующего признака привело бы к приведению всех коэффициентов к одинаковой единице измерения. Как мы увидим дальше, это эквивалентно нормализации числовых переменных к их стандартному отклонению, так как \(y = \sum{coef_i \times X_i} = \sum{(coef_i \times std_i) \times (X_i / std_i)}\).
Таким образом, мы подчеркиваем, что чем больше дисперсия признака, тем больше вес соответствующего коэффициента на выходе при прочих равных условиях.
coefs = pd.DataFrame(
model[-1].regressor_.coef_ * X_train_preprocessed.std(axis=0),
columns=["Coefficient importance"],
index=feature_names,
)
coefs.plot(kind="barh", figsize=(9, 7))
plt.xlabel("Coefficient values corrected by the feature's std. dev.")
plt.title("Ridge model, small regularization")
plt.axvline(x=0, color=".5")
plt.subplots_adjust(left=0.3)

Теперь, когда коэффициенты были масштабированы, мы можем их безопасно сравнивать.
Предупреждение
Почему график выше показывает, что увеличение возраста приводит к снижению заработной платы? Почему первоначальная диаграмма рассеяния пар говорит об обратном?
График выше показывает нам зависимости между конкретным признаком и целевым значением, когда все остальные признаки остаются неизменными, то есть условные зависимости. Увеличение возраста приведёт к снижению заработной платы, когда все остальные признаки останутся неизменными. Напротив, увеличение опыта приведёт к увеличению заработной платы, когда все остальные признаки останутся неизменными. Также AGE, EXPERIENCE и EDUCATION — это три переменные, которые в наибольшей степени влияют на модель.
Интерпретация коэффициентов: осторожность в отношении причинно-следственных связей
Линейные модели — отличный инструмент для измерения статистической связи, но мы должны быть осторожны при выводах о причинно-следственных связях, ведь корреляция не всегда подразумевает причинно-следственную связь. Это особенно сложно в социальных науках, потому что наблюдаемые нами переменные являются лишь заместителями лежащего в основе причинного процесса.
В нашем конкретном случае мы можем рассматривать образование человека как заместитель его профессиональной пригодности, реальной переменной, которая нас интересует, но которую мы не можем наблюдать. Мы, конечно, хотели бы думать, что более длительное обучение в школе повысит техническую компетентность, но также вполне возможно, что причинно-следственная связь действует и в обратную сторону. То есть, те, кто технически компетентен, склонны учиться дольше.
Работодатель вряд ли будет заботиться о том, какой из случаев имеет место (или если это смесь обоих), пока он остаётся убеждённым, что человек с более высоким образованием лучше подходит для работы, и он будет рад заплатить более высокую заработную плату.
Это смешение эффектов становится проблематичным при рассмотрении каких-либо вмешательств, например, государственных субсидий на высшее образование или рекламных материалов, побуждающих людей получить высшее образование. Полезность таких мер может оказаться завышенной, особенно если степень смешения значительная. Наша модель предсказывает увеличение почасовой заработной платы на 0,054699 за каждый год образования. Фактическое причинное воздействие может быть ниже из-за этого смешения.
Проверка изменчивости коэффициентов
Мы можем проверить изменчивость коэффициентов с помощью перекрёстной проверки: это форма возмущения данных (связанная с перевыборкой).
Если коэффициенты значительно изменяются при изменении входных данных, их устойчивость не гарантируется, и их интерпретацию следует проводить с осторожностью.
from sklearn.model_selection import RepeatedKFold, cross_validate
cv = RepeatedKFold(n_splits=5, n_repeats=5, random_state=0)
cv_model = cross_validate(
model,
X,
y,
cv=cv,
return_estimator=True,
n_jobs=2,
)
coefs = pd.DataFrame(
[
est[-1].regressor_.coef_ * est[:-1].transform(X.iloc[train_idx]).std(axis=0)
for est, (train_idx, _) in zip(cv_model["estimator"], cv.split(X, y))
],
columns=feature_names,
)
plt.figure(figsize=(9, 7))
sns.stripplot(data=coefs, orient="h", palette="dark:k", alpha=0.5)
sns.boxplot(data=coefs, orient="h", color="cyan", saturation=0.5, whis=10)
plt.axvline(x=0, color=".5")
plt.xlabel("Coefficient importance")
plt.title("Coefficient importance and its variability")
plt.suptitle("Ridge model, small regularization")
plt.subplots_adjust(left=0.3)

Предобработка числовых переменных
Как было сказано выше (см. «Машинный цикл»), мы также можем выбрать масштабирование числовых значений перед обучением модели. Это может быть полезно, когда мы применяем аналогичное количество регуляризации ко всем из них в методе Ridge. Препроцессор переопределяется для вычитания среднего значения и масштабирования переменных до единичной дисперсии.
from sklearn.preprocessing import StandardScaler
preprocessor = make_column_transformer(
(OneHotEncoder(drop="if_binary"), categorical_columns),
(StandardScaler(), numerical_columns),
)
Модель останется неизменной.
model = make_pipeline(
preprocessor,
TransformedTargetRegressor(
regressor=Ridge(alpha=1e-10), func=np.log10, inverse_func=sp.special.exp10
),
)
model.fit(X_train, y_train)
Линейные модели с регуляризацией
На практике машинного обучения регрессия с гребнем чаще используется с нетривиальной регуляризацией.
Выше мы ограничили эту регуляризацию очень малым значением. Регуляризация улучшает обусловленность задачи и уменьшает дисперсию оценок. RidgeCV применяет перекрестную проверку, чтобы определить, какое значение параметра регуляризации (alpha) лучше всего подходит для прогнозирования.
from sklearn.linear_model import RidgeCV
alphas = np.logspace(-10, 10, 21) # alpha values to be chosen from by cross-validation
model = make_pipeline(
preprocessor,
TransformedTargetRegressor(
regressor=RidgeCV(alphas=alphas),
func=np.log10,
inverse_func=sp.special.exp10,
),
)
model.fit(X_train, y_train)
Линейные модели с разреженными коэффициентами
Другой способ учесть коррелированные переменные в наборе данных — это оценить разреженные коэффициенты. В некотором роде мы уже делали это вручную, когда удаляли столбец AGE в предыдущей оценке с гребнем.
Модели Лассо (см. раздел руководства пользователя Lasso) оценивают разреженные коэффициенты. LassoCV применяет перекрестную проверку, чтобы определить, какое значение параметра регуляризации (alpha) лучше всего подходит для оценки модели.
from sklearn.linear_model import LassoCV
alphas = np.logspace(-10, 10, 21) # alpha values to be chosen from by cross-validation
model = make_pipeline(
preprocessor,
TransformedTargetRegressor(
regressor=LassoCV(alphas=alphas, max_iter=100_000),
func=np.log10,
inverse_func=sp.special.exp10,
),
)
_ = model.fit(X_train, y_train)
Сначала мы проверяем, какое значение \(\alpha\) было выбрано.
model[-1].regressor_.alpha_
np.float64(0.001)
Затем мы проверяем качество прогнозов.
mae_train = median_absolute_error(y_train, model.predict(X_train))
y_pred = model.predict(X_test)
mae_test = median_absolute_error(y_test, y_pred)
scores = {
"MedAE on training set": f"{mae_train:.2f} $/hour",
"MedAE on testing set": f"{mae_test:.2f} $/hour",
}
_, ax = plt.subplots(figsize=(6, 6))
display = PredictionErrorDisplay.from_predictions(
y_test, y_pred, kind="actual_vs_predicted", ax=ax, scatter_kwargs={"alpha": 0.5}
)
ax.set_title("Lasso model, optimum regularization")
for name, score in scores.items():
ax.plot([], [], " ", label=f"{name}: {score}")
ax.legend(loc="upper left")
plt.tight_layout()

Для нашего набора данных модель снова не очень предсказательная.
coefs = pd.DataFrame(
model[-1].regressor_.coef_,
columns=["Coefficients importance"],
index=feature_names,
)
coefs.plot(kind="barh", figsize=(9, 7))
plt.title("Lasso model, optimum regularization, normalized variables")
plt.axvline(x=0, color=".5")
plt.subplots_adjust(left=0.3)

Модель Лассо определяет корреляцию между AGE и EXPERIENCE и подавляет одну из них ради прогноза.
Важно помнить, что коэффициенты, которые были исключены, могут быть связаны с результатом сами по себе: модель выбрала их подавить, потому что они вносят мало или совсем не вносят дополнительной информации по сравнению с другими признаками. Кроме того, такой отбор нестабилен для коррелированных признаков и должен интерпретироваться с осторожностью.
Действительно, мы можем проверить изменчивость коэффициентов по разделам.
cv_model = cross_validate(
model,
X,
y,
cv=cv,
return_estimator=True,
n_jobs=2,
)
coefs = pd.DataFrame(
[est[-1].regressor_.coef_ for est in cv_model["estimator"]], columns=feature_names
)
plt.figure(figsize=(9, 7))
sns.stripplot(data=coefs, orient="h", palette="dark:k", alpha=0.5)
sns.boxplot(data=coefs, orient="h", color="cyan", saturation=0.5, whis=100)
plt.axvline(x=0, color=".5")
plt.title("Coefficient variability")
plt.subplots_adjust(left=0.3)

Мы наблюдаем, что коэффициенты AGE и EXPERIENCE сильно меняются в зависимости от раздела.
Неправильная интерпретация причинно-следственной связи
Создатели политики могут захотеть узнать влияние образования на заработную плату, чтобы оценить, оправдано ли определенное политическое решение, направленное на побуждение людей к получению большего образования. Хотя модели машинного обучения отлично подходят для измерения статистических связей, они, как правило, не могут вывести причинно-следственные эффекты.
Может возникнуть желание посмотреть на коэффициент образования по заработной плате из нашей последней модели (или любой модели) и заключить, что он отражает истинный эффект изменения стандартизированной переменной образования на заработную плату.
К сожалению, вероятно, существуют необнаблюдаемые смешивающие переменные, которые либо увеличивают, либо уменьшают этот коэффициент. Смешивающая переменная — это переменная, которая влияет как на ОБРАЗОВАНИЕ, так и на ЗАРАБОТНУЮ ПЛАТУ. Одним примером такой переменной является способность. Предположительно, более способные люди с большей вероятностью получат образование, и при этом с большей вероятностью получат более высокую почасовую заработную плату на любом уровне образования. В этом случае способность вызывает положительное смещение, вызванное пропущенной переменной (OVB) для коэффициента ОБРАЗОВАНИЯ, тем самым преувеличивая влияние образования на заработную плату.
См. Невозможность машинного обучения вывести причинно-следственные эффекты для моделируемого случая смещения OVB, связанного с способностью.
Уроки, извлеченные из опыта
- Для получения важности признаков коэффициенты необходимо масштабировать до одной и той же единицы измерения. Масштабирование с использованием стандартного отклонения признака является полезным приближением.
- Интерпретация причинно-следственной связи затруднена при наличии смешивающих эффектов. Если взаимосвязь между двумя переменными также зависит от чего-то незаметного, мы должны быть осторожны при выводах о причинно-следственной связи.
- Коэффициенты в многофакторных линейных моделях представляют зависимость между заданным признаком и целевой переменной при условии присутствия других признаков.
- Коррелированные признаки вызывают нестабильность коэффициентов линейных моделей, и их эффекты трудно отделить друг от друга.
- Разные линейные модели по-разному реагируют на корреляцию признаков, и коэффициенты могут существенно отличаться друг от друга.
- Проверка коэффициентов по итерациям цикла перекрестной проверки дает представление об их устойчивости.
- Коэффициенты вряд ли будут иметь какое-либо причинно-следственное значение. Они имеют тенденцию к смещению из-за незамеченных смешивающих факторов.
- Инструменты проверки могут не обязательно предоставлять информацию о реальном процессе генерации данных.
Общее время выполнения скрипта: (0 минут 14.475 секунд)
Связанные примеры
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/inspection/plot_linear_model_coefficient_interpretation.html







