คำตอบนี้จะครอบคลุมองค์ประกอบหลายอย่างเช่นเดียวกับคำตอบที่มีอยู่ แต่ปัญหานี้ (การส่งชื่อคอลัมน์ไปยังฟังก์ชัน) มักเกิดขึ้นมากพอที่ฉันต้องการให้มีคำตอบที่ครอบคลุมสิ่งต่าง ๆ อย่างครอบคลุมมากขึ้นเล็กน้อย
สมมติว่าเรามี data frame ง่ายๆ:
dat <- data.frame(x = 1:4,
y = 5:8)
และเราต้องการเขียนฟังก์ชันที่สร้างคอลัมน์ใหม่z
ซึ่งเป็นผลรวมของคอลัมน์x
และy
.
สิ่งที่ทำให้สะดุดบ่อยมากที่นี่คือความพยายามที่เป็นธรรมชาติ (แต่ไม่ถูกต้อง) มักมีลักษณะดังนี้:
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
นี่คือปัญหาที่ไม่ได้ประเมินการแสดงออกdf$col1
col1
มันก็จะมองหาคอลัมน์ในที่เรียกว่าอักษรdf
col1
ลักษณะการทำงานนี้ได้อธิบายไว้ใน?Extract
ส่วน "วัตถุที่เกิดซ้ำ (เหมือนรายการ)"
วิธีแก้ปัญหาที่ง่ายที่สุดและแนะนำบ่อยที่สุดคือเปลี่ยนจาก$
เป็น[[
และส่งผ่านอาร์กิวเมนต์ของฟังก์ชันเป็นสตริง:
new_column1 <- function(df,col_name,col1,col2){
#Create new column col_name as sum of col1 and col2
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column1(dat,"z","x","y")
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
นี่มักถือเป็น "แนวทางปฏิบัติที่ดีที่สุด" เนื่องจากเป็นวิธีการที่ยากที่สุดในการแก้ไขปัญหา การส่งผ่านชื่อคอลัมน์เป็นสตริงนั้นไม่คลุมเครือเท่าที่คุณจะได้รับ
สองตัวเลือกต่อไปนี้เป็นขั้นสูง แพ็กเกจยอดนิยมจำนวนมากใช้เทคนิคประเภทนี้ แต่การใช้ให้ดีต้องใช้ความระมัดระวังและทักษะมากกว่าเนื่องจากสามารถแนะนำความซับซ้อนที่ละเอียดอ่อนและจุดล้มเหลวที่ไม่คาดคิดได้ ส่วนนี้ของหนังสือ Advanced R ของ Hadley เป็นข้อมูลอ้างอิงที่ดีเยี่ยมสำหรับปัญหาเหล่านี้
หากคุณจริงๆต้องการที่จะบันทึกผู้ใช้จากการพิมพ์คำพูดเหล่านั้นทั้งหมดเป็นทางเลือกหนึ่งอาจจะมีการแปลงเปลือยชื่อคอลัมน์ unquoted สตริงใช้deparse(substitute())
:
new_column2 <- function(df,col_name,col1,col2){
col_name <- deparse(substitute(col_name))
col1 <- deparse(substitute(col1))
col2 <- deparse(substitute(col2))
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column2(dat,z,x,y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
ตรงไปตรงมาอาจเป็นเรื่องโง่เล็กน้อยเนื่องจากเรากำลังทำสิ่งเดียวกันกับในnew_column1
เพียงแค่มีงานพิเศษมากมายในการแปลงชื่อเปล่าเป็นสตริง
ในที่สุดถ้าเราอยากได้แบบแฟนซีจริงๆเราอาจตัดสินใจได้ว่าแทนที่จะส่งชื่อสองคอลัมน์มาเพิ่มเราต้องการที่จะยืดหยุ่นมากขึ้นและอนุญาตให้มีการผสมสองตัวแปรอื่น ๆ ในกรณีนี้เราน่าจะใช้eval()
กับนิพจน์ที่เกี่ยวข้องกับสองคอลัมน์:
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
เพื่อความสนุกสนานฉันยังคงใช้deparse(substitute())
ชื่อคอลัมน์ใหม่ ที่นี่สิ่งต่อไปนี้ทั้งหมดจะใช้ได้:
> new_column3(dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
x y z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
x y z
1 1 5 5
2 2 6 12
3 3 7 21
4 4 8 32
ดังนั้นคำตอบสั้น ๆ คือโดยทั่วไป: ส่งชื่อคอลัมน์ data.frame เป็นสตริงและใช้[[
เพื่อเลือกคอลัมน์เดียว เพียงเริ่มขุดคุ้ยeval
, substitute
ฯลฯ ถ้าคุณรู้ว่าสิ่งที่คุณกำลังทำ