การดำเนินงาน data.table ตามชื่อคอลัมน์

2014-01-09 r data.table

สมมติว่าฉันมี data.table

a <- data.table(id=c(1,1,2,2,3),a=21:25,b=11:15,key="id")

ฉันสามารถเพิ่มคอลัมน์ใหม่ดังนี้:

a[, sa := sum(a), by="id"]
a[, sb := sum(b), by="id"]
> a
   id  a  b sa sb
1:  1 21 11 43 23
2:  1 22 12 43 23
3:  2 23 13 47 27
4:  2 24 14 47 27
5:  3 25 15 25 15

อย่างไรก็ตามสมมติว่าฉันมี ชื่อคอลัมน์ แทน:

for (n in c("a","b")) {
  s <- paste0("s",n)
  a[, s := sum(n), by="id", with=FALSE] # ERROR: invalid 'type' (character) of argument
}

ฉันจะทำอย่างไร

Answers

แก้ไข 2020-02-15 เกี่ยวกับ ..

data.table รองรับไวยากรณ์ .. เพื่อ "ค้นหาระดับ" ด้วยการตัดความต้องการ with=FALSE ในกรณีส่วนใหญ่เช่น dt[ , ..n1] และ dt[ , ..n2] ด้านล่าง


ได้ดู with ? data.table :

dt <- data.table(id=1:5,a=21:25,b=11:15,key="id")
dt[, n3 := dt[ , n1, with = FALSE ] * dt[ , n2, with = FALSE ], with = FALSE ]

แก้ไข:

หรือคุณเพียงแค่เปลี่ยนชื่อไปมาและกลับ:

dt <- data.table(id=1:5,a=21:25,b=11:15,key="id")
dt[ , dt.names["n3"] := 1L, with = FALSE ]

dt.names <- c( n1 = "a", n2 = "b", n3 = "c" )
setnames( dt, dt.names, names(dt.names) )

dt[ , n3 := n1 * n2, by = "id" ]
setnames( dt, names(dt.names), dt.names )

ซึ่งทำงานร่วมกับโดย

สิ่งนี้คล้ายกับ:

วิธีการสร้างชุดค่าผสมเชิงเส้นของตัวแปรและตารางการปรับปรุงโดยใช้ data.table ในการโทรแบบวนซ้ำ

แต่คุณต้องการรวมสิ่งนี้ด้วย by= ด้วยดังนั้น set() จึงไม่ยืดหยุ่นพอ นั่นเป็นการออกแบบโดยเจตนาและ set() ซึ่งไม่น่าจะเปลี่ยนแปลงในเรื่องนั้น

บางครั้งฉันใช้ผู้ช่วย EVAL เมื่อสิ้นสุดคำตอบนั้น
https://stackoverflow.com/a/20808573/403310
เสียวสะดุ้งที่วิธีการนั้น แต่ฉันคิดว่ามันเหมือนการสร้างคำสั่ง SQL แบบไดนามิกซึ่งเป็นเรื่องธรรมดา วิธี EVAL ให้ความยืดหยุ่นสูงสุดโดยไม่มีการขีดข่วน EVAL eval() และ quote() หากต้องการดูคิวรีแบบไดนามิกที่สร้างขึ้น (เพื่อตรวจสอบ) คุณสามารถเพิ่มการ print ภายในฟังก์ชันตัวช่วย EVAL ของคุณ

อย่างไรก็ตามในตัวอย่างง่ายๆนี้คุณสามารถ data.table LHS of := ด้วยเครื่องหมายวงเล็บเพื่อบอก data.table เพื่อค้นหาค่า (ชัดเจนกว่า with=FALSE ) และ RHS ต้องการ get()

for (n in c("a","b")) {
  s <- paste0("s",n)
  a[, (s) := sum(get(n)), by="id"]
}

คุณยังสามารถทำสิ่งนี้:

a <- data.table(id=c(1,1,2,2,3),a=21:25,b=11:15,key="id")

a[, c("sa", "sb") := lapply(.SD, sum), by = id]

หรือมากกว่าโดยทั่วไปเล็กน้อย:

cols.to.sum = c("a", "b")
a[, paste0("s", cols.to.sum) := lapply(.SD, sum), by = id, .SDcols = cols.to.sum]

นี่คือวิธีการที่จะทำการโทรและหลีกเลี่ยงโอเวอร์เฮดใด ๆ ด้วย. .SD

# a helper function
makeCall <- function(x,fun) bquote(.(fun)(.(x)))
# the columns you wish to sum (apply function to)
cols <- c('a','b')
new.cols <- paste0('s',cols)
# create named list of names
name.cols <- setNames(sapply(cols,as.name), new.cols)
# create the call
my_call <-  as.call(c(as.name(':='), lapply(name.cols, makeCall, fun = as.name('sum'))))
(a[, eval(my_call), by = 'id'])

#    id  a  b sa sb
# 1:  1 21 11 43 23
# 2:  1 22 12 43 23
# 3:  2 23 13 47 27
# 4:  2 24 14 47 27
# 5:  3 25 15 25 15

Related