Поиск по сайту:

Как использовать XGBoost для прогнозирования временных рядов


XGBoost — это эффективная реализация повышения градиента для задач классификации и регрессии.

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

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

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

После завершения этого урока вы будете знать:

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

Начните свой проект с помощью моей новой книги XGBoost With Python, включая пошаговые руководства и файлы исходного кода Python для всех примеров. .

Давайте начнем.

  • Обновление, август 2020 г.: исправлена ошибка в расчете MAE, обновлена конфигурация модели для более точных прогнозов (спасибо Кауставу!)

Обзор руководства

Этот урок разделен на три части; они есть:

  1. XGBoost ансамбль
  2. Подготовка данных временных рядов
  3. XGBoost для прогнозирования временных рядов

XGBoost ансамбль

XGBoost является сокращением от Extreme Gradient Boosting и представляет собой эффективную реализацию алгоритма машинного обучения стохастического повышения градиента.

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

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

— XGBoost: масштабируемая система повышения качества деревьев, 2016 г.

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

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

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

— XGBoost: масштабируемая система повышения качества деревьев, 2016 г.

XGBoost предназначен для классификации и регрессии наборов табличных данных, хотя его можно использовать для прогнозирования временных рядов.

Дополнительную информацию о повышении градиента и реализации XGBoost см. в руководстве:

  • Нежное введение в алгоритм повышения градиента для машинного обучения

Сначала необходимо установить библиотеку XGBoost.

Вы можете установить его с помощью pip следующим образом:

sudo pip install xgboost

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

# xgboost
import xgboost
print("xgboost", xgboost.__version__)

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

xgboost 1.0.1

Хотя библиотека XGBoost имеет собственный API Python, мы можем использовать модели XGBoost с API scikit-learn через класс-оболочку XGBRegressor.

Экземпляр модели можно создать и использовать так же, как и любой другой класс scikit-learn для оценки модели. Например:

...
# define model
model = XGBRegressor()

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

Подготовка данных временных рядов

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

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

Давайте конкретизируем это на примере. Представьте, что у нас есть следующий временной ряд:

time, measure
1, 100
2, 110
3, 108
4, 115
5, 120

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

Реорганизовав набор данных временных рядов таким образом, данные будут выглядеть следующим образом:

X, y
?, 100
100, 110
110, 108
108, 115
115, 120
120, ?

Обратите внимание, что столбец времени удален, а некоторые строки данных, например первая и последняя, непригодны для обучения модели.

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

Дополнительную информацию о подходе скользящего окна для подготовки данных прогнозирования временных рядов см. в руководстве:

  • Прогнозирование временных рядов как контролируемое обучение

Мы можем использовать функциюshift() в Pandas для автоматического создания новых постановок задач временных рядов с учетом желаемой длины входных и выходных последовательностей.

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

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

# transform a time series dataset into a supervised learning dataset
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
	n_vars = 1 if type(data) is list else data.shape[1]
	df = DataFrame(data)
	cols = list()
	# input sequence (t-n, ... t-1)
	for i in range(n_in, 0, -1):
		cols.append(df.shift(i))
	# forecast sequence (t, t+1, ... t+n)
	for i in range(0, n_out):
		cols.append(df.shift(-i))
	# put it all together
	agg = concat(cols, axis=1)
	# drop rows with NaN values
	if dropnan:
		agg.dropna(inplace=True)
	return agg.values

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

Подробнее о пошаговой разработке этой функции смотрите в туториале:

  • Как преобразовать временной ряд в задачу контролируемого обучения в Python

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

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

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

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

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

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

Дополнительную информацию о поэтапной проверке см. в руководстве:

  • Как протестировать модели машинного обучения для прогнозирования временных рядов

Функция ниже выполняет предварительную проверку.

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

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

