Данная статья является переводом. Оригинал находится здесь.

Этот модуль дает интуитивно понятное введение в очень фундаментальные концепции переобучения и недообучения в машинном обучении. Модели машинного обучения никогда не могут делать идеальные прогнозы: ошибка теста никогда не равна нулю. Этот провал происходит из-за фундаментального компромисса между гибкостью моделирования и ограниченным размером обучающего набора данных .

Это и ежу понятно
Это и ежу понятно
  • Первая презентация определит эти проблемы и охарактеризует, как и почему они возникают.

  • Затем мы представим методологию количественной оценки этих проблем путем сравнения ошибки train с ошибкой test для различного выбора семейства моделей и параметров модели.

  • Что еще более важно, мы подчеркнем влияние размера обучающей выборки на этот компромисс .

  • Наконец, мы свяжем переобучение и недообучение с понятиями статистической дисперсии и систематической ошибки.

Итак, приступим.

Для удобства, скачайте готовый ноутбук здесь.

Датасет для примеров, раскрытых в ноутбуке находится здесь.

Overfitting and underfitting

Cross-validation framework

Структура перекрестной проверки

В предыдущих записных книжках мы вводим некоторые понятия, касающиеся оценки прогностических моделей. Хотя этот раздел может быть немного избыточным, мы намерены подробно остановиться на структуре перекрестной проверки.

Прежде чем мы углубимся в это, давайте остановимся на причинах всегда иметь наборы для обучения и тестирования. Давайте сначала рассмотрим ограничение использования набора данных без исключения каких-либо образцов.

Чтобы проиллюстрировать различные концепции, мы будем использовать набор данных о жилье в Калифорнии.

В этом наборе данных цель состоит в том, чтобы предсказать медианную стоимость домов в районе Калифорнии. Собранные функции основаны на общей информации о недвижимости и географических данных.

Поэтому задача для решения отличается от той, что показана в предыдущей тетради. Предсказываемая цель является непрерывной переменной, а не дискретной. Эта задача называется регрессией.

Для этого мы будем использовать прогностическую модель, специфичную для регрессии, а не для классификации.

print(housing.DESCR)
.. _california_housing_dataset:

California Housing dataset
--------------------------

**Data Set Characteristics:**

    :Number of Instances: 20640

    :Number of Attributes: 8 numeric, predictive attributes and the target

    :Attribute Information:
        - MedInc        median income in block
        - HouseAge      median house age in block
        - AveRooms      average number of rooms
        - AveBedrms     average number of bedrooms
        - Population    block population
        - AveOccup      average house occupancy
        - Latitude      house block latitude
        - Longitude     house block longitude

    :Missing Attribute Values: None

This dataset was obtained from the StatLib repository.
http://lib.stat.cmu.edu/datasets/

The target variable is the median house value for California districts.

This dataset was derived from the 1990 U.S. census, using one row per census
block group. A block group is the smallest geographical unit for which the U.S.
Census Bureau publishes sample data (a block group typically has a population
of 600 to 3,000 people).

It can be downloaded/loaded using the
:func:`sklearn.datasets.fetch_california_housing` function.

.. topic:: References

    - Pace, R. Kelley and Ronald Barry, Sparse Spatial Autoregressions,
      Statistics and Probability Letters, 33 (1997) 291-297

Ошибка обучения и ошибка тестирования

Чтобы решить эту задачу регрессии, мы будем использовать регрессор дерева решений.

from sklearn.tree import DecisionTreeRegressor

regressor = DecisionTreeRegressor(random_state=0)
regressor.fit(data, target)
DecisionTreeRegressor(random_state=0)
from sklearn import set_config
set_config(display='diagram')
regressor
DecisionTreeRegressor
DecisionTreeRegressor(random_state=0)

После обучения регрессора мы хотели бы узнать его потенциальную производительность обобщения после развертывания в рабочей среде. Для этой цели мы используем среднюю абсолютную ошибку, которая дает нам ошибку в исходной единице, т.е. k$.

