Как правила соседства могут повредить вашим прогнозам.

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

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

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
%matplotlib inline
#make fake data with a time trend
X = np.random.rand(1000,10)
#add time feature simulating years 2000-2010
time = np.random.randint(2000,2011,size=1000)
#add time to X
X = np.hstack((X,time.reshape(-1,1)))
#create target via a linear relationship to X
weights = np.random.rand(11)
y = X.dot(weights)
#create test data that includes years
#not in training data 2000 - 2019
X_test = np.random.rand(1000,10)
time_test = np.random.randint(2000,2020,size=1000)
X_test = np.hstack((X_test,time_test.reshape(-1,1)))
y_test = X_test.dot(weights)

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

#fit and score the data using RF
RF = RandomForestRegressor(n_estimators=100)
RF.fit(X,y)
RF.score(X_test,y_test)
>>0.5872576516824577

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

#plot RF as trees increase
#set starting point for subplots
index = 1
#set the size of the subplot to something large
plt.figure(figsize=(20,20))
#iterate through number of trees in model
#and plot predictions v actual
for i in [1,5,10,100]:
    plt.subplot(2, 2, index)
    RF_plot = RandomForestRegressor(n_estimators=i)
    RF_plot.fit(X,y)
    #split data btw vals RF can interploate vs. data
    #it needs to exptrapolate
    interpolate_index = X_test[:,10]<=2010
    extrapolate_index = X_test[:,10]>2010
    X_interpolate = X_test[interpolate_index]
    X_extrapolate = X_test[extrapolate_index]
    y_interpolate = y_test[interpolate_index]
    y_extrapolate = y_test[extrapolate_index]
    #plot predictions vs. actual
    plt.scatter(RFplot.predict(X_interpolate),
                y_interpolate,
                color="g",label="interpolate")
    plt.scatter(RFplot.predict(X_extrapolate),
                y_extrapolate,
                color="b",label="extrapolate")
    plt.xlabel('Predicted')
    plt.ylabel('Actual')
    plt.title('Random Forest with {} trees'.format(i))
    plt.subplots_adjust(wspace=.4, hspace=.4)
    plt.legend(loc="best")
    index += 1

Этот график показывает, что максимальное значение, которое модель может предсказать, составляет около 961, в то время как основной тренд в данных подталкивает более свежие значения к 966. К сожалению, случайный лес не может экстраполировать линейный тренд и точно предсказать новые примеры которые имеют значение времени выше, чем в данных обучения (2000–2010 гг.). Даже регулировка количества деревьев не решает проблемы. В этой ситуации, поскольку мы установили идеально линейную зависимость для данных, модель, такая как линейная регрессия, будет лучшим выбором, и у нее не будет проблем с обнаружением тенденции в данных и выполнением точных прогнозов для данных за пределами временных диапазонов в обучении. данные.

#fit the data using Linear Regression
LR = LinearRegression()
LR.fit(X,y)
LR.score(X_test,y_test)
>>1.0
#plot predictions of Linear Regression against actual
plt.figure(figsize=(7,7))
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Linear Regression - Test Data')
_ = plt.scatter(LR.predict(X_interpolate),y_interpolate,
               color="g",label="interpolate")
_ = plt.scatter(LR.predict(X_extrapolate),y_extrapolate,
               color="b",label="extrapolate")
plt.legend(loc="best")

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