การใช้การประเมินที่ไม่ได้มาตรฐานตามระเบียบในการถอดรหัสในด้านขวามือของการกลายพันธุ์


13

ลองพิจารณาดูซิว่าแต่ละคอลัมน์เป็นเวกเตอร์ของตัวละครที่สามารถมีค่าได้มากมายสมมติว่า "A" ถึง "F"

library(tidyverse)
sample_df <- tibble(q1 = c("A", "B", "C"), q2 = c("B", "B", "A"))

ฉันต้องการสร้างฟังก์ชั่นที่ใช้ชื่อคอลัมน์เป็นอาร์กิวเมนต์และ recodes คอลัมน์นั้นเพื่อให้คำตอบ "A" ใด ๆ กลายเป็น NA และ df จะถูกส่งกลับตามที่เป็นอยู่ เหตุผลในการออกแบบด้วยวิธีนี้คือเพื่อให้พอดีกับไปป์ไลน์ที่กว้างขึ้นที่ดำเนินการชุดของการดำเนินงานโดยใช้คอลัมน์ที่กำหนด

มีหลายวิธีในการทำเช่นนี้ แต่ฉันสนใจที่จะเข้าใจว่าวิธีที่ดีที่สุดในการใช้สำนวน tidy_eval / tidyverse อันดับแรกชื่อคำถามต้องอยู่ทางด้านซ้ายของกริยากลายพันธุ์ดังนั้นเราจึงใช้!!และ:=ตัวดำเนินการอย่างเหมาะสม แต่แล้วจะวางอะไรไว้ทางด้านขวามือ?

fix_question <- function(df, question) {
    df %>% mutate(!!question := recode(... something goes here...))
}

fix_question(sample_df, "q1") # should produce a tibble whose first column is (NA, "B", "C")

ความคิดเริ่มต้นของฉันคือการทำงานนี้:

df %>% mutate(!!question := recode(!!question, "A" = NA_character_))

