【问题标题】:How to apply a list of functions using tidyverse and get back a column for each function applied如何使用 tidyverse 应用函数列表并为每个应用的函数取回一列
【发布时间】:2021-02-03 18:51:13
【问题描述】:

我正在尝试将多个函数应用于数据集中的每一列,并为每个计算的函数取回一列,然后这些行将对应于计算它的列。所以在下面的代码中,有 3 个 ID。然后我计算每个函数的三个函数,因此最终的数据框将有 3 行和 3 列。现在,行对应于计算函数的 Id,列对应于计算的内容。我对其他解决方案持开放态度,但更喜欢 tidyverse 解决方案,因为我需要它可以推广到很多功能并且仍然很快。

预期的输出在 end.data 中

data <- data.frame(id1 = 1:10,id2 = 1:10,id3 = 1:10)
data

end.data <- data.frame(innprod = c(385,385,385),identity = c(55,55,55) , range = c(9,9,9))
end.data

我尝试合并并汇总计算,但它在各自的列中返回每个。

data <- data.frame(id1 = 1:10,id2 = 1:10,id3 = 1:10)
map.fun <- list(
  innprod = ~ t(.x)%*%.x, 
  identity = ~ sum(.x),
  range = ~ max(.x) - min(.x)
)
feat_m <-      data %>%  summarise(across(where(is.numeric),map.fun))
feat_m

【问题讨论】:

  • 预期输出在 end.data 中。将编辑问题以明确说明

标签: r dplyr tidyverse tidyr data-manipulation


【解决方案1】:

我们可以重塑为“长”格式,然后作为函数应用

library(dplyr)
library(tidyr)
map.fun <- function(.x) list(
  innprod =  as.numeric(t(.x)%*%.x), 
 identity =  sum(.x),
 range =  max(.x) - min(.x)
)

data %>% 
       select(where(is.numeric)) %>% 
       pivot_longer(everything()) %>% 
       group_by(name) %>% 
       summarise(value = list(map.fun(value)), .groups = 'drop') %>% 
       unnest_wider(c(value))

-输出

# A tibble: 3 x 4
#  name  innprod identity range
#  <chr>   <dbl>    <int> <int>
#1 id1       385       55     9
#2 id2       385       55     9
#3 id3       385       55     9

【讨论】:

  • 有趣。我没有想过改变当前的格式。聪明的!谢谢!!
【解决方案2】:

Base R 替代方案,本质上是一个隐藏的双循环。仍然可以根据要求推广到许多功能:

funs <-  c(
  innprod  = function(x) c(t(x) %*% x),
  identity = sum,
  range    = function(x) diff(range(x))
)
sapply(funs, function(f) sapply(data, function(d) f(d)) )

#    innprod identity range
#id1     385       55     9
#id2     385       55     9
#id3     385       55     9

【讨论】:

    【解决方案3】:

    map.fun 的函数返回inprod 的矩阵,我们首先需要将其转换为向量,就像其余元素一样。

    map.fun <- list(
      innprod = ~ c(t(.x)%*%.x), 
      identity = ~ sum(.x),
      range = ~ max(.x) - min(.x)
    )
    

    完成此操作后,您可以使用summarise + across 将该函数应用于每个数字列。如果您希望将每个值放在单独的列中,则可以在带有 names_sep 参数的汇总数据上使用 pivot_longer

    library(dplyr)
    
    data %>%  
      summarise(across(where(is.numeric),map.fun)) %>%
      tidyr::pivot_longer(cols = where(is.numeric), 
                   names_to = c('id', '.value'), 
                   names_sep = '_') 
    
    #   id    innprod identity range
    #  <chr>   <dbl>    <int> <int>
    #1 id1       385       55     9
    #2 id2       385       55     9
    #3 id3       385       55     9
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-08
      • 2012-05-12
      • 2021-09-23
      相关资源
      最近更新 更多