簡體   English   中英

如何從R中的自定義函數向數據框添加多個列

[英]How to add multiple columns to a dataframe from a custom function in R

我創建了一個代碼,它將采用輸入向量,根據輸入創建數據幀,優化一些值並返回其中一些值。 我現在把它變成一個函數,它將在輸入數據幀上按行計算。 下面是我想要實現的最小工作示例(我的實際功能在這里分享的時間太長了!):

# 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向量。 我已經看過SO,但我還沒有找到答案。 我認為解決方案是使用其中一個apply函數而不是dplyr ,但我老實說從來沒有完全理解apply函數。 我也不會喜歡使用的解決方案for以循環rbind正如我在以前的項目嘗試這樣做,對於大dataframes就變得非常慢!

我們可以使用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)))

或者正如我們在評論中討論的那樣,不是讓函數采用多個參數,而是使用單個參數並使用apply with MARGIN=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設置任何種子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM