【问题标题】:pmap_dfr performing row-wise (not column-wise) operation with named function which has multiple inputspmap_dfr 使用具有多个输入的命名函数执行逐行(非逐列)操作
【发布时间】:2020-12-16 20:02:22
【问题描述】:

我知道这篇文章的标题很复杂。但是我在网上的例子中没有找到我的确切情况。

我有一个命名(非匿名)函数,它接受一个 tibble、一个字符串(结构)和一个数字(百分比)的 作为输入并执行线性插值,沿着行中值的子集。 (不是按列操作。)它执行线性插值。它的“数学”涉及使用单元格中的值以及从列名中提取的数字。这些列的名称类似于 GTV0、GTV1、... GTV135。

下面的工作代码。为了完整起见,我在这里复制它,尽管具体细节不一定与下面的问题密切相关。

# This function works if fed one row of a df at a time, but isn't "multi-dimensional":
Dx <- function(df, structure, percent) {

  # First, make sure we've got our data in the right formats:
  df <- df %>% tibble() %>% select(starts_with(structure)) %>% rowwise() 
  structure <- toString(structure)
  percent <- as.double(percent)
  
  # If we don't have any DVH data for the structure, return "NA"
  if(is.na(df[[9]])) return(NA)
  
  for(i in 9:(length(df) - 1)) {   # The V0 is the 9th entry in the array, so start iterating there.
    
    # Deal with pesky NA's as iterating along (convert to 0's):
    if(is.na(df[[i]])) df[[i]] <- 0
    if(is.na(df[[i+1]])) df[[i+1]] <- 0
    
    # Typically unlikely for the cell's value to be a round percent, but:    
    if(df[[i]] == percent) {
      
      answer <- colnames(df[i])
      return(as.double(str_replace(answer, paste0(structure, "V"), "")))
      
    } else if(df[[i]] > percent & df[[i+1]] < percent) {  # This is why we stop at "length - 1" of data frame.
      # Do the linear interpolation here
      
      # First, capture the names of the two columns:
      column1 <- colnames(df[i])
      column2 <- colnames(df[i+1])
      
      # Strip the structure names from the column names and convert to doubles:
      column1 <- as.double(str_replace(column1, paste0(structure, "V"), ""))
      column2 <- as.double(str_replace(column2, paste0(structure, "V"), ""))
      
      # Perform the linear interpolation:
      return(as.double(column1 + ((percent - df[[i]])/(df[[i+1]] - df[[i]]) * (column2 - column1))))
    }
  }    
}

我的问题是: 我该如何净化这个?理想情况下,我会将它与 mutate 一起使用来创建一个新列,并将插值逐行放入其中。我的问题分为两部分:

  1. 如何调用命名函数 Dx?
  2. 我必须如何修改函数的内容(如果有的话)才能使用 purrr?

我以为会是这样的:

df <- df %>% rowwise() %>% mutate(GTVD95 = pmap_dfr(df, Dx, "GTV", 95))

但这是不对的。

我可以用 for 循环调用这个现有函数:

for (i in 1:nrow(df)) {
  df$GTVD95[i] <- Dx(df[i,], "GTV", 95)
}

但这并不理想,因为我什至想把它放入一个循环中,因为我想找到大约 20 个插值点并且不想调用它 20 次,改变数字(例如,两个 95在上面的循环中)每次。

我感谢任何见解!提前致谢!

【问题讨论】:

  • 嗨,汤姆,欢迎来到 Stack Overflow!如果您提供数据样本,回答您的问题会容易得多。请使用dput(df[1:10,1:10]) 的输出编辑您的问题。还请提供此示例数据的预期输出,以便我们检查我们的解决方案。请参阅How to make a great R reproducible example 了解更多信息。
  • 也许mutate(GTVD95 = Dx(cur_data(), "GTV", 95)) 会起作用
  • 做到了。杰出的!我以前没有遇到过“cur_data()”。感谢您的提示!
  • @TomDilling 不客气 :)

标签: r purrr


【解决方案1】:

你可以使用cur_data() 访问当前组数据,因为我们使用的是rowwise(),它会获取行数据:

df %>% rowwise()  %>% mutate(GTVD95 =  print(cur_data()))
#> # A tibble: 1 x 4
#>       a     b     c     d
#>   <int> <int> <int> <int>
#> 1     1     1     1     1
#> # A tibble: 1 x 4
#>       a     b     c     d
#>   <int> <int> <int> <int>
#> 1     2     2     2     2
#> # A tibble: 1 x 4
#>       a     b     c     d
#>   <int> <int> <int> <int>
#> 1     3     3     3     3
#> # A tibble: 1 x 4
#>       a     b     c     d
#>   <int> <int> <int> <int>
#> 1     4     4     4     4
#> # A tibble: 1 x 4
#>       a     b     c     d
#>   <int> <int> <int> <int>
#> 1     5     5     5     5

pmap 实际上会将每一列作为参数发送,即

pmap(df, function(...) print(c(...)))
#> a b c d 
#> 1 1 1 1 
#> a b c d 
#> 2 2 2 2 
#> a b c d 
#> 3 3 3 3 
#> a b c d 
#> 4 4 4 4 
#> a b c d 
#> 5 5 5 5

由于您的函数需要获取包含行数据的整个data.frame,我们可以这样做:

df %>% rowwise() %>% mutate(GTVD95 = Dx(cur_data(), "GTV", 95))

或者如果你想使用pmap:

Dx <- function(..., structure, percent) {
  df <- as_tibble(list(...))
  .
  .
  .
}
# use df or cur_data() inside mutate
df %>% mutate(GTVD95 = pmap(df, Dx, structure="GTV", percent=95))

【讨论】:

  • 我不知道cur_data() 函数集。这很整洁。我一直使用pmap(~with(list(...), print(GTVD95))) 来按名称访问列。
  • @IanCampbell 感谢您的反馈,很高兴听到我的回答对某人有所帮助:)
猜你喜欢
  • 1970-01-01
  • 2011-12-07
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 2019-09-13
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
相关资源
最近更新 更多