【问题标题】:Calculating decision tree depth from a column of data in R?从R中的一列数据计算决策树深度?
【发布时间】:2022-01-27 04:01:45
【问题描述】:

我试图想出一种方法来根据 R 中数据框中的几列计算决策树的深度。

例如,如果我有一些看起来像这样的数据:

library(dplyr)

df <- tibble(
  var = c("x1", NA, "x2", "x9", NA, NA, NA, 'x5', NA, "x3", NA, NA, "x1", NA, NA),
  treeNumber = c(1,1,1,1,1,1,1,2,2,2,2,2,3,3,3)
) 

> df
# A tibble: 15 × 2
   var   treeNumber
   <chr>      <dbl>
 1 x1             1
 2 NA             1
 3 x2             1
 4 x9             1
 5 NA             1
 6 NA             1
 7 NA             1
 8 x5             2
 9 NA             2
10 x3             2
11 NA             2
12 NA             2
13 x1             3
14 NA             3
15 NA             3

如果上述数据创建了 3 个如下所示的决策树:

正如我们所见,终端节点在df 中以NA 的形式给出(为简单起见,我省略了数据框中的实际决策/吐出值[如图所示] 列)。

为了清楚起见,我们可以看到treeNumber 1 的深度为 2(如果我们将根节点索引为 0)。 treeNumber 2 的深度为 1,treeNumber 3 的深度为 0。

从数据框中绘制树的规则或方向是从左到右的类型。例如,如果我们只看 2 号树,我们可以看到数据框的形状与树的绘制方式是如何对应的:

再次,为了清楚起见,如果我们只查看数据框中的 treeNumber = 2,我们可以在 var 列中看到它显示为 x5, NA, x3, NA, NA。这对应于从左到右绘制图像的方式。

我试图找出一种方法来计算每棵树的深度。

一种解决方案是使用igraph 或类似方法,将每棵树变成一个图形对象,然后使用函数igraph::bfs() 计算深度。但是,如果我有很多树(例如 100,000 棵),遍历它们并将它们转换为图形对象是非常耗时的。我希望找到一种仅使用示例中提供的数据来计算深度的方法。

关于如何实现这一点的任何建议?

编辑

根据一些建议,我将提供一个小例子来说明尝试计算树深度的复杂性以及我发现它难以实现的原因。

例如,如果我的数据如下所示:

df <- tibble(
  var = c("x1", "x2", NA, NA, "x9", NA, NA, "x1", NA, "x2", "x3", NA, NA, NA),
  treeNumber = c(1,1,1,1,1,1,1,2,2,2,2,2,2,2)
) 

在这里,我只有两棵树。如果我要绘制这些树,它们会是这样的:

所以,这里我们可以看到treeNumber 1 的深度为 1,而treeNumber 2 的深度为 2。每棵树都有相同数量的终端节点(即NAs),并且每棵树都有相同的数量非终端节点......但每棵树的深度不同。不幸的是,这意味着我们不能只过滤掉NAs 并汇总行数。

【问题讨论】:

  • 如果你的设置和描述的一样,你不需要任何特别的东西。这使用dplyr:df %&gt;% group_by(treeNumber) %&gt;% summarise(n())
  • 恐怕这样不行。我不想总结行数。我试图找到树木的深度。例如,treeNumber 1 有 7 行(其中每行对应于树中的一个节点),但正如您在图像中看到的,它的深度仅为 2(如果我们说根节点的深度为0).
  • 好吧,我误解了你想要的。哇,我差远了。我发誓我读了你的帖子!无论如何,这应该可以:filter(df, !is.na(var)) %&gt;% group_by(treeNumber) %&gt;% summarise(count = n()-1).
  • 您可以试试:df %&gt;% group_by(treeNumber) %&gt;% summarise_each(funs(sum(!is.na(.))-1)) - 这将返回 var 的值 2,1 和 0,分别对应 treeNumber 1、2 和 3。
  • 这些建议很棒。但是,不幸的是,它们仅适用于我给出的示例。如果树结构更复杂,这些方法就不起作用。我将通过一个小例子来编辑我的问题,说明这些方法在哪里失败。

标签: r decision-tree


【解决方案1】:

我认为这行得通,不管树的形状或大小如何。看看你能不能从中找出问题。

# empty data frame to store results 
  # assuming there will be many trees
treeDepth = data.frame(tree = numeric(), depth = numeric())

# loop through each tree number
for(i in unique(df$treeNumber)){
  df2 <- df %>% 
    filter(treeNumber == i) %>%           # filter for the tree number
    mutate(TF = ifelse(is.na(var) == F,   # determine with are are NA or not
                       TRUE, FALSE))
  s <- rle(df2$TF)                        # count consecutive strings of T or F
  
  # frame and filter the consecutive counts data
  s2 <- data.frame(runs = s$lengths %>% unlist(), 
                   TF = s$values %>% unlist()) %>% 
    filter(TF == T)
  
  # if the only T is the first, it's a 0
  if(nrow(s2) == 1){
    depth = 0
  } else{       # otherwise ignore the first T, look for the longest string of Ts
    depth = max(s2[2:nrow(s2), ]$runs) # don't include first T
  }
  # add the tree number & depth to df before next loop
  treeDepth[nrow(treeDepth) + 1, ] <- c(i, depth)
}

treeDepth 
#   tree depth
# 1    1     2
# 2    2     1
# 3    3     0
# 4    4     1
# 5    5     2 

【讨论】:

    猜你喜欢
    • 2017-03-07
    • 2018-09-21
    • 2014-07-20
    • 2016-10-18
    • 2019-03-10
    • 2016-09-13
    • 1970-01-01
    • 2017-01-21
    • 2023-04-08
    相关资源
    最近更新 更多