【问题标题】:Recursive method for Catalan numbers in RR中加泰罗尼亚数的递归方法
【发布时间】:2018-05-21 16:41:07
【问题描述】:

我正在尝试在 R 中编写一个函数,该函数将接受输入 numb 并输出相应的加泰罗尼亚语数字。 供您参考,加泰罗尼亚数字的递归公式是,

C_0 = 1; 
C_n = {(4n - 2)*C_(n-1)}/(n+1)

我的代码如下,

catalan_num_recr <- function(numb){
  if (numb == 0){
    return(1)
  }
  else
    return(((4*numb-2)*catalan_num_recr(numb-1))/(numb+1))
}

当我运行这个函数时,我得到了,

> catalan_num_recr(3)
[1] 5

这是正确的。

AIM:但是,我正在尝试查找加泰罗尼亚语的数字范围, 我想找到类似catalan_num_recr(1:10) 的东西。

问题:这不适用于我的函数,我收到以下警告,

Warning messages:
1: In if (numb == 0) { :
  the condition has length > 1 and only the first element will be used

还有很多错误的值作为输出,

> catalan_num_recr(1:15)
 [1] 1.000000 2.000000 2.500000 2.800000 3.000000 3.142857 3.250000
 [8] 3.333333 3.400000 3.454545 3.500000 3.538462 3.571429 3.600000
[15] 3.625000

有人可以帮我修改我的功能/或帮我解决问题吗?

问候。

【问题讨论】:

    标签: r function catalan


    【解决方案1】:

    使用Vectorize,它接受一个函数并返回一个新函数,该函数本质上是接受向量化输入的函数的包装器。计算实际上是由mapply 重复执行的,因此它不会像编写手动向量化的函数那样快。

    Vectorize(catalan_num_recr)(1:15)
     [1]       1       2       5      14      42     132     429    1430    4862
    [10]   16796   58786  208012  742900 2674440 9694845
    

    【讨论】:

    • 这有效,但是,我的代码也有效,但结果错误。你能告诉我到底发生了什么吗?
    【解决方案2】:

    您的函数当前不接受向量输入。这可能有点令人困惑,因为许多函数(例如数学运算符)默认情况下是矢量化的。您需要使用mapapply 函数将该函数应用于向量的每个元素。这实际上是一个快速循环,purrr 包具有语法一致和类型稳定的优点。

    catalan_num_recr <- function(numb){
      if (numb == 0){
        return(1)
      }
      else
        return(((4*numb-2)*catalan_num_recr(numb-1))/(numb+1))
    }
    
    purrr::map_dbl(1:15, catalan_num_recr)
    #>  [1]       1       2       5      14      42     132     429    1430
    #>  [9]    4862   16796   58786  208012  742900 2674440 9694845
    

    reprex package (v0.2.0) 于 2018 年 5 月 21 日创建。

    【讨论】:

    • purr::map_dbl从哪里来?
    • 在 R 中,:: 指的是包名,所以这是来自purrr 包的map_dbl 函数。这个包是 tidyverse 系列包的成员,它们可以很好地协同工作。
    【解决方案3】:

    您只需要使用sapply 之类的矢量化函数,来自apply 系列。

    sapply(1:10,catalan_num_recr,USE.NAMES = F)

    【讨论】:

      【解决方案4】:

      您可以在数字向量上使用sapply(或lapply

      sapply(c(0:15), catalan_num_recr)
      

      只需将输出放入数据框中,以便您检查数字

      data.frame("n" = c(0:5), "cnr" = sapply(c(0:5), catalan_num_recr))
      
        n cnr
      1 0   1
      2 1   1
      3 2   2
      4 3   5
      5 4  14
      6 5  42
      

      【讨论】:

        【解决方案5】:

        首先,您收到的警告是告诉您在numb == 0 中,R 只会评估numb[1] == 0

        虽然其他答案是正确的,但它们效率不高,因为您需要多次计算每个加泰罗尼亚数字。 (对于 Catalan(15),您需要计算 Catalan(14),您已经计算过了)

        我认为这是一个更好的版本,它计算每个加泰罗尼亚语数字直到最大数字,然后返回您要求的数字。

        catalan <- function(numbs) {
           cat <- vector("numeric", length(max(numbs)) + 1)
           for (i in 0:max(numbs)) {
              if (i == 0) {
                 cat[i+1] <- 1
              } else {
                 cat[i+1] <- ((4*i - 2)*cat[i])/(i + 1)
              }
           }
           cat[numbs + 1]
        }
        
        > catalan(1:15)
         [1]       1       2       5      14      42     132     429
         [8]    1430    4862   16796   58786  208012  742900 2674440
        [15] 9694845
        

        这是一个小基准,其中catrvect = Vectorize(catalan_num_recr)

        microbenchmark::microbenchmark(catalan(1:100), catvect(1:100))
        Unit: microseconds
                   expr      min        lq      mean    median       uq
         catalan(1:100)   86.515   98.7565  127.3139  122.7665  141.423
         catvect(1:100) 4764.728 4947.3070 5661.0624 5124.3385 5647.238
               max neval
           276.825   100
         11009.428   100
        

        当然,这个函数现在不是递归的了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-26
          • 2012-04-19
          相关资源
          最近更新 更多