# walk-forward validation for univariate data
def walk_forward_validation(data, n_test):
	predictions = list()
	# split dataset
	train, test = train_test_split(data, n_test)
	# seed history with training dataset
	history = [x for x in train]
	# step over each time-step in the test set
	for i in range(len(test)):
		# split test row into input and output columns
		testX, testy = test[i, :-1], test[i, -1]
		# fit model on history and make a prediction
		yhat = xgboost_forecast(history, testX)
		# store forecast in list of predictions
		predictions.append(yhat)
		# add actual observation to history for the next loop
		history.append(test[i])
		# summarize progress
		print('>expected=%.1f, predicted=%.1f' % (testy, yhat))
	# estimate prediction error
	error = mean_absolute_error(test[:, -1], predictions)
	return error, test[:, 1], predictions

Функция train_test_split() вызывается для разделения набора данных на обучающий и тестовый наборы.

Мы можем определить эту функцию ниже.

# split a univariate dataset into train/test sets
def train_test_split(data, n_test):
	return data[:-n_test, :], data[-n_test:, :]

Мы можем использовать класс XGBRegressor для создания одношагового прогноза.

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

# fit an xgboost model and make a one step prediction
def xgboost_forecast(train, testX):
	# transform list into array
	train = asarray(train)
	# split into input and output columns
	trainX, trainy = train[:, :-1], train[:, -1]
	# fit model
	model = XGBRegressor(objective='reg:squarederror', n_estimators=1000)
	model.fit(trainX, trainy)
	# make a one-step prediction
	yhat = model.predict([testX])
	return yhat[0]

Теперь, когда мы знаем, как подготовить данные временных рядов для прогнозирования и оценить модель XGBoost, мы можем рассмотреть использование XGBoost в реальном наборе данных.

XGBoost для прогнозирования временных рядов

В этом разделе мы рассмотрим, как использовать XGBoost для прогнозирования временных рядов.

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

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

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

Вы можете скачать набор данных отсюда и поместить его в текущий рабочий каталог с именем файла «daily-total-female-births.csv».

  • Набор данных (ежедневно-всего-женщин-рождений.csv)
  • Описание (всего-женщин-рождений.имена)

Первые несколько строк набора данных выглядят следующим образом:

"Date","Births"
"1959-01-01",35
"1959-01-02",32
"1959-01-03",30
"1959-01-04",31
"1959-01-05",44
...

Сначала давайте загрузим и построим набор данных.

Полный пример приведен ниже.

# load and plot the time series dataset
from pandas import read_csv
from matplotlib import pyplot
# load dataset
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
values = series.values
# plot dataset
pyplot.plot(values)
pyplot.show()

При выполнении примера создается линейный график набора данных.

Мы видим, что нет явной тенденции или сезонности.

Модель устойчивости может достичь MAE около 6,7 рождений при прогнозировании последних 12 дней. Это обеспечивает базовый уровень производительности, выше которого модель можно считать квалифицированной.

Далее мы можем оценить модель XGBoost на наборе данных при составлении одношаговых прогнозов для данных за последние 12 дней.

Мы будем использовать только предыдущие 6 временных шагов в качестве входных данных для модели и гиперпараметров модели по умолчанию, за исключением того, что мы изменим потерю на «reg:squarederror» (чтобы избежать предупреждающего сообщения) и будем использовать 1000 деревьев. в ансамбле (во избежание недообучения).

Полный пример приведен ниже.

# forecast monthly births with xgboost
from numpy import asarray
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from sklearn.metrics import mean_absolute_error
from xgboost import XGBRegressor
from matplotlib import pyplot

# transform a time series dataset into a supervised learning dataset
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
	n_vars = 1 if type(data) is list else data.shape[1]
	df = DataFrame(data)
	cols = list()
	# input sequence (t-n, ... t-1)
	for i in range(n_in, 0, -1):
		cols.append(df.shift(i))
	# forecast sequence (t, t+1, ... t+n)
	for i in range(0, n_out):
		cols.append(df.shift(-i))
	# put it all together
	agg = concat(cols, axis=1)
	# drop rows with NaN values
	if dropnan:
		agg.dropna(inplace=True)
	return agg.values

# split a univariate dataset into train/test sets
def train_test_split(data, n_test):
	return data[:-n_test, :], data[-n_test:, :]

