Как справиться с линейной регрессией, когда между ними больше переменных и взаимодействий с наиболее распространенными библиотеками Python, а также новый подход к генетическому программированию, который значительно улучшает результат.
У всех нас был какой-то опыт линейной регрессии. Это один из наиболее часто используемых методов регрессии. Почему? Потому что это просто объяснить и легко реализовать. Но что происходит, когда у вас более одной переменной? Как вы можете справиться с этой повышенной сложностью и по-прежнему использовать такую простую для понимания регрессию? А что будет, если система будет еще сложнее? Представим, что у вас есть взаимодействие между двумя переменными.
Здесь вступает в действие множественная линейная регрессия, и мы увидим, как справляться с взаимодействиями с помощью некоторых удобных библиотек в Python. Наконец, мы попытаемся решить ту же проблему с символической регрессией, и мы будем наслаждаться преимуществами, которые она дает!
Если вы хотите освежить в памяти линейную регрессию, есть много доступных ресурсов, и я также написал краткое введение в кодирование. А как насчет символической регрессии? В этой статье мы будем использовать gplearn. См. Его документацию для получения дополнительной информации или, если хотите, прочтите мою другую статью о том, как использовать его со сложными функциями в Python здесь.
Подготовка данных
Мы рассмотрим два варианта использования регрессии. В первом случае у нас будет всего четыре переменных (от x1 до x4), которые складываются плюс некоторые предопределенные взаимодействия: x1 * x2, x3 * x2 и x4 * x2.
Обратите внимание, что в нашем наборе данных out_df нет условий взаимодействия. То, что мы будем делать, будет пытаться обнаружить эти отношения с помощью наших инструментов. Вот как выглядят переменные, когда мы строим их с помощью seaborn, используя x4 в качестве оттенка (рисунок 1):
Y во втором случае (рисунок 2) определяется как:
y_true = x1+x2+x3+x4+ (x1*x2)*x2 - x3*x2 + x4*x2*x3*x2 + x1**2
Довольно сложный сценарий!
Случай 1: множественная линейная регрессия
Первый шаг - лучше понять взаимосвязь, поэтому мы попробуем наш стандартный подход и приспособим множественную линейную регрессию к этому набору данных. Для этого мы будем использовать статистические модели. На рисунке 3 представлены результаты регрессии OLS.
import statsmodels.api as sm Xb = sm.add_constant(out_df[['x1','x2','x3','x4']]) mod = sm.OLS(y_true, Xb) res = mod.fit() res.summary()
Ой, это явно не тот результат, на который мы надеялись. R² составляет всего 0,567, и, более того, я удивлен, увидев, что значение P для x1 и x4 невероятно велико. Нам нужна другая стратегия.
Полиномиальные особенности
Что мы можем сделать, так это импортировать библиотеку Python под названием PolynomialFeatures из sklearn, которая будет генерировать полиномиальные и интерактивные функции. Например, если входной образец является двумерным и имеет форму [a, b], полиномиальные характеристики степени 2 будут [1, a, b, a², ab, b²].
from sklearn.preprocessing import PolynomialFeatures import scipy.special poly = PolynomialFeatures(interaction_only=True) X_tr = poly.fit_transform(Xb) Xt = pd.concat([Xb,pd.DataFrame(X_tr,columns=poly.get_feature_names()).drop([‘1’,’x0',’x1',’x2',’x3',’x4'],1)],1)
С «Interaction_only = True» создаются только интерактивные функции: функции, которые являются продуктами не более degree
отдельных входных функций (но не x[1] ** 2
, x[0] * x[2] ** 3
и т. Д.). Параметр степени по умолчанию - 2.
С тем же кодом, что и раньше, но с использованием Xt сейчас, дает следующие результаты.
mod = sm.OLS(y_true, Xt) res = mod.fit() res.summary()
Теперь R² на рисунке 4 равен 1, что идеально. Слишком идеально, чтобы быть хорошим? На самом деле терминов взаимодействия в сводной статистике очень много. Некоторые из них мы даже не знали. Наше уравнение имеет вид:
y = x₁ + 05 * x₂ + 2 * x₃ + x₄ + x₁ * x₂ - x₃ * x₂ + x₄ * x₂
Итак, наша подгонка вводит взаимодействия, которых мы не делали » t явно использовать в нашей функции. Даже если мы удалим те, которые имеют высокое значение p (x₁ x₄), у нас останется сложный сценарий. Это может быть проблемой для обобщения. Мы можем использовать генетическое программирование, чтобы дать нам здесь несколько советов.
Генетическое программирование: GPlearn
С помощью генетического программирования мы в основном говорим системе сделать все возможное, чтобы найти взаимосвязи в наших данных в аналитической форме. Если вы прочитаете другой учебник, некоторые функции, которые я здесь буду называть, будут более понятными. Однако в основном мы хотим импортировать SymbolicRegressor из gplearn.genetic, и мы будем использовать sympy для красивого форматирования наших уравнений.
Поскольку мы находимся в процессе, мы также импортируем регрессоры RandomForest и DecisionTree, чтобы позже сравнить результаты между всеми этими инструментами. Ниже кода, чтобы заставить его работать:
Словарь конвертера предназначен для того, чтобы помочь нам сопоставить уравнение с соответствующей функцией Python, чтобы simpy выполнял свою работу. Мы также разделяем наши данные на train_test, чтобы сравнивать наши прогнозы только на тестовых данных. Мы определили набор функций, в котором мы используем стандартные функции из набора gplearn.
На 40-м поколении код останавливается, и мы видим, что R² почти равно 1, а сгенерированная формула теперь довольно легко читается.
Если вы сравните ее с формулой, которую мы фактически использовали, вы увидите, что она очень похожа, рефакторинг нашей формулы выглядит следующим образом:
y = -x₃ (x₂–2) + x₂ (x₁+x₄+ 0.5)+x₁+x₄
Все алгоритмы хорошо справились с этой работой: вот R².
statsmodels OLS with polynomial features 1.0, random forest 0.9964436147653762, decision tree 0.9939005077996459, gplearn regression 0.9999946996993035
Случай 2: взаимодействия 2-го порядка
В этом случае отношения усложняются по мере увеличения порядка взаимодействия:
X = np.column_stack((x1, x2, x3, x4)) y_true = x1+x2+x3+x4+ (x1*x2)*x2 - x3*x2 + x4*x2*x3*x2 + x1**2 out_df['y'] = y_true
Мы делаем в основном те же шаги, что и в первом случае, но здесь мы уже начинаем с полиномиальных функций:
poly = PolynomialFeatures(interaction_only=True) X_tr = poly.fit_transform(out_df.drop('y',1)) Xt = pd.concat([out_df.drop('y',1),pd.DataFrame(X_tr,columns=poly.get_feature_names()).drop(['1','x0','x1','x2','x3'],1)],1) Xt = sm.add_constant(Xt) mod = sm.OLS(y_true, Xt) res = mod.fit() res.summary()
В этом сценарии наш подход больше не приносит результатов. Понятно, что в нашем наборе данных нет правильных предикторов. Мы могли бы использовать полиномиальные особенности для исследования взаимодействий более высокого порядка, но размерность, вероятно, слишком сильно увеличится, и у нас останется не намного больше знаний, чем раньше. Кроме того, если бы у вас был реальный набор данных и вы не знали формулу цели, вы бы увеличили порядок взаимодействий? Думаю, нет!
В приведенном ниже коде мы снова подбираем и прогнозируем наш набор данных с помощью дерева решений и алгоритмов случайного леса, но также используем gplearn.
X_train, X_test, y_train, y_test = train_test_split(out_df.drop('y',1), y, test_size=0.30, random_state=42) est_tree = DecisionTreeRegressor(max_depth=5) est_tree.fit(X_train, y_train) est_rf = RandomForestRegressor(n_estimators=100,max_depth=5) est_rf.fit(X_train, y_train) y_gp = est_gp.predict(X_test) score_gp = est_gp.score(X_test, y_test) y_tree = est_tree.predict(X_test) score_tree = est_tree.score(X_test, y_test) y_rf = est_rf.predict(X_test) score_rf = est_rf.score(X_test, y_test) y_sm = res.predict(Xt) est_gp.fit(X_train, y_train) print('R2:',est_gp.score(X_test,y_test)) next_e = sympify((est_gp._program), locals=converter) next_e
Результат невероятный: снова после 40 поколений у нас остается невероятно высокий R² и, что еще лучше, простое аналитическое уравнение.
Исходная формула такая:
Итак, мы видим, что действительно существуют различия в терминах, которые включают x1 и его взаимодействия. А термины, не зависящие от него, совершенно там. Тем не менее, по сравнению с подходом полиномиальных функций, здесь мы имеем дело с гораздо менее сложной формулой.
В чем ошибка разных систем? Что ж, для gplearn это невероятно мало по сравнению с другими. На рисунке 8 показана ошибка координаты y по сравнению с фактическим значением y. Хотя ось x является общей, вы можете заметить, насколько разной стала ось y. Максимальная ошибка с GPlearn составляет около 4, в то время как другие методы могут отображать всплески до 1000.
Заключение
В первой части этой статьи мы увидели, как бороться с множественной линейной регрессией при наличии взаимодействий. Мы использовали statsmodels OLS для множественной линейной регрессии и функции многочлена sklearn для генерации взаимодействий. Затем мы подошли к той же проблеме с другим классом алгоритмов, а именно с генетическим программированием, которое легко импортировать и реализовать и которое дает аналитическое выражение.
Во второй части мы увидели, что когда все становится запутанным, у нас остается некоторая неуверенность при использовании стандартных инструментов, даже тех, что используются в традиционном машинном обучении. Однако с этим классом проблем легче справиться при использовании gplearn. С помощью этой библиотеки нам напрямую была предоставлена аналитическая формула для нашей проблемы.
использованная литература
[1] статистические модели
[2] особенности полинома sklearn
[3] gplearn