【问题标题】:Using purrr::map on a function that requires column specification在需要列规范的函数上使用 purrr::map
【发布时间】:2020-04-09 20:23:53
【问题描述】:

我想使用 purrr::map() 来运行一个预打包的函数 fishmethods::deplet

数据集有多年(见下面的示例),我需要为每一年分别拟合模型。

b <- structure(list(Year = c(2012, 2012, 2012, 2012, 2015, 2015, 2015, 
2015), BF_AYAs_count = c(37, 12, 7, 8, 13, 4, 3, 6), BF_noT_effort = c(0.445138888899237, 
0.343750000007276, 0.51597222223063, 0.444444444437977, 0.613194444456894, 
0.437499999992724, 0.374999999992724, 0.607638888897782)), row.names = c(NA, 
-8L), class = c("tbl_df", "tbl", "data.frame"))

deplet 需要以下输入 (catch=NULL,effort=NULL, method = "l") 并输出一个列表 X.out,其中 X == method。出于我的目的,我想按年份获取结果(例如,l.out$results)并将它们放入数据框中。这是我尝试过的代码,它返回 Error in deplet(catch = BF_AYAs_count, effort = BF_noT_effort, method = "l") : object 'BF_AYAs_count' not found 我认为这是由 deplet() 函数期望数据输入的方式引起的问题,因为如果我替换为 map(data, ~lm(BF_AYAs_count~BF_noT_effort, data=.),则此代码可以正常工作。

library(tidyverse)
library(fishmethods)

bf_AYA_popest <- b %>% 
  nest(-Year) %>% 
  mutate(fit=map(data, deplet(catch=BF_AYAs_count,effort=BF_noT_effort, method="l")),
         results = l.out$results) %>% 
  unnest()

【问题讨论】:

    标签: r purrr


    【解决方案1】:

    更新 为了解决 deplet() 无法将 deplet 的结果分配给对象的问题,我们可以将 deplet 包装在我们自己的函数中,该函数实际上将它总是创建的 l.out 对象返回给我们创建的对象。然后我们可以按照您最初想要的方式变异和映射我们的新耗尽:

    deplet2 <- function(...){
      deplet(...)
      return(l.out)
    }
    
    bf_AYA_popest <- b %>% 
      nest(data = c(BF_AYAs_count, BF_noT_effort)) %>% 
      mutate(fit = map(data, ~deplet2(catch = .$BF_AYAs_count,
                                     effort = .$BF_noT_effort,
                                     method ="l")),
             results = map(fit, "results"))
    

    我会先说我从未使用过 fishmethods 包或 deplet() 函数。我认为问题在于我无法将 deplet() 的结果分配给一个对象(即 x

    如果您对此持开放态度,也许另一种建议是仅使用 for 循环并分别构建结果列表,然后将整个列表变异到嵌套数据框:

    #nest the count and effort data
    bf_AYA_popest <- b %>% 
      nest(data = c(BF_AYAs_count, BF_noT_effort))
    
    #create an empty list to store results
    results_list <- vector("list")
    #loop through rows of nested dataframes giving the data to deplete
    for(i in 1:nrow(bf_AYA_popest)){
    
      deplet(catch = bf_AYA_popest$data[[i]]$BF_AYAs_count, 
             effort = bf_AYA_popest$data[[i]]$BF_noT_effort,
             method ="l")
      #each time deplet runs it makes an l.out
      results_list[[i]] <- l.out$results  #catch the ouput and store in list
      #the next run through l.out is overwrritten 
    }
    
    #add the list as a  column to the original nested df
    bf_AYA_popest <- bf_AYA_popest %>% 
      mutate(fit = results_list)
    

    这是我在 mutate 调用中进行这项工作的尝试:

    bf_AYA_popest <- b %>% 
      nest(data = c(BF_AYAs_count, BF_noT_effort)) %>% 
      mutate(fit = map(data, ~deplet(catch = .$BF_AYAs_count,
                                     effort = .$BF_noT_effort,
                                     method ="l")))
    

    没有抛出错误,但结果为 NULL 列:

    # A tibble: 2 x 3
       Year data             fit   
      <dbl> <list>           <list>
    1  2012 <tibble [4 × 2]> <NULL>
    2  2015 <tibble [4 × 2]> <NULL>
    

    我会在我的全局环境中填充一个“l.out”对象。

    【讨论】:

    • 谢谢,更新非常有帮助,解决了我的问题。我假设“巢”按年嵌套,因为一旦其他列被分配给“数据”,它就是df中唯一剩下的列。对于可能从fishmethods应用相同功能的任何人的注意事项-确保更新包装函数中的“METHOD.out”以匹配deplet()中应用的方法-我提供的示例代码使用“l " 方法,但输出名称随方法而变化,例如,method = "ml" output = ml.out.
    猜你喜欢
    • 2022-01-23
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多