from sklearn.metrics import mean_absolute_error

target_predicted = regressor.predict(data)
score = mean_absolute_error(target, target_predicted)
print(f"On average, our regressor makes an error of {score:.2f} k$")
On average, our regressor makes an error of 0.00 k$

Мы получаем идеальный прогноз без ошибок. Это слишком оптимистично и почти всегда выявляет методологическую проблему при машинном обучении.

Действительно, мы тренировались и прогнозировали на одном и том же наборе данных. Поскольку наше дерево решений полностью выросло, каждая выборка в наборе данных хранится в конечном узле. Таким образом, наше дерево решений полностью запоминало набор данных, предоставленный во время, fit и поэтому не допускало ошибок при прогнозировании.

Эта рассчитанная выше ошибка называется эмпирической ошибкой или ошибкой обучения .

Мы обучили прогностическую модель, чтобы свести к минимуму ошибку обучения, но наша цель — свести к минимуму ошибку данных, которые не были замечены во время обучения.

Эту ошибку также называют ошибкой обобщения или «истинной» ошибкой тестирования .

Таким образом, самая основная оценка включает в себя:

разделение нашего набора данных на два подмножества: обучающий набор и набор для тестирования;

примерка модели на обучающем наборе;

оценку ошибки обучения на обучающей выборке;

оценка ошибки тестирования на тестовом множестве.

Итак, давайте разделим наш набор данных.

from sklearn.model_selection import train_test_split

data_train, data_test, target_train, target_test = train_test_split(
    data, target, random_state=0)

Затем давайте обучим нашу модель.

regressor.fit(data_train, target_train)

Наконец, мы оцениваем различные типы ошибок. Начнем с вычисления ошибки обучения.

target_predicted = regressor.predict(data_train)
score = mean_absolute_error(target_train, target_predicted)
print(f"The training error of our model is {score:.2f} k$")

Мы наблюдаем те же явления, что и в предыдущем эксперименте: наша модель запомнила обучающую выборку. Однако теперь мы вычисляем ошибку тестирования.

target_predicted = regressor.predict(data_test)
score = mean_absolute_error(target_test, target_predicted)
print(f"The testing error of our model is {score:.2f} k$")
The testing error of our model is 47.28 k$

Эта ошибка тестирования на самом деле связана с тем, что мы ожидали бы от нашей модели, если бы она использовалась в производственной среде.

Стабильность оценок перекрестной проверки

При выполнении одного разделения поезд-тест мы не даем никаких указаний относительно надежности оценки нашей прогностической модели: в частности, если набор тестов мал, эта оценка ошибки тестирования будет нестабильной и не будет отражать «истинная частота ошибок», которую мы наблюдали бы с той же моделью на неограниченном количестве тестовых данных.

Например, нам могло повезти, когда мы сделали случайное разделение нашего ограниченного набора данных и случайно выделили некоторые из самых простых для прогнозирования случаев в тестовом наборе: в этом случае оценка ошибки тестирования была бы чрезмерно оптимистичной.

Перекрестная проверка позволяет оценить надежность прогностической модели путем повторения процедуры разделения. Это даст несколько ошибок обучения и тестирования и, таким образом, некоторую оценку изменчивости производительности обобщения модели .

Существуют разные стратегии перекрестной проверки , сейчас мы сосредоточимся на одной, называемой «перетасовка-разделение». На каждой итерации этой стратегии мы:

случайно перетасовать порядок образцов копии полного набора данных;

разделить перетасованный набор данных на поезд и тестовый набор;

обучить новую модель на поезде;

оценить ошибку тестирования на тестовом наборе.

Повторяем эту процедуру n_splitsраз. Имейте в виду, что вычислительная стоимость увеличивается с n_splits.

