[英]How to apply a custom function with multiple parameters to df by factor levels
[英]Apply a custom function over levels of a factor in a dataframe
我正在尝试应用基于 tidyverse 的方法,或者至少是一个整洁的解决方案,以在数据帧中的因子级别上应用自定义函数。
考虑以下测试数据集:
df <- tibble(LINE=rep(c(1,2),each=6), FOUND=c(1,1,1,0,1,1,0,0,1,0,0,1))
# LINE FOUND
# <dbl> <dbl>
# 1 1 1
# 2 1 1
# 3 1 1
# 4 1 0
# 5 1 1
# 6 1 1
# 7 2 0
# 8 2 0
# 9 2 1
#10 2 0
#11 2 0
#12 2 1
例如,我想知道按 LINE 因子级别找到的结果(例如 FOUND==1)的比例。 现在,我正在使用以下代码,但我确实在尝试更简洁的代码。
# This is the function to calculate the proportion "found"
get_prop <- function (data) {
tot <- data %>% nrow()
found <- data %>% dplyr::filter(FOUND==1) %>% nrow
found / tot
}
# This is the code to generate the expected result
lines <- df$LINE %>% unique %>% sort
v_line <- vector()
v_prop <- vector()
for (i in 1:length(lines)) {
tot <- df %>% dplyr::filter(LINE==lines[i])
v_line[i] <- lines[i]
v_prop[i] <- get_prop(tot)
}
df_line = data.frame(LINE = v_line, CALL = v_prop)
我希望以下内容有效,但它没有,因为它返回每个级别的结果,但数值解是整个数据集的结果,而不是特定于级别的:
df %>% dplyr::group_by(LINE) %>% dplyr::summarise(get_prop(.))
编辑:请注意,我正在寻找的是一种解决方案,用于在数据帧中的因子级别上应用自定义函数。 它不一定是特定值出现的次数或比例,如所示示例中所示。
编辑 2 :也就是说,我正在寻找一种使用上面的get_prop
函数的解决方案。 这不是因为它是解决这个特定问题的最佳方法,而是因为它更具有普遍性
如果要按组应用自定义函数,可以使用group_split
命令。 这会将您的数据框拆分为列表的元素。 每个列表元素都是 df 的子集。 然后,您可以使用map
将您的函数应用于每个级别(请注意,您可以使用group_map
一步进行group_split
和map
)。 我添加了最后一行以获得原始方法的形式。
df %>%
group_by(LINE) %>%
group_split() %>%
map_dbl(get_prop) %>%
tibble(LINE = seq_along(.), CALL = .) # optional to get back to a df
#> # A tibble: 2 x 2
#> LINE CALL
#> <int> <dbl>
#> 1 1 0.833
#> 2 2 0.333
由reprex 包(v0.3.0) 创建于 2020-01-20
现在我担心这个解决方案的一件事是group_split
删除分组变量(如果它保留为列表名称或属性,我会更喜欢)。 所以如果你想要一个 tibble 作为结果,预先保存分组变量可能是有意义的:
groups <- unique(df$LINE)
df %>%
group_by(LINE) %>%
group_split() %>%
map_dbl(get_prop) %>%
tibble(group = groups, result = .)
我认为整体最干净的方法是这样的(使用更一般的例子):
library(tidyverse)
df <- tibble(LINE=rep(c("a", "b"),each=6), FOUND=c(1,1,1,0,1,1,0,0,1,0,0,1))
lvls <- unique(df$LINE)
df %>%
group_by(LINE) %>%
group_map(~ get_prop(.x)) %>%
setNames(lvls) %>%
unlist() %>%
enframe()
#> # A tibble: 2 x 2
#> name value
#> <chr> <dbl>
#> 1 a 0.833
#> 2 b 0.333
由reprex 包(v0.3.0) 创建于 2020-01-20
另一种选择是使用group_map
然后使用 tibble tibble::enframe
library(dplyr)
df %>%
group_by(LINE) %>%
group_map(~get_prop(.)) %>%
unlist() %>%
tibble::enframe()
# name value
# <int> <dbl>
#1 1 0.833
#2 2 0.333
您还可以使用group_modify
来保留组名(使用@JBGruber 的数据)
df %>%
group_by(LINE) %>%
group_modify(~ tibble::enframe(get_prop(.), name = NULL))
# LINE value
# <chr> <dbl>
#1 a 0.833
#2 b 0.333
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.