按组在R中的数据框上运行自定义函数

Bil*_*tti 9 aggregate r function dplyr

在使用自定义函数循环数据框中的组时遇到一些麻烦.

以下是一些示例数据:

set.seed(42)
tm <- as.numeric(c("1", "2", "3", "3", "2", "1", "2", "3", "1", "1"))
d <- as.numeric(sample(0:2, size = 10, replace = TRUE))
t <- as.numeric(sample(0:2, size = 10, replace = TRUE))
h <- as.numeric(sample(0:2, size = 10, replace = TRUE))

df <- as.data.frame(cbind(tm, d, t, h))
df$p <- rowSums(df[2:4])
Run Code Online (Sandbox Code Playgroud)

我创建了一个自定义函数来计算值w:

calc <- function(x) {
  data <- x
  w <- (1.27*sum(data$d) + 1.62*sum(data$t) + 2.10*sum(data$h)) / sum(data$p)
  w
  }
Run Code Online (Sandbox Code Playgroud)

当我在整个数据集上运行该函数时,我得到以下答案:

calc(df)
[1]1.664474
Run Code Online (Sandbox Code Playgroud)

理想情况下,我想返回按tm分组的结果,例如:

tm     w
1    result of calc
2    result of calc
3    result of calc
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已尝试使用aggregate我的函数,但我收到以下错误:

aggregate(df, by = list(tm), FUN = calc)
Error in data$d : $ operator is invalid for atomic vectors
Run Code Online (Sandbox Code Playgroud)

我觉得我已经盯着这个太久了,而且有一个明显的答案.任何意见,将不胜感激.

Col*_*vel 13

你可以尝试split:

sapply(split(df, tm), calc)

#       1        2        3 
#1.665882 1.504545 1.838000 
Run Code Online (Sandbox Code Playgroud)

如果你想要一个清单lapply(split(df, tm), calc).

或者data.table:

library(data.table)

setDT(df)[,calc(.SD),tm]
#   tm       V1
#1:  1 1.665882
#2:  2 1.504545
#3:  3 1.838000
Run Code Online (Sandbox Code Playgroud)


akr*_*run 11

运用 dplyr

library(dplyr)
df %>% 
   group_by(tm) %>%
   do(data.frame(val=calc(.)))
#  tm      val
#1  1 1.665882
#2  2 1.504545
#3  3 1.838000
Run Code Online (Sandbox Code Playgroud)

如果我们稍微改变函数以包含多个参数,这也可以使用 summarise

 calc1 <- function(d1, t1, h1, p1){
      (1.27*sum(d1) + 1.62*sum(t1) + 2.10*sum(h1) )/sum(p1) }
 df %>%
     group_by(tm) %>% 
     summarise(val=calc1(d, t, h, p))
 #  tm      val
 #1  1 1.665882
 #2  2 1.504545
 #3  3 1.838000
Run Code Online (Sandbox Code Playgroud)


Moo*_*per 5

dplyr 0.8开始你可以使用group_map

library(dplyr)
df %>% group_by(tm) %>% group_map(~tibble(w=calc(.)))
#> # A tibble: 3 x 2
#> # Groups:   tm [3]
#>      tm     w
#>   <dbl> <dbl>
#> 1     1  1.67
#> 2     2  1.50
#> 3     3  1.84
Run Code Online (Sandbox Code Playgroud)