【问题标题】:Apply a custom function over levels of a factor in a dataframe在数据框中的因子级别上应用自定义函数
【发布时间】:2020-01-20 14:32:05
【问题描述】:

我正在尝试应用基于 tidyverse 的方法,或者至少是一个 tidy 解决方案,以便在数据帧中的因子级别上应用自定义函数。

考虑以下测试数据集:

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(.))

编辑:请注意,我正在寻找的解决方案是在数据框中的某个因子的级别上应用 自定义函数。它不一定是特定值出现的次数或比例,如示例所示。

EDIT 2:也就是说,我正在寻找一种利用上述get_prop 函数的解决方案。这并不是因为它是解决这个特定问题的最佳方法,而是因为它更具有普遍性

【问题讨论】:

    标签: r


    【解决方案1】:

    如果您想按组应用自定义函数,可以使用group_split 命令。这会将您的数据框拆分为列表的元素。每个列表元素都是 df 的子集。然后您可以使用map 将您的功能应用到每个级别(请注意,您可以使用group_map 一步完成group_splitmap)。我添加了最后一行以获得原始方法的形式。

    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 package (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 package (v0.3.0) 于 2020-01-20 创建

    【讨论】:

    • 请注意我已经编辑了这个问题,所以更清楚的是我正在寻找的是一种按因子级别调用通用或自定义函数的方法,而不一定要计算比例。
    • 啊,我明白了。我以为您只是想要从该功能中获得的结果。它必须是问题中的确切 get_prop 函数吗?
    • 最好是。这样,解决方案将更容易推广到任何自定义函数
    • 再看看。我想这应该是你想要的。
    • 我正要问关于分组变量名的问题!感谢您的编辑
    【解决方案2】:

    另一种选择是使用group_map,然后使用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
    

    【讨论】:

      猜你喜欢
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 2014-02-11
      • 1970-01-01
      • 2018-03-13
      • 2022-01-20
      • 2018-11-04
      • 1970-01-01
      相关资源
      最近更新 更多