R:随机 split 的递归树算法

标签 r algorithm recursion tree

我有兴趣编写递归二叉树算法。给定以下数据,我已经对协变量 x

进行了排序
mydata <- data.frame(x = c(10, 20, 25, 35), y = c(-10.5, 6.5, 7.5, -7.5))
> mydata
   x     y
1 10 -10.5
2 20   6.5
3 25   7.5
4 35  -7.5

假设我的最终树看起来像这样:

          [-10.5, 6.5, 7.5, -7.5]
                /         \
          [-10.5]        [6.5, 7.5, -7.5]
                            /      \
                    [6.5, 7.5]       [ -7.5]

我希望函数的最终输出返回一个包含所有节点的列表:

> final_tree
[[1]]
[[1]][[1]]
   x     y
1 10 -10.5
2 20   6.5
3 25   7.5
4 35  -7.5


[[2]]
[[2]][[1]]
   x     y
1 10 -10.5


[[2]][[2]]
   x     y
1 20   6.5
2 25   7.5
3 35  -7.5


[[3]]
[[3]][[1]]
NULL

[[3]][[2]]
NULL

[[3]][[3]]
   x     y
1 20   6.5
2 25   7.5


[[3]][[4]]
   x     y
1 35  -7.5

我使用 best_split_ind 在每个节点上随机拆分树。如果 best_split_ind = 1,则意味着 node_parent 中的第一个实例将最终位于 node_left 中,其余实例最终位于 >node_right。如果 best_split_ind = 3,则意味着 node_parent 中的前三个实例将最终出现在 node_left 中,其余的最终将出现在 node_right

这是我到目前为止所拥有的:

# Initialize empty tree
create_empty_tree <- function(max_height) sapply(1:max_height, function(k) replicate(2**(k-1),c()))

# Create empty tree with max_height = 3
tree_struc <- create_empty_tree(max_height = 3)

grow_tree <- function(node_parent, max_height, tree_struc, height){
  # Sort x
  sorted_x <- sort(node_parent$x)

  # Determine best split 
  best_split_ind <- sample(1:(nrow(node_parent) - 1), 1)

  # Assign instances to left or right nodes
  group <- ifelse(node_parent$x <= node_parent$x[best_split_ind], "left", "right")
  node_left <- node_parent[which(group == "left"), ]
  node_right <- node_parent[which(group == "right"), ]

  # Recursive call on left and right nodes
  if(height < max_height){
  tree_struc[[height]] <- node_parent
  tree_struc[[height + 1]][[1]] <- grow_tree(node_parent = node_left, max_height = max_height, tree_struc = tree_struc, height = height + 1)
  tree_struc[[height + 1]][[2]] <- grow_tree(node_parent = node_right, max_height = max_height, tree_struc = tree_struc, height = height + 1)
  }

  return(tree_struc)
}

grow_tree(node_parent = mydata, max_height = 3, tree_struc = tree_struc, height = 1)

生成的树不正确。我认为这与我如何递归调用左右子节点上的函数有关。谁能指出我正确的方向?

最佳答案

我可能误解了你的意思,但是你可以通过使用两个相互递归调用的函数来简化很多。无需设置初始容器。

第一个函数我们甚至不需要手动调用,而是从我们的 grow_tree 函数内部调用。它只是检查是否尚未达到最大树深度以及是否还有足够的元素可供拆分。如果是这样,它会对其内容调用grow_tree。否则,它返回其内容不变:

conditional_split <- function(df, depth, max_depth)
{
  if(nrow(df) == 1 | depth == max_depth) return(df)
  else grow_tree(df, depth + 1, max_depth)
}

然后,我们的主函数可以安全地分割给定的数据帧,并使用 lapply 递归调用 conditional_split:

grow_tree <- function(df, depth = 1, max_depth = 3)
{
  break_at <- sample(nrow(df) - 1, 1)
  branched <- list(left = df[1:break_at,], right = df[-seq(break_at),])
  lapply(branched, conditional_split, depth, max_depth)
}

我认为这符合您的要求:

grow_tree(mydata, max_depth = 3)
#> $left
#>    x     y
#> 1 10 -10.5
#> 
#> $right
#> $right$left
#> $right$left$left
#>    x   y
#> 2 20 6.5
#> 
#> $right$left$right
#>    x   y
#> 3 25 7.5
#> 
#> 
#> $right$right
#>    x    y
#> 4 35 -7.5

您可以轻松更改最大树深度:

grow_tree(mydata, max_depth = 2)
#> $left
#> $left$left
#>    x     y
#> 1 10 -10.5
#> 
#> $left$right
#>    x   y
#> 2 20 6.5
#> 3 25 7.5
#> 
#> 
#> $right
#>    x    y
#> 4 35 -7.5

关于R:随机 split 的递归树算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61621974/

相关文章:

r - 如何使用 knit r 导入 python 包?

algorithm - 数据结构 : Big O time cost

algorithm - 如何在 3D 网格中线性迭代?

c# - Action<Action> 是什么意思?

r - 使用数据帧列为r中的bind_rows指定数据帧

r - 创建空间点数据框

r - ggplot2 的多个图例

c - 地址值更改不会反射(reflect)在 while 循环中

java - 我的 Java 递归函数出了什么问题?

java 递归二叉搜索树