На этом рисунке показан частный случай стратегии перекрестной проверки в случайном порядкеn_splits=5 с использованием . Для каждого разделения перекрестной проверки процедура обучает модель на всех красных образцах и оценивает оценку модели на синих образцах.

В этом случае мы установим n_splits=40, что означает, что всего мы обучим 40 моделей, и все они будут отброшены: мы просто записываем их эффективность обобщения на каждом варианте тестового набора.

Чтобы оценить производительность обобщения нашего регрессора, мы можем использовать sklearn.model_selection.cross_validate с sklearn.model_selection.ShuffleSplit объектом:

from sklearn.model_selection import cross_validate
from sklearn.model_selection import ShuffleSplit

cv = ShuffleSplit(n_splits=40, test_size=0.3, random_state=0)
cv_results = cross_validate(
    regressor, data, target, cv=cv, scoring="neg_mean_absolute_error")

Результаты cv_results сохраняются в словаре Python. Мы преобразуем его в фрейм данных pandas, чтобы упростить визуализацию и манипулирование.

import pandas as pd

cv_results = pd.DataFrame(cv_results)
cv_results.head(10)
fit_time	score_time	test_score
0	0.112997	0.000000	-46.909797
1	0.110834	0.000000	-46.421170
2	0.112016	0.000000	-47.411089
3	0.111001	0.002102	-44.319824
4	0.107722	0.001999	-47.607875
5	0.108330	0.001993	-45.901300
6	0.108706	0.001966	-46.572767
7	0.104813	0.005600	-46.194585
8	0.106206	0.003693	-45.590236
9	0.109070	0.002961	-45.727998

Оценка — это показатель, для которого более высокие значения означают лучшие результаты. Наоборот, ошибка — это показатель, для которого более низкие значения означают лучшие результаты.

Параметр всегда scoring ожидает cross_validate функцию, которая является оценкой.

Для простоты все метрики ошибок в scikit-learn, такие как mean_absolute_error, можно преобразовать в оценку, которая будет использоваться в cross_validate.

Для этого вам нужно передать строку метрики ошибок с дополнительной neg_строкой впереди параметру scoring; например scoring="neg_mean_absolute_error".

В этом случае будет вычислено отрицательное значение средней абсолютной ошибки, что будет эквивалентно баллу.

Давайте вернем отрицание, чтобы получить реальную ошибку:

cv_results["test_error"] = -cv_results["test_score"]

Давайте проверим результаты перекрестной проверки.

cv_results.head(10)
fit_time	score_time	test_score	test_error
0	0.112997	0.000000	-46.909797	46.909797
1	0.110834	0.000000	-46.421170	46.421170
2	0.112016	0.000000	-47.411089	47.411089
3	0.111001	0.002102	-44.319824	44.319824
4	0.107722	0.001999	-47.607875	47.607875
5	0.108330	0.001993	-45.901300	45.901300
6	0.108706	0.001966	-46.572767	46.572767
7	0.104813	0.005600	-46.194585	46.194585
8	0.106206	0.003693	-45.590236	45.590236
9	0.109070	0.002961	-45.727998	45.727998

Мы получаем информацию о времени для подгонки и прогнозирования на каждой итерации перекрестной проверки. Также мы получаем тестовый балл, который соответствует ошибке тестирования на каждом из сплитов.

len(cv_results)

Мы получаем 40 записей в результирующем фрейме данных, потому что мы выполнили 40 разбиений. Следовательно, мы можем показать распределение ошибок тестирования и, таким образом, оценить его изменчивость.

import matplotlib.pyplot as plt

cv_results["test_error"].plot.hist(bins=10, edgecolor="black", figsize =(10, 7))
plt.xlabel("Mean absolute error (k$)")
_ = plt.title("Test error distribution")

Мы видим, что ошибка тестирования сгруппирована вокруг 47 тысяч долларов и колеблется от 43 тысяч долларов до 50 тысяч долларов.

