如何在R编程中指定决策树的分裂方式?

8

我想在这里应用决策树。决策树会自行处理每个节点的分割。但是,在第一个节点上,我想基于"年龄"进行分割。该如何强制执行呢?

library(party)    
fit2 <- ctree(Churn ~ Gender + Age + LastTransaction + Payment.Method + spend + marStat, data = tsdata)
3个回答

13

ctree()中没有内置选项可以实现此功能。手动完成这个最简单的方法是:

  1. 只使用解释变量Agemaxdepth = 1学习一棵树,以便只创建一个分裂。

  2. 使用步骤1中的树拆分数据并为左分支创建子树。

  3. 使用步骤1中的树拆分数据并为右分支创建子树。

这将实现您想要的效果(尽管我通常不建议这样做...)。

如果您使用partykit中的ctree()实现,则还可以将这三棵树合并成单个树,以进行可视化和预测等操作。这需要进行一些修改,但仍然可行。

我将使用iris数据并强制在变量Sepal.Length中进行分裂,否则该树不会使用该变量。学习上述三棵树非常容易:

library("partykit")
data("iris", package = "datasets")
tr1 <- ctree(Species ~ Sepal.Length,     data = iris, maxdepth = 1)
tr2 <- ctree(Species ~ Sepal.Length + ., data = iris,
  subset = predict(tr1, type = "node") == 2)
tr3 <- ctree(Species ~ Sepal.Length + ., data = iris,
  subset = predict(tr1, type = "node") == 3)

需要注意的是,使用公式Sepal.Length + .非常重要,以确保模型框架中的变量在所有树中都按相同方式排序。

接下来是最技术性的步骤:我们需要从三棵树中提取原始node结构,修复节点id,使其处于正确的顺序,然后将所有内容整合成单个节点:

fixids <- function(x, startid = 1L) {
  id <- startid - 1L
  new_node <- function(x) {
    id <<- id + 1L
    if(is.terminal(x)) return(partynode(id, info = info_node(x)))
    partynode(id,
      split = split_node(x),
      kids = lapply(kids_node(x), new_node),
      surrogates = surrogates_node(x),
      info = info_node(x))
  }

  return(new_node(x))   
}
no <- node_party(tr1)
no$kids <- list(
  fixids(node_party(tr2), startid = 2L),
  fixids(node_party(tr3), startid = 5L)
)
no
## [1] root
## |   [2] V2 <= 5.4
## |   |   [3] V4 <= 1.9 *
## |   |   [4] V4 > 1.9 *
## |   [5] V2 > 5.4
## |   |   [6] V4 <= 4.7
## |   |   |   [7] V4 <= 3.6 *
## |   |   |   [8] V4 > 3.6 *
## |   |   [9] V4 > 4.7
## |   |   |   [10] V5 <= 1.7 *
## |   |   |   [11] V5 > 1.7 *

最后,我们设置了一个包含所有数据的联合模型框架,并将其与新的联合树结合起来。为了能够将树转化为 constparty 以进行良好的可视化和预测,添加了一些关于拟合节点和响应的信息。有关此背景,请参见 vignette("partykit", package = "partykit")

d <- model.frame(Species ~ Sepal.Length + ., data = iris)
tr <- party(no, 
  data = d,
  fitted = data.frame(
    "(fitted)" = fitted_node(no, data = d),
    "(response)" = model.response(d),
    check.names = FALSE),
  terms = terms(d),
)
tr <- as.constparty(tr)

然后我们完成了,可以使用强制第一个分割来可视化我们合并的树:

plot(tr)

合并树


5
在每次迭代中,决策树将选择最佳变量进行分割(基于信息增益/基尼指数,用于CART,或者基于卡方检验,用于条件推断树)。如果您有更好的预测变量可以将类别分开,比利用年龄这个预测变量更好,那么该变量将首先被选择。
我认为根据您的要求,您可以执行以下几个操作:
(1)无监督:离散化年龄变量(根据您的领域知识创建区间,例如0-20、20-40、40-60等),并对每个年龄段的数据进行子集处理,然后在每个子集上训练一个单独的决策树。
(2)有监督:不断删除其他预测变量,直到年龄被首先选择。现在,您将获得一个以年龄为第一个变量选择的决策树。使用决策树创建的年龄规则(例如Age>36&Age<=36)将数据子集化为两部分。在每个部分上,分别使用所有变量学习一个完整的决策树。
(3)有监督集成:您可以使用随机森林分类器来查看年龄变量的重要性。

0
您可以使用rpartpartykit的组合来实现这种操作。
请注意,如果您使用ctree来训练DT,然后使用data_party函数从不同节点中提取数据,那么在提取的数据集中仅包括训练变量,即在您的情况下是年龄。
我们必须在第一步中使用rpart来训练带有所选变量的模型,因为有一种方法使用rpart训练DT,使您可以在提取的数据集中保留所有变量,而不将这些变量作为训练变量。
library(rpart)
fit2 <- rpart(Churn ~ . -(Gendere + LastTransaction + Payment.Method + spend + marStat) , data = tsdata, maxdepth = 1)

使用这种方法,您唯一的训练变量将是年龄,您可以将您的rpart树转换为partykit,并从不同的节点提取数据并分别进行训练:
library(partykit)
fit2party <- as.party(fit2)
dataset1 <- data_party(fit2party, id = 2)
dataset2 <- data_party(fit2party, id = 3)

现在你有两个数据集,基于年龄分割,并且包含了你未来训练决策树所需的所有变量。你可以根据自己的需要使用rpart或ctree构建决策树。

之后,你可以使用partynodepartysplit组合来根据你所达到的训练规则构建树形结构。

希望这正是你所需要的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接