# fit an xgboost model and make a one step prediction
def xgboost_forecast(train, testX):
	# transform list into array
	train = asarray(train)
	# split into input and output columns
	trainX, trainy = train[:, :-1], train[:, -1]
	# fit model
	model = XGBRegressor(objective='reg:squarederror', n_estimators=1000)
	model.fit(trainX, trainy)
	# make a one-step prediction
	yhat = model.predict(asarray([testX]))
	return yhat[0]

# walk-forward validation for univariate data
def walk_forward_validation(data, n_test):
	predictions = list()
	# split dataset
	train, test = train_test_split(data, n_test)
	# seed history with training dataset
	history = [x for x in train]
	# step over each time-step in the test set
	for i in range(len(test)):
		# split test row into input and output columns
		testX, testy = test[i, :-1], test[i, -1]
		# fit model on history and make a prediction
		yhat = xgboost_forecast(history, testX)
		# store forecast in list of predictions
		predictions.append(yhat)
		# add actual observation to history for the next loop
		history.append(test[i])
		# summarize progress
		print('>expected=%.1f, predicted=%.1f' % (testy, yhat))
	# estimate prediction error
	error = mean_absolute_error(test[:, -1], predictions)
	return error, test[:, -1], predictions

# load the dataset
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
values = series.values
# transform the time series data into supervised learning
data = series_to_supervised(values, n_in=6)
# evaluate
mae, y, yhat = walk_forward_validation(data, 12)
print('MAE: %.3f' % mae)
# plot expected vs preducted
pyplot.plot(y, label='Expected')
pyplot.plot(yhat, label='Predicted')
pyplot.legend()
pyplot.show()

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

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

Мы видим, что модель работает лучше, чем модель персистентности, достигая MAE около 5,9 рождений по сравнению с 6,7 рождений.

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

>expected=42.0, predicted=44.5
>expected=53.0, predicted=42.5
>expected=39.0, predicted=40.3
>expected=40.0, predicted=32.5
>expected=38.0, predicted=41.1
>expected=44.0, predicted=45.3
>expected=34.0, predicted=40.2
>expected=37.0, predicted=35.0
>expected=52.0, predicted=32.5
>expected=48.0, predicted=41.4
>expected=55.0, predicted=46.6
>expected=50.0, predicted=47.2
MAE: 5.957

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

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

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

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

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

# finalize model and make a prediction for monthly births with xgboost
from numpy import asarray
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from xgboost import XGBRegressor

# transform a time series dataset into a supervised learning dataset
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
	n_vars = 1 if type(data) is list else data.shape[1]
	df = DataFrame(data)
	cols = list()
	# input sequence (t-n, ... t-1)
	for i in range(n_in, 0, -1):
		cols.append(df.shift(i))
	# forecast sequence (t, t+1, ... t+n)
	for i in range(0, n_out):
		cols.append(df.shift(-i))
	# put it all together
	agg = concat(cols, axis=1)
	# drop rows with NaN values
	if dropnan:
		agg.dropna(inplace=True)
	return agg.values

# load the dataset
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
values = series.values
# transform the time series data into supervised learning
train = series_to_supervised(values, n_in=6)
# split into input and output columns
trainX, trainy = train[:, :-1], train[:, -1]
# fit model
model = XGBRegressor(objective='reg:squarederror', n_estimators=1000)
model.fit(trainX, trainy)
# construct an input for a new preduction
row = values[-6:].flatten()
# make a one-step prediction
yhat = model.predict(asarray([row]))
print('Input: %s, Predicted: %.3f' % (row, yhat[0]))

Выполнение примера соответствует модели XGBoost для всех доступных данных.

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

Input: [34 37 52 48 55 50], Predicted: 42.708

Дальнейшее чтение

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

Похожие руководства

  • Нежное введение в алгоритм повышения градиента для машинного обучения
  • Прогнозирование временных рядов как контролируемое обучение
  • Как преобразовать временной ряд в задачу контролируемого обучения в Python
  • Как протестировать модели машинного обучения для прогнозирования временных рядов

Краткое содержание

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

В частности, вы узнали:

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

У вас есть вопросы?
Задавайте свои вопросы в комментариях ниже, и я постараюсь ответить.