print(f"The mean cross-validated testing error is: "
      f"{cv_results['test_error'].mean():.2f} k$")
he mean cross-validated testing error is: 46.36 k$

Обратите внимание, что стандартное отклонение намного меньше среднего: мы могли бы резюмировать, что наша перекрестная оценка ошибки тестирования составляет 46,36 ± 1,17 тыс. $.

Если бы мы обучили одну модель на полном наборе данных (без перекрестной проверки), а затем получили доступ к неограниченному количеству тестовых данных, мы бы ожидали, что ее истинная ошибка тестирования будет близка к этой области.

Хотя эта информация интересна сама по себе, ее следует сопоставить с масштабом естественной изменчивости вектора targetв нашем наборе данных.

Построим распределение целевой переменной:

target.plot.hist(bins=20, edgecolor="black", figsize =(10, 7))
plt.xlabel("Median House Value (k$)")
_ = plt.title("Target distribution")
print(f"The standard deviation of the target is: {target.std():.2f} k$")
The standard deviation of the target is: 115.40 k$

Целевая переменная колеблется от почти 0 тысяч долларов до 500 тысяч долларов со стандартным отклонением около 115 тысяч долларов.

Мы замечаем, что средняя оценка ошибки тестирования, полученная перекрестной проверкой, немного меньше естественного масштаба вариации целевой переменной. Кроме того, стандартное отклонение оценки перекрестной проверки ошибки тестирования еще меньше.

Это хорошее начало, но его недостаточно, чтобы решить, достаточно ли хороша производительность обобщения, чтобы сделать наш прогноз полезным на практике.

Напомним, что наша модель в среднем дает ошибку около 47 тыс. долл. США. Имея эту информацию и глядя на целевое распределение, такая ошибка может быть приемлемой при прогнозировании домов с 500 тысячами долларов. Однако это было бы проблемой с домом стоимостью 50 тысяч долларов. Таким образом, это указывает на то, что наша метрика (средняя абсолютная ошибка) не идеальна.

Вместо этого мы могли бы выбрать показатель относительно целевого значения для прогнозирования: гораздо лучшим выбором была бы средняя абсолютная процентная ошибка.

Но во всех случаях ошибка в 47 тысяч долларов может оказаться слишком большой для автоматического использования нашей модели для маркировки стоимости домов без экспертного контроля.

Подробнее о cross_validate

Во время перекрестной проверки многие модели обучаются и оцениваются. Действительно, количество элементов в каждом массиве вывода cross_validateявляется результатом одной из этих fit/ scoreпроцедур. Чтобы сделать это явным, можно получить эти подогнанные модели для каждого из расщеплений/складок, передав параметр return_estimator=Trueв cross_validate.

cv_results = cross_validate(regressor, data, target, return_estimator=True)
cv_results
{'fit_time': array([0.13367248, 0.13264561, 0.12363744, 0.12354398, 0.1199131 ]),
 'score_time': array([0.00199413, 0.00199533, 0.00199533, 0.00199485, 0.00199509]),
 'estimator': [DecisionTreeRegressor(random_state=0),
  DecisionTreeRegressor(random_state=0),
  DecisionTreeRegressor(random_state=0),
  DecisionTreeRegressor(random_state=0),
  DecisionTreeRegressor(random_state=0)],
 'test_score': array([0.26291527, 0.41947109, 0.44492564, 0.23357874, 0.40788361])}
cv_results["estimator"]
[DecisionTreeRegressor(random_state=0),
 DecisionTreeRegressor(random_state=0),
 DecisionTreeRegressor(random_state=0),
 DecisionTreeRegressor(random_state=0),
 DecisionTreeRegressor(random_state=0)]

Пять регрессоров деревьев решений соответствуют пяти подобранным деревьям решений на разных складках. Доступ к этим регрессорам удобен,

потому что он позволяет проверить внутренние подогнанные параметры этих регрессоров.

