最终决策为线性回归的决策树

数据挖掘 Python scikit-学习 决策树
2021-09-15 10:18:58

问题:我想实现一个决策树,每个叶子都是线性回归,这样的模型是否存在(最好在 sklearn 中)?

案例一:

样机数据使用以下公式生成:

y = int(x) + x * 1.5

看起来像:

在此处输入图像描述

我想使用决策树来解决这个问题,其中最终决策会产生线性公式。就像是:

  1. 0 <= x < 1 -> y = 0 + 1.5 * x
  2. 1 <= x < 2 -> y = 1 + 1.5 * x
  3. 2 <= x < 3 -> y = 2 + 1.5 * x
  4. 等等。

我认为最好使用决策树来完成。我做了一些谷歌搜索,我认为DecisionTreeRegressorfromsklearn.tree可以工作,但这会导致点在一个范围内被分配一个恒定值,如下所示: 在此处输入图像描述

代码:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.tree import DecisionTreeRegressor

x = np.linspace(0, 5, 100)
y = np.array([int(i) for i in x]) + x * 1.5

x_train = np.linspace(0, 5, 10)
y_train = np.array([int(i) for i in x_train]) + x_train * 1.5

clf = DecisionTreeRegressor()
clf.fit(x_train.reshape((len(x_train), 1)), y_train.reshape((len(x_train), 1)))

y_result = clf.predict(x.reshape(len(x), 1))
plt.plot(x, y, label='actual results')
plt.plot(x, y_result, label='model predicts')
plt.legend()
plt.show()

示例案例 2: 不是一个输入,而是两个输入:x1 和 x2,输出计算如下:

  1. x1 = 0 -> y = 1 * x2
  2. x1 = 1 -> y = 3 * x2 + 5
  3. x1 = 6 -> y = -1 * x2 -4
  4. 否则 -> y = x2 * 20 - 100

在此处输入图像描述

代码:

import matplotlib.pyplot as plt
import random

def get_y(x1, x2):
    if x1 == 0:
        return x2
    if x1 == 1:
        return 3 * x2 + 5
    if x1 == 6:
        return - x2 - 4
    return x2 * 20 - 100

X_0 = [(0, random.random()) for _ in range(100)]
x2_0 = [i[1] for i in X_0]
y_0 = [get_y(i[0], i[1]) for i in X_0]
X_1 = [(1, random.random()) for _ in range(100)]
x2_1 = [i[1] for i in X_1]
y_1 = [get_y(i[0], i[1]) for i in X_1]
X_2 = [(6, random.random()) for _ in range(100)]
x2_2 = [i[1] for i in X_2]
y_2 = [get_y(i[0], i[1]) for i in X_2]
X_3 = [(random.randint(10, 100), random.random()) for _ in range(100)]
x2_3 = [i[1] for i in X_3]
y_3 = [get_y(i[0], i[1]) for i in X_3]
plt.scatter(x2_0, y_0, label='x1 = 0')
plt.scatter(x2_1, y_1, label='x1 = 1')
plt.scatter(x2_2, y_2, label='x1 = 6')
plt.scatter(x2_3, y_3, label='x1 not 0, 1 or 6')
plt.grid()
plt.xlabel('x2')
plt.ylabel('y')
plt.legend()
plt.show()

所以我的问题是:每个叶子都是线性回归的决策树是否存在?

4个回答

我认为最简单的方法是创建一个决策树,其中最终决策会产生一个线性公式。

撇开这实际上是否最简单/最好,这种类型的模型确实存在,通常称为“基于模型的递归分区”。参见例如https://stats.stackexchange.com/q/78563/232706
R中有几个包:(partyfit和较旧的更简单的partymob,,,Cubist不幸的是,Python 中似乎还没有。 这是从 2018 年年中开始将其包含在 sklearn 中的讨论。

我建议使用样条回归。或一些多项式回归。

为什么?您基本上近似的是(几乎)逐步函数。这里

更多信息在这里和一个伟大的背景介绍在这里

您正在寻找线性树

线性树决策树不同,因为它们计算线性近似(而不是常数近似),在叶子中拟合简单的线性模型。

对于我的一个项目,我开发了linear-tree一个 python 库,用于在叶子上构建带有线性模型的模型树。

在此处输入图像描述

线性树被开发为与 scikit-learn 完全集成。

from sklearn.linear_model import *
from lineartree import LinearTreeRegressor, LinearTreeClassifier

# REGRESSION
regr = LinearTreeRegressor(base_estimator=LinearRegression())
regr.fit(X, y)

# CLASSIFICATION
clf = LinearTreeClassifier(base_estimator=RidgeClassifier())
clf.fit(X, y)

LinearTreeRegressorLinearTreeClassifier作为 scikit-learn 提供BaseEstimator它们是在拟合线性估计器的数据上构建决策树的包装器sklearn.linear_model所有可用的模型sklearn.linear_model都可以用作线性估计器。

比较决策树和线性树:

在此处输入图像描述

在此处输入图像描述

即使在您更新之后,我认为 Noah 对样条回归的提示是解决问题的最佳方法。这是R中的一个简短示例:

# Generate data
x <- -50:100
y <- 0.001*x^3
plot(x,y)
df = data.frame(y,x)

# Linear regression
reg_ols=lm(y~.,data=df)
pred_ols = predict(reg_ols, newdata=df)

# GAM with regression splines
library(gam)
reg_gam = gam(y~s(x,5), data=df)
pred_gam = predict(reg_gam, newdata=df)

# Plot prediction and actual data
require(ggplot2)
df2 = data.frame(x,y,pred_ols, pred_gam)
ggplot(df2, aes(x)) +                    
  geom_line(aes(y=y),size=1, colour="red") +  
  geom_line(aes(y=pred_ols),size=1, colour="blue") +
  geom_line(aes(y=pred_gam),size=1, colour="black", linetype = "dashed")  

所以我有一些函数是数据生成过程(图中的红线),我想很好地适应这个函数。OLS(线性回归)效果不佳(图中的蓝线),但带有样条的 GAM 将非常适合(黑色虚线)。

在此处输入图像描述

这个模型看起来像 yi=β0+β1x1,i+ui (像 2D 一样),但当然您可以将模型扩展为 yi=β0+β1x1,i+...+βkxk,i+ui, 在哪里 k 是模型中“变量”的数量(类似于 kD)。

由于您似乎在使用 Python,因此您需要寻找 GAM 的 Py 实现,例如PyGAMStatsmodels

“统计学习简介”的第 7 章介绍了样条回归。您可以查看本书Python 实验室