การเขียนฟังก์ชันที่กำหนดเองเพื่อแปลงคลาสของตัวแปรในดาต้าเฟรมโดยยึดตามตารางอื่น

Jan 03 2021

ฉันกำลังพยายามเขียนฟังก์ชันที่สามารถรับ:

  • data frame ( df_1) ซึ่งต้องมีการแปลงคลาสของคอลัมน์
  • data frame อื่น ( 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 ที่นี่ซึ่งดูเหมือนจะใกล้เคียงกับสิ่งที่ฉันพยายามจะบรรลุ

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_namedf_1

ผมจะดีใจสำหรับความคิดใด ๆ ในการสร้างฟังก์ชั่นสำหรับการแปลงdf_1's vars df_2เรียนตามข้อมูลที่พบใน การหาวิธีแก้ปัญหาโดยใช้tidyverseฟังก์ชันจะเหมาะอย่างยิ่ง ขอบคุณ!

คำตอบ

1 IanCampbell Jan 03 2021 at 00:26

นี่คือแนวทางในการใช้ประโยชน์acrossและcur_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_ofdf_2

อาร์กิวเมนต์ที่สองคือฟังก์ชันที่ใช้กับคอลัมน์ที่มีอยู่ คุณสามารถใช้cur_column()เพื่อเข้าถึงชื่อของคอลัมน์ที่กำลังกลายพันธุ์ จากนั้นเราก็ค้นหาชื่อคอลัมน์นั้นdf_2และส่งคืนค่าที่var_classคุณต้องการ จากนั้นใช้get()จากฐาน R (.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  
# ...