В случае, когда вас интересует только результат теста, scikit-learn предоставляет cross_val_scoreфункцию.

Это идентично вызову cross_validateфункции и выбору test_scoreединственного (как мы часто делали в предыдущих блокнотах).

from sklearn.model_selection import cross_val_score

scores = cross_val_score(regressor, data, target)
scores
array([0.26291527, 0.41947109, 0.44492564, 0.23357874, 0.40788361])

Резюме

В этом блокноте мы увидели:

необходимость разделения данных на набор train и test;

значение ошибок обучения и тестирования;

общая структура перекрестной проверки с возможностью изучения изменений производительности обобщения.

Переобучение против недообучения

Чтобы лучше понять эффективность обобщения нашей модели и, возможно, найти способы ее улучшения, мы сравним ошибку тестирования с ошибкой обучения. Таким образом, нам нужно вычислить ошибку на обучающей выборке, что возможно с помощью cross_validate функции.

import pandas as pd
from sklearn.model_selection import cross_validate, ShuffleSplit

cv = ShuffleSplit(n_splits=30, test_size=0.2)
cv_results = cross_validate(regressor, data, target,
                            cv=cv, scoring="neg_mean_absolute_error",
                            return_train_score=True, n_jobs=2)
cv_results = pd.DataFrame(cv_results)

В перекрестной проверке использовалась отрицательная средняя абсолютная ошибка. Преобразуем отрицательную среднюю абсолютную ошибку в положительную среднюю абсолютную ошибку.

scores = pd.DataFrame()
scores[["train error", "test error"]] = -cv_results[
    ["train_score", "test_score"]]
import matplotlib.pyplot as plt

scores.plot.hist(bins=50, edgecolor="black", figsize =(10, 7))
plt.xlabel("Mean absolute error (k$)")
_ = plt.title("Train and test errors distribution via cross-validation")

Построив график распределения ошибок обучения и тестирования, мы получаем информацию о том, является ли наша модель подгонкой, подгонкой (или и тем, и другим одновременно).

Здесь мы наблюдаем небольшую ошибку обучения (на самом деле нулевую), что означает, что модель не является недостаточно подходящей : она достаточно гибкая, чтобы фиксировать любые изменения, присутствующие в обучающем наборе.

Однако значительно большая ошибка тестирования говорит нам о том, что модель переобучается : модель запомнила множество вариантов обучающего набора, которые можно было бы считать «зашумленными», поскольку они не обобщаются, чтобы помочь нам сделать хороший прогноз на тестовом наборе.

Кривая проверки

Некоторые гиперпараметры модели обычно являются ключом к переходу от модели, которая не подходит, к модели, которая подходит лучше, мы надеемся, пройдя через область, где мы сможем получить хороший баланс между ними. Мы можем получить знания, построив кривую, называемую кривой проверки. Эта кривая также может быть применена к приведенному выше эксперименту и меняет значение гиперпараметра.

Для дерева решений max_depthпараметр используется для управления компромиссом между подгонкой и переподгонкой.

%%time
from sklearn.model_selection import validation_curve

max_depth = [1, 5, 10, 15, 20, 25]
train_scores, test_scores = validation_curve(
    regressor, data, target, param_name="max_depth", param_range=max_depth,
    cv=cv, scoring="neg_mean_absolute_error", n_jobs=2)
train_errors, test_errors = -train_scores, -test_scores
Wall time: 7.87 s

Теперь, когда мы собрали результаты, мы покажем кривую проверки, нанеся на график ошибки обучения и тестирования (а также их отклонения).

plt.plot(max_depth, train_errors.mean(axis=1), label="Training error")
plt.plot(max_depth, test_errors.mean(axis=1), label="Testing error")
plt.legend()

plt.xlabel("Maximum depth of decision tree")
plt.ylabel("Mean absolute error (k$)")
_ = plt.title("Validation curve for decision tree")

