【问题标题】:How to add multiple columns to a dataframe from a custom function in R如何从 R 中的自定义函数将多列添加到数据框中
【发布时间】:2016-12-29 20:11:43
【问题描述】:

我创建的代码将采用输入向量、基于输入创建数据框、优化一些值并返回其中一些值。我现在将其转换为一个函数,该函数将在输入数据帧上逐行应用计算。下面是我想要实现的最小工作示例(我的实际功能太长,无法在这里分享!):

# Randomly generated dataframe
df <-  data.frame(a = rnorm(10, 0, 1), x = rnorm(10, 1, 3), y = rnorm(10, 2, 3))

# Function that takes multiple arguments and returns multiple values in a list
zsummary <- function(x, y) { 
  if (y < 0) return(list(NA, NA))
  z = rnorm(10, x, abs(y))
  return(list(mean(z), sd(z)))
}

# Example of something that works using dplyr
#    However, this results in a lot of function calls...
#    especially if there were a lot of columns in the list...
library(dplyr)
df %>% rowwise() %>%
  mutate(mean = zsummary(x,y)[[1]], sd = zsummary(x,y)[[1]])

如您所见,我无法将单独的函数应用于每个新的 df$meandfsd 列,因为它们依赖于只能生成一次的 z 向量。我已经环顾四周了,但我还没有找到答案。我认为解决方案是使用apply 函数之一,而不是dplyr 的函数,但老实说,我从来没有完全理解apply 函数。我也喜欢使用 for 循环和 rbind 的解决方案,因为我在以前的项目中尝试过这个,对于大型数据帧它变得非常慢!

【问题讨论】:

    标签: r function dataframe


    【解决方案1】:

    我们可以为此使用mapply。由于zsummary 有两个参数,mapply 将是一种选择,因为它需要'x' 和'y' 的对应元素来应用zsummary

    t(mapply(zsummary, df$x, df$y))
    

    我们也可以稍微改变一下函数,用dplyr得到输出

    zsummary <- function(x, y) { 
       if (y < 0) return(data.frame(mean = NA, sd = NA))
       z = rnorm(10, x, abs(y))
       data.frame(mean = mean(z), sd = sd(z))
    }
    
     df %>%
         rowwise() %>% 
         do(data.frame(., zsummary(.$x, .$y)))
    

    或者正如我们在 cmets 中讨论的那样,不是让函数接受多个参数,而是使用一个参数并使用 applyMARGIN=1 将其应用于每一行。

    zsummary2 <- function(v1){
          if(v1[2] < 0) return(c(mean = NA, sd = NA))
          z <- rnorm(10, v1[1], abs(v1[2]))
           c(mean = mean(v1), sd= sd(v1))
         }
    
    t(apply(df[-1], 1, zsummary2))
    #         mean        sd
    # [1,]  1.403066 0.8757504
    # [2,]  5.058188 5.1401507
    # [3,]  4.288365 1.4194393
    # [4,]  1.932829 6.7587054
    # [5,] -1.864236 3.7587462
    # [6,]        NA        NA
    # [7,]  3.328629 1.3711950
    # [8,] -2.347699 5.0449958
    # [9,]  2.936615 1.7332283
    #[10,]        NA        NA
    

    注意:每次运行的值都会不同,因为我们没有为 rnorm 设置任何种子。

    【讨论】:

    • 感谢您的快速回复!是否有其他方法来处理 x 和 y?我的实际输入有十几个列,所以使用 colnames 之类的东西会很棒,因为我每次想在 mapply 中使用我的函数时都不需要输入 input$a, input$b, input$c,...跨度>
    • @Alwin 您可以以这样的方式创建函数,即它需要像数据集列这样的单个参数,然后在内部进行处理。可能会更好。
    • +1,因为我没有足够的代表来支持你的答案。如果没有更好的,我会接受它作为正确答案
    • @Alwin 感谢 cmets。
    • 如果可以的话,+10,很好的答案!你至少可以为我节省几个小时的谷歌搜索和反复试验。我已将您的答案标记为已接受的正确答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-29
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 2015-06-29
    • 1970-01-01
    • 2014-08-02
    相关资源
    最近更新 更多