【问题标题】:Apply different functions to columns of a dataframe selecting functions by name将不同的函数应用于按名称选择函数的数据框的列
【发布时间】:2022-01-21 09:31:29
【问题描述】:

假设我有一个包含多个列的数据框,其中一些我想要转换。列名定义了需要使用的转换。

library(tidyverse)
set.seed(42)
df <- data.frame(A = 1:100, B = runif(n = 100, 0, 1), log10 = runif(n = 100, 10, 100), log2 = runif(n = 100, 10, 100), log1p = runif(n = 100, 10, 100), sqrt = runif(n = 100, 10, 100))
trans <- list()
trans$log10 <- log10
trans$log2 <- log2
trans$log1p <- log1p
trans$sqrt <- sqrt

理想情况下,我想使用 across 调用,其中列名与 trans 函数名匹配,并且转换将即时执行。 所需的输出如下:

df_trans <- df %>% 
  dplyr::mutate(log10 = trans$log10(log10),
                log2 = trans$log2(log2),
                log1p = trans$log1p(log1p),
                sqrt = trans$sqrt(sqrt))
df_trans

但是,我不想单独手动指定每个转换。在代表性示例中,我只有 4 个,但这个数字可能会有所不同,而且会显着增加,这使得手动规范变得繁琐且容易出错。

我已设法通过将 trans 列表转换为数据框并左连接来将列名与函数匹配,但随后无法调用 trans_function 列中的函数。

trans_df <- enframe(trans, value = "trans_function")
df %>% 
  pivot_longer(cols = everything()) %>% 
  left_join(trans_df) %>% 
  dplyr::mutate(value = trans_function(value))

错误:mutate()value 出现问题。
value = trans_function(value).
x 找不到函数“trans_function”

我想我要么需要找到一种从列表列中调用函数的方法,要么需要找到另一种将函数名与列名匹配的方法。欢迎所有想法。

【问题讨论】:

    标签: r dplyr apply


    【解决方案1】:

    另一种可能性如下:

    library(tidyverse)
    set.seed(42)
    df <- data.frame(A = 1:100, B = runif(n = 100, 0, 1), log10 = runif(n = 100, 10, 100), log2 = runif(n = 100, 10, 100), log1p = runif(n = 100, 10, 100), sqrt = runif(n = 100, 10, 100))
    
    df %>% 
      mutate(across(-(A:B), ~ getFunction(cur_column())(.x))) %>% head
    
    #>   A         B    log10     log2    log1p     sqrt
    #> 1 1 0.9148060 1.821920 6.486402 3.998918 3.470303
    #> 2 2 0.9370754 1.470472 5.821200 3.932046 7.496103
    #> 3 3 0.2861395 1.469690 6.437524 2.799395 8.171007
    #> 4 4 0.8304476 1.653261 5.639570 3.700698 6.905755
    #> 5 5 0.6417455 1.976905 4.597484 4.500461 9.441077
    #> 6 6 0.5190959 1.985133 5.638341 4.551289 4.440590
    

    【讨论】:

      【解决方案2】:

      base R,我们可以使用Map

      df[names(trans)] <- Map(function(x, y) x(y), trans, df[names(trans)])
      

      -检查

      > identical(df, df_trans)
      [1] TRUE
      

      【讨论】:

        【解决方案3】:

        我们可以在across 中使用cur_column() 来获取列名并将其用于子集trans

        library(dplyr)
        
        df %>%
          mutate(across(names(trans), ~trans[[cur_column()]](.x))) %>%
          head
        
        #  A         B    log10     log2    log1p     sqrt
        #1 1 0.9148060 1.821920 6.486402 3.998918 3.470303
        #2 2 0.9370754 1.470472 5.821200 3.932046 7.496103
        #3 3 0.2861395 1.469690 6.437524 2.799395 8.171007
        #4 4 0.8304476 1.653261 5.639570 3.700698 6.905755
        #5 5 0.6417455 1.976905 4.597484 4.500461 9.441077
        #6 6 0.5190959 1.985133 5.638341 4.551289 4.440590
        

        将其与df_trans 的输出进行比较。

        head(df_trans)
        
        #  A         B    log10     log2    log1p     sqrt
        #1 1 0.9148060 1.821920 6.486402 3.998918 3.470303
        #2 2 0.9370754 1.470472 5.821200 3.932046 7.496103
        #3 3 0.2861395 1.469690 6.437524 2.799395 8.171007
        #4 4 0.8304476 1.653261 5.639570 3.700698 6.905755
        #5 5 0.6417455 1.976905 4.597484 4.500461 9.441077
        #6 6 0.5190959 1.985133 5.638341 4.551289 4.440590
        

        【讨论】:

          【解决方案4】:

          一种方法是使用 lapply:

          library(tidyverse)
          set.seed(42)
          
          df <- data.frame(A = 1:100, B = runif(n = 100, 0, 1), log10 = runif(n = 100, 10, 100), log2 = runif(n = 100, 10, 100), log1p = runif(n = 100, 10, 100), sqrt = runif(n = 100, 10, 100))
          trans <- list()
          trans$log10 <- log10
          trans$log2 <- log2
          trans$log1p <- log1p
          trans$sqrt <- sqrt
          
          
          df_trans <- setNames(lapply(names(df),
                      function(x) if(x %in% names(trans))
                      { trans[[x]](df[,(x)])} else {df[,x]}),names(df)) %>% 
            bind_cols() %>% 
            as.data.frame() 
          
          head(df_trans)
          

          给出:

            A         B    log10     log2    log1p     sqrt
            1 1 0.1365052 1.739051 6.301896 4.530600 4.318942
            2 2 0.1771364 1.549601 5.793220 4.521715 3.649834
            3 3 0.5195605 1.902438 4.819125 3.343266 6.788565
            4 4 0.8111208 1.572253 6.219991 4.075945 3.322401
            5 5 0.1153620 1.751276 6.306097 4.060292 7.817301
            6 6 0.8934218 1.724403 6.201123 3.235938 9.749128
          

          原始数据框为:

          head(df)
            A         B    log10     log2    log1p     sqrt
            1 1 0.1365052 54.83409 78.89684 91.81428 18.65326
            2 2 0.1771364 35.44878 55.45401 90.99323 13.32129
            3 3 0.5195605 79.88006 28.22936 27.31143 46.08461
            4 4 0.8111208 37.34675 74.54249 57.90612 11.03835
            5 5 0.1153620 56.39961 79.12693 56.99123 61.11019
            6 6 0.8934218 53.01557 73.57393 24.43022 95.04549
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-03-20
            • 2016-10-13
            • 1970-01-01
            • 2020-03-23
            • 2019-06-01
            • 1970-01-01
            相关资源
            最近更新 更多