Кривую валидации можно разделить на три области:

Для дерево решений не подходит. Ошибка обучения и, следовательно, ошибка тестирования высоки. Модель слишком ограничена и не может отразить большую часть изменчивости целевой переменной.max_depth < 10

Область вокруг соответствует параметру, для которого дерево решений обобщает лучше всего. Он достаточно гибок, чтобы захватить часть изменчивости цели, которая обобщает, не запоминая при этом весь шум в цели.max_depth = 10

Для дерево решений переобучается. Ошибка обучения становится очень малой, а ошибка тестирования увеличивается. В этой области модели создают решения специально для зашумленных выборок, что наносит ущерб его способности обобщать тестовые данные.max_depth > 10

Обратите внимание, что для модель немного переобучается, так как существует разрыв между ошибкой обучения и ошибкой тестирования. В то же время он также потенциально может немного недооценивать, потому что ошибка обучения все еще далека от нуля (более 30 тысяч долларов), а это означает, что модель все еще может быть слишком ограничена для моделирования интересных частей данных. Однако погрешность тестирования минимальна, а это главное. Это лучший компромисс, которого мы могли бы достичь, просто настроив этот параметр.max_depth = 10

Имейте в виду, что просмотр средних ошибок весьма ограничен. Мы также должны посмотреть на стандартное отклонение, чтобы оценить дисперсию оценки. Мы можем повторить тот же график, что и раньше, но на этот раз мы добавим некоторую информацию, чтобы показать стандартное отклонение ошибок.

plt.errorbar(max_depth, train_errors.mean(axis=1),
             yerr=train_errors.std(axis=1), label='Training error')
plt.errorbar(max_depth, test_errors.mean(axis=1),
             yerr=test_errors.std(axis=1), label='Testing error')
plt.legend()

plt.xlabel("Maximum depth of decision tree")
plt.ylabel("Mean absolute error (k$)")
_ = plt.title("Validation curve for decision tree")

Нам повезло, что дисперсия ошибок была мала по сравнению с их соответствующими значениями, и поэтому сделанные выше выводы вполне ясны. Это не всегда так.

Резюме: В этом блокноте мы увидели:

как определить, является ли модель обобщающей, переоснащенной или неподходящей;

как проверить влияние гиперпараметра на компромисс между недообучением/переоснащением.

Влияние размера выборки на перекрестную проверку

from sklearn.tree import DecisionTreeRegressor

regressor = DecisionTreeRegressor()

Кривая обучения

Чтобы понять влияние количества выборок, доступных для обучения, на эффективность обобщения прогностической модели, можно синтетически уменьшить количество выборок, используемых для обучения прогностической модели, и проверить ошибки обучения и тестирования.

Поэтому мы можем варьировать количество образцов в обучающей выборке и повторять эксперимент. Оценки обучения и тестирования можно построить аналогично кривой проверки, но вместо изменения гиперпараметра мы изменяем количество обучающих выборок. Эта кривая называется кривой обучения .

Он дает информацию о пользе добавления новых обучающих выборок для улучшения производительности обобщения модели.

Давайте вычислим кривую обучения для дерева решений и изменим долю обучающего набора от 10% до 100%.

import numpy as np
train_sizes = np.linspace(0.1, 1.0, num=5, endpoint=True)
train_sizes
array([0.1  , 0.325, 0.55 , 0.775, 1.   ])

Мы будем использовать ShuffleSplitперекрестную проверку для оценки нашей прогностической модели.

from sklearn.model_selection import ShuffleSplit

cv = ShuffleSplit(n_splits=30, test_size=0.2)

Теперь все готово для проведения эксперимента.

from sklearn.model_selection import learning_curve

results = learning_curve( regressor, data, target, train_sizes=train_sizes, cv=cv, scoring="neg_mean_absolute_error", n_jobs=2) train_size, train_scores, test_scores = results[:3]