แต่แน่นอนปังปังในฟังก์ชั่นเพียงแค่ส่งกลับสตริงตัวอักษร (เช่น "q1") ฉันลงเอยด้วยการใช้เส้นทางที่แฮ็คเพื่ออ้างอิงข้อมูลทางด้านขวาใช้ตัวดำเนินการฐาน R [[และอาศัย.โครงสร้างจาก dplyr และใช้งานได้ดังนั้นในความรู้สึกฉันได้แก้ไขปัญหาพื้นฐานของฉันแล้ว:

df %>% mutate(!!question := recode(.[[question]], "A" = NA_character_))

ฉันสนใจที่จะรับข้อเสนอแนะจากผู้ที่มีความเชี่ยวชาญในเรื่อง tidyeval มากว่าจะมีวิธีการทำแบบนี้หรือเปล่าโดยหวังว่าการดูตัวอย่างการทำงานจะช่วยเพิ่มความเข้าใจของฉันเกี่ยวกับฟังก์ชัน tidyeval ที่ตั้งโดยทั่วไป ความคิดใด ๆ


ขอบคุณนี่เป็นวิธีที่ฉลาด - ฉันใช้วิธีการทำงานในส่วนอื่น ๆ ในรหัสของฉันและอาจมีความคิดเกี่ยวกับการทำที่นี่เช่นกัน ฉันรู้ว่าบางคนขมวดคิ้วในสไตล์การพูดคุยเกี่ยวกับ SO แต่การเห็นรูปแบบที่แตกต่างกันของคำตอบอย่างรวดเร็วนั้นได้ผลมากสำหรับฉัน
แอรอน

1
การรวมแนวคิดหลายอย่างในคำถามนี้ฉันเชื่อว่านี่เป็นรุ่นรวบรัดที่สุดที่ใช้ได้กับทั้งq1(สัญลักษณ์) และ"q1"(สตริง):df %>% mutate_at( vars(!!ensym(question)), recode, A = NA_character_)
Artem Sokolov

คำตอบ:


6

ที่นี่ทางด้านขวาของ:=เราสามารถระบุsymให้แปลงเป็นสัญลักษณ์แล้วประเมิน ( !!)

fix_question <- function(df, question) {
    df %>%
       mutate(!!question := recode(!! rlang::sym(question), "A" = NA_character_))
  }

fix_question(sample_df, "q1") 
# A tibble: 3 x 2
#  q1    q2   
#  <chr> <chr>
#1 <NA>  B    
#2 B     B    
#3 C     A    

วิธีที่ดีกว่าที่จะใช้งานได้กับทั้งอินพุตและเครื่องหมายอัญประกาศคือ ensym

fix_question <- function(df, question) {
    question <- ensym(question)
    df %>%
       mutate(!!question := recode(!! question, "A" = NA_character_))
  }


fix_question(sample_df, q1)
# A tibble: 3 x 2
#  q1    q2   
#  <chr> <chr>
#1 <NA>  B    
#2 B     B    
#3 C     A    

fix_question(sample_df, "q1")
# A tibble: 3 x 2
#  q1    q2   
#  <chr> <chr>
#1 <NA>  B    
#2 B     B    
#3 C     A    

2
ฉันได้ลองใช้ฟังก์ชั่นการแปลง rlang สองสามอัน แต่เห็นได้ชัดว่าไม่ได้เลือกที่ถูกต้อง แต่วิธีการของคุณใช้งานได้ - ฉันคิดว่าจริง ๆ แล้วฉันแค่ต้องการเวิร์กโฟลว์การแปลงประเภทในหัวของฉัน คำถามของฉัน !! ไม่ทำงานเพราะมันประเมินสตริงตัวอักษรอย่างแท้จริง ของคุณทำงานได้เพราะมันจะแปลงสตริงอักขระเป็นสัญลักษณ์ก่อนจากนั้นประเมินสัญลักษณ์แล้วคืนค่าเวกเตอร์ ฉันไม่สามารถห่อหัวของฉันนั่นคือคำสั่งของการดำเนินการ ขอบคุณอีกครั้ง.
แอรอน

8

คุณสามารถใช้ "หยิกหยิก" วิธีการตอนนี้ถ้าคุณมีrlang> = 0.4.0

คำอธิบายต้องขอบคุณ @ eipi10:

สิ่งนี้รวมกระบวนการสองขั้นตอนของอัญประกาศแล้วไม่พูดถึงในขั้นตอนเดียวดังนั้นจึง{{question}}เทียบเท่า!!enquo(question)

fix_question <- function(df, question){
  df %>% mutate({{question}} := recode({{question}}, A = NA_character_))
}

fix_question(sample_df, q1)
# # A tibble: 3 x 2
#   q1    q2   
#   <chr> <chr>
# 1 NA    B    
# 2 B     B    
# 3 C     A    

โปรดทราบว่าensymวิธีนี้ไม่สามารถใช้ได้กับชื่อตัวละคร ยิ่งแย่ไปกว่านั้นมันทำสิ่งที่ผิดแทนที่จะให้แค่ข้อผิดพลาด

fix_question(sample_df, 'q1')

# # A tibble: 3 x 2
#   q1    q2   
#   <chr> <chr>
# 1 q1    B    
# 2 q1    B    
# 3 q1    A    

2
ฉันยังไม่ได้เข้าสู่นิสัย "ลอนหยิก" เลย คุณรู้ไหมว่าทำไมสิ่งนี้ถึงได้ผลในขณะที่รุ่น "bang bang" ที่ดูเหมือนจะไม่เหมือนกัน
คามิลล์

ขอบคุณที่พูดถึงหยิกหยักศกซึ่งฉันได้ยินมาว่ากำลังจะเกิดขึ้น คำตอบไม่ทำงานสำหรับรุ่นใด ๆ ของ rlang / dplyr ฉันได้ติดตั้ง; ฉันพบข้อผิดพลาดกับ LHS ถ้าฉันแทนที่ LHS ด้วย LHS ของฉันและเสนอราคา q1 ฉันจะได้รับปัญหาเดียวกันกับที่ฉันได้กล่าวไว้ข้างต้น ถ้าฉันไม่พูด q1 ฉันได้รับข้อผิดพลาด นี่อาจเป็นสิ่งที่รุ่น
แอรอน

1
ใช่แล้ว rlang 0.4.0 เพิ่งเปิดตัวเมื่อสิ้นเดือนมิถุนายนดังนั้นหากคุณยังไม่ได้อัปเดตตั้งแต่นั้นมาสิ่งนี้จะไม่ทำงานสำหรับคุณ
IceCreamToucan

2
ฉันคิดว่าบางปังไม่ทำงานเพราะquestionก่อนอื่นจะต้องกลายเป็น quosure ( question = enquo(question)) ก่อนที่จะถูกนำมาใช้ในท่อ dplyr เทียบเท่ากับ{{question}} !!enquo(question)
eipi10

2
คุณต้องการ enquo สำหรับคำถามแรกเช่นกันเพื่อที่จะเทียบเท่า
IceCreamToucan

7

คุณสามารถทำให้ฟังก์ชั่นมีความยืดหยุ่นเพิ่มขึ้นอีกนิดโดยอนุญาตให้เวกเตอร์ของค่าที่ถูกเข้ารหัสสามารถป้อนเป็นอาร์กิวเมนต์ได้เช่นกัน ตัวอย่างเช่น:

library(tidyverse)
sample_df <- tibble(q1 = c("A", "B", "C"), q2 = c("B", "B", "A"))

fix_question <- function(df, question, recode.vec) {

  df %>% mutate({{question}} := recode({{question}}, !!!recode.vec))

}

fix_question(sample_df, q1, c(A=NA_character_, B="Was B"))
  q1    q2   
1 <NA>  B    
2 Was B B    
3 C     A

โปรดทราบว่าrecode.vecคือ "ได้นำมาอ้าง-แต่งงาน" !!!กับ คุณสามารถดูสิ่งที่กำลังทำกับตัวอย่างนี้ดัดแปลงจากการเขียนโปรแกรมด้วยบทความสั้น ๆ (ค้นหา "splice" เพื่อดูตัวอย่างที่เกี่ยวข้อง) หมายเหตุว่า!!!"splices" คู่ recoding ค่าลงในrecodeฟังก์ชั่นเพื่อที่พวกเขาจะใช้เป็นข้อโต้แย้งใน...recode

x = c("A", "B", "C")
args = c(A=NA_character_, B="Was B")

quo(recode(x, !!!args))

<quosure>
expr: ^recode(x, A = <chr: NA>, B = "Was B")
env:  global

หากคุณต้องการเรียกใช้ฟังก์ชั่นการเขียนรหัสซ้ำในหลายคอลัมน์คุณสามารถเปลี่ยนเป็นฟังก์ชั่นที่ใช้เพียงชื่อคอลัมน์และเวกเตอร์การเข้ารหัส วิธีนี้ดูเหมือนว่าจะเป็นมิตรกับท่อมากขึ้น

fix_question <- function(question, recode.vec) {

  recode({{question}}, !!!recode.vec)

}

sample_df %>% 
  mutate_at(vars(matches("q")), list(~fix_question(., c(A=NA_character_, B="Was B"))))
  q1    q2   
1 <NA>  Was B
2 Was B Was B
3 C     <NA>

หรือเพื่อบันทึกคอลัมน์เดียว:

sample_df %>% 
  mutate(q1 = fix_question(q1, c(A=NA_character_, B="Was B")))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.