【问题标题】:Writing a custom function to convert class of variables in a dataframe based on another table编写自定义函数以基于另一个表转换数据框中的变量类
【发布时间】:2021-01-02 16:46:07
【问题描述】:

我正在尝试编写一个可以接收的函数:

  • 需要转换其列类的数据框(df_1
  • 另一个数据框 (df_2),对于 df_1 的每个变量都有一个
  • df_2 中的一列指定df_1 中的每个变量应转换为的类

示例

1 -- 带有我的数据(以及要转换的变量类)的数据框 (df_1)

library(tibble)
library(dplyr)

set.seed(2021)

df_1 <-
  tibble(name = c("john", "jack", "mary", "matt", "elizabeth", "richard", "carlos", "george", "ferdinand", "william"), 
       height = sample(155:200, size = 10),
       weight = sample(50:100, size = 10),
       age = sample(20:100, size = 10),
       gender = sample(c("male", "female"), size = 10, replace = TRUE),
       preferred_pet = sample(c("dog", "cat", "frog", "rabbit"), size= 10, replace = TRUE)) %>%
  mutate(across(everything(), as.character))

## # A tibble: 10 x 6
##    name      height weight age   gender preferred_pet
##    <chr>     <chr>  <chr>  <chr> <chr>  <chr>        
##  1 john      161    100    38    female frog         
##  2 jack      192    67     87    female dog          
##  3 mary      193    52     24    male   rabbit       
##  4 matt      166    95     92    male   dog          
##  5 elizabeth 160    89     82    female cat          
##  6 richard   199    75     57    male   dog          
##  7 carlos    195    85     37    female rabbit       
##  8 george    159    86     62    male   rabbit       
##  9 ferdinand 177    71     78    female cat          
## 10 william   197    80     89    female rabbit 

2 -- 数据框 (df_2) 包含将 df_1 列转换为的类

set.seed(2021)

df_2 <-
  tibble(var_name =  c("name", "height", "weight", "gender", "preferred_pet", "record_creation"),
         var_class = c("character", "numeric", "numeric", "factor", "factor", "datetime")) %>%
  slice(sample(1:n()))

## # A tibble: 6 x 2
##   var_name        var_class
##   <chr>           <chr>    
## 1 weight          numeric  
## 2 record_creation datetime 
## 3 height          numeric  
## 4 name            character
## 5 gender          factor   
## 6 preferred_pet   factor 

3 -- 构建类转换函数

我已经看到@akrun 的解决方案here,这似乎与我想要实现的目标非常接近。

library(purrr)
library(stringr)

my_df <- iris
my_types <- c("factor", "character", "double", "logical", "character")
my_df[] <- map2(my_df, str_c("as.", my_types), ~ get(.y)(.x))

但是,此解决方案无法解决像我这样的情况,其中 df_1 的变量名不一定出现在 df_2 中,同样,df_2$var_name 包括不一定出现在 df_1 中的变量.

如果有任何想法可以根据df_2 中的信息构建用于转换df_1 的vars 类的函数,我将很高兴。使用tidyverse 函数找到解决方案将是理想的。 谢谢!

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    这是一种利用acrosscur_column 的方法:

    library(dplyr) #version >= 1.0.0
    df_1 %>% 
      mutate(across(any_of(df_2$var_name), 
                    ~get(paste0("as.",df_2[df_2$var_name == cur_column(),"var_class"]))(.x)))
    # A tibble: 10 x 6
       name      height weight age   gender preferred_pet
       <chr>      <dbl>  <dbl> <chr> <fct>  <fct>        
     1 john         161    100 38    female frog         
     2 jack         192     67 87    female dog          
     3 mary         193     52 24    male   rabbit       
     4 matt         166     95 92    male   dog          
     5 elizabeth    160     89 82    female cat          
     6 richard      199     75 57    male   dog          
     7 carlos       195     85 37    female rabbit       
     8 george       159     86 62    male   rabbit       
     9 ferdinand    177     71 78    female cat          
    10 william      197     80 89    female rabbit 
    

    any_of 选择助手可确保您仅尝试更改 df_2 中存在的列。

    第二个参数是应用于现有列的函数。您可以使用cur_column() 来访问正在变异的列的名称。从那里,我们只需在 df_2 中查找该列名称并返回您想要的 var_class。然后使用基础 R 中的 get() 返回适当的函数并将其应用于具有 (.x) 的列。

    如果你想定义一个函数,并像使用其他 tidyverse 函数一样传递不带引号的列名,你可以使用rlang::enquo

    library(rlang)
    change_class_by_table <- function(data,data_ref,column_name,column_class){
    data %>% 
      mutate(across(any_of(pull(data_ref,!!enquo(column_name))), 
                    ~get(paste0("as.",filter(data_ref, !!enquo(column_name) == cur_column()) %>%
                                        pull(!!enquo(column_class))))(.x)))
    }
    change_class_by_table(df_1,df_2,var_name,var_class)
    ## A tibble: 10 x 6
    #   name      height weight age   gender preferred_pet
    #   <chr>      <dbl>  <dbl> <chr> <fct>  <fct>        
    # 1 john         161    100 38    female frog         
    # 2 jack         192     67 87    female dog          
    # 3 mary         193     52 24    male   rabbit  
    # ...
    

    【讨论】:

    • 查看编辑以了解如何使用不带引号的列名
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 2011-04-13
    相关资源
    最近更新 更多