Convert the scores into errors

train_errors, test_errors = -train_scores, -test_scores

Теперь мы можем построить кривую.

import matplotlib.pyplot as plt

plt.errorbar(train_size, train_errors.mean(axis=1),
             yerr=train_errors.std(axis=1), label="Training error")
plt.errorbar(train_size, test_errors.mean(axis=1),
             yerr=test_errors.std(axis=1), label="Testing error")
plt.legend()

plt.xscale("log")
plt.xlabel("Number of samples in the training set")
plt.ylabel("Mean absolute error (k$)")
_ = plt.title("Learning curve for decision tree")

Резюме В тетради мы узнали:

влияние количества выборок в наборе данных, особенно на изменчивость ошибок, сообщаемых при выполнении перекрестной проверки;

о кривой обучения, которая представляет собой визуальное представление способности модели улучшаться за счет добавления новых образцов.

Главный вывод

Подведение итогов Переобучение вызвано ограниченным размером обучающей выборки , шумом в данных и высокой гибкостью распространенных моделей машинного обучения.

Недообучение происходит, когда изученные функции прогнозирования страдают от систематических ошибок . Это может быть вызвано выбором семейства моделей и параметров, что приводит к недостаточной гибкости для захвата повторяемой структуры реального процесса генерации данных.

Для фиксированного обучающего набора цель состоит в том, чтобы свести к минимуму ошибку теста путем настройки семейства моделей и его параметров, чтобы найти наилучший компромисс между переоснащением и недообучением .

При данном выборе семейства моделей и параметров увеличение размера обучающей выборки уменьшит переоснащение, но также может привести к увеличению недообучения.

Ошибка теста модели, которая не является ни переоснащением, ни недообучением, все еще может быть высокой, если вариации целевой переменной не могут быть полностью определены входными признаками. Эта неустранимая ошибка вызвана тем, что мы иногда называем шумом этикетки. На практике это часто происходит, когда мы не имеем доступа к важным функциям по той или иной причине.

Чтобы идти дальше Можно дать точную математическую обработку систематической ошибки и дисперсии регрессионной модели. В статье Википедии о компромиссе смещения и дисперсии объясняется, как квадрат ошибки теста можно разложить на сумму квадрата смещения, дисперсии и неустранимой ошибки для данной ошибки регрессии.

В следующих главах, посвященных линейным моделям, деревьям решений и ансамблям, будут приведены конкретные примеры того, как диагностировать переоснащение и недообучение и как бороться с ним.

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


  1. lonelymyp
    28.05.2023 18:19
    +15

    Лайк, подписка, колокольчик, не переключайтесь, скоро будет что-то интересное (нет)!

    Никто не любит бессмысленные тизеры, с нулём полезной информации, пожалуйста, не надо так делать.


    1. Demir_Uzun Автор
      28.05.2023 18:19
      -5

      Вас понял, исправляюсь


  1. smind
    28.05.2023 18:19
    +4

    зашёл посмотреть за что столько дисов, после второго и последнего абзаца понял за что.


  1. lgorSL
    28.05.2023 18:19
    +2

    Это перевод, и должна быть ссылка на оригинал:
    https://inria.github.io/scikit-learn-mooc/python_scripts/cross_validation_train_test.html

    А ещё оригинал опубликован под лицензией и её неплохо бы соблюдать:

    By scikit-learn developers

    Brought to you under a CC-BY License by Inria Learning Lab, scikit-learn @ La Fondation Inria, Inria Academy, with many thanks to the scikit-learn community as a whole!


    1. Demir_Uzun Автор
      28.05.2023 18:19

      Исправил


  1. sunnybear
    28.05.2023 18:19
    +3

    Хочу себе поезд-тест, где можно купить?


    1. avitek
      28.05.2023 18:19

      Не покупать, его нужно скачивать вместе с ноутбуком.
      Пардон, с "готовым ноутбуком"!