ไม่มีคำตอบที่ตรงไปตรงมา / เรียบง่ายเนื่องจากปรัชญาของแพ็คเกจทั้งสองนี้แตกต่างกันในบางแง่มุม ดังนั้นการประนีประนอมบางอย่างจึงหลีกเลี่ยงไม่ได้ นี่คือข้อกังวลบางประการที่คุณอาจต้องจัดการ / พิจารณา
การดำเนินการที่เกี่ยวข้องกับi
(== filter()
และslice()
ใน dplyr)
สมมติDT
ว่าพูด 10 คอลัมน์ พิจารณานิพจน์ data.table เหล่านี้:
DT[a > 1, .N]
DT[a > 1, mean(b), by=.(c, d)]
(1) ให้จำนวนแถวในที่คอลัมน์DT
a > 1
(2) ส่งคืนที่mean(b)
จัดกลุ่มโดยc,d
สำหรับนิพจน์เดียวกันในi
(1)
dplyr
นิพจน์ที่ใช้โดยทั่วไปจะเป็น:
DT %>% filter(a > 1) %>% summarise(n())
DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b))
เห็นได้ชัดว่ารหัส data.table นั้นสั้นกว่า นอกจากนี้ยังมีหน่วยความจำที่มีประสิทธิภาพมากขึ้น1 . ทำไม? เนื่องจากในทั้ง (3) และ (4) filter()
จะส่งคืนแถวสำหรับคอลัมน์ทั้ง 10 คอลัมน์ก่อนเมื่ออยู่ใน (3) เราต้องการจำนวนแถวและใน (4) เราต้องการเพียงแค่คอลัมน์b, c, d
สำหรับการดำเนินการต่อเนื่อง เพื่อเอาชนะสิ่งนี้เราต้องselect()
คอลัมน์ apriori:
DT %>% select(a) %>% filter(a > 1) %>% summarise(n())
DT %>% select(a,b,c,d) %>% filter(a > 1) %>% group_by(c,d) %>% summarise(mean(b))
สิ่งสำคัญคือต้องเน้นความแตกต่างทางปรัชญาที่สำคัญระหว่างสองแพ็คเกจ:
ในdata.table
เราต้องการให้การดำเนินการที่เกี่ยวข้องเหล่านี้เข้าด้วยกันและทำให้สามารถดูj-expression
(จากการเรียกใช้ฟังก์ชันเดียวกัน) และตระหนักว่าไม่จำเป็นต้องมีคอลัมน์ใด ๆ ใน (1) นิพจน์ในi
ได้รับการคำนวณและ.N
เป็นเพียงผลรวมของเวกเตอร์ตรรกะที่ให้จำนวนแถว ส่วนย่อยทั้งหมดไม่เคยรับรู้ ใน (2) มีเพียงคอลัมน์b,c,d
ที่ปรากฏในชุดย่อยส่วนคอลัมน์อื่น ๆ จะถูกละเว้น
แต่ในdplyr
ปรัชญาคือการมีฟังก์ชั่นได้อย่างแม่นยำทำสิ่งหนึ่งที่ดี ไม่มีทาง (อย่างน้อยในปัจจุบัน) ที่จะบอกได้ว่าการดำเนินการหลังจากนั้นfilter()
ต้องการคอลัมน์ทั้งหมดที่เรากรองหรือไม่ คุณจะต้องคิดล่วงหน้าหากคุณต้องการทำงานดังกล่าวอย่างมีประสิทธิภาพ โดยส่วนตัวแล้วฉันพบว่ามันขัดแย้งในกรณีนี้
โปรดทราบว่าใน (5) และ (6) เรายังคงเป็นคอลัมน์ย่อยa
ที่เราไม่ต้องการ แต่ฉันไม่แน่ใจว่าจะหลีกเลี่ยงสิ่งนั้นได้อย่างไร หากfilter()
ฟังก์ชันมีอาร์กิวเมนต์เพื่อเลือกคอลัมน์ที่จะส่งคืนเราสามารถหลีกเลี่ยงปัญหานี้ได้ แต่ฟังก์ชันจะไม่ทำงานเพียงงานเดียว (ซึ่งเป็นตัวเลือกการออกแบบ dplyr ด้วย)
มอบหมายย่อยโดยการอ้างอิง
dplyr จะไม่อัปเดตโดยอ้างอิง นี่เป็นอีกหนึ่งความแตกต่างที่ยิ่งใหญ่ (เชิงปรัชญา) ระหว่างสองแพ็คเกจ
ตัวอย่างเช่นใน data.table คุณสามารถทำได้:
DT[a %in% some_vals, a := NA]
ซึ่งอัปเดตคอลัมน์a
โดยอ้างอิง เฉพาะแถวที่ตรงตามเงื่อนไข ในขณะนี้ dplyr deep คัดลอกข้อมูลทั้งหมดตารางภายในเพื่อเพิ่มคอลัมน์ใหม่ @BrodieG พูดถึงเรื่องนี้แล้วในคำตอบของเขา
แต่สำเนาลึกจะถูกแทนที่ด้วยสำเนาตื้นเมื่อFR # 617จะดำเนินการ นอกจากนี้ยังเกี่ยวข้อง: dplyr: FR โปรดทราบว่าคอลัมน์ที่คุณแก้ไขจะถูกคัดลอกเสมอ (ดังนั้นจึงช้าลง / หน่วยความจำมีประสิทธิภาพน้อยลง) จะไม่มีวิธีอัปเดตคอลัมน์โดยการอ้างอิง
ฟังก์ชันอื่น ๆ
ใน data.table คุณสามารถรวมได้ในขณะที่เข้าร่วมและนี่เป็นวิธีที่ตรงกว่าที่จะเข้าใจและมีประสิทธิภาพของหน่วยความจำเนื่องจากผลการรวมระดับกลางไม่เคยปรากฏ ตรวจสอบโพสต์นี้เพื่อดูตัวอย่าง คุณไม่สามารถ (ในขณะนี้?) โดยใช้ไวยากรณ์ data.table / data.frame ของ dplyr
คุณลักษณะการรวมการกลิ้งของ data.table ไม่รองรับในไวยากรณ์ของ dplyr เช่นกัน
เมื่อเร็ว ๆ นี้เราได้ใช้การรวมแบบทับซ้อนใน data.table ที่จะรวมช่วงช่วงเวลา ( นี่คือตัวอย่าง ) ซึ่งเป็นฟังก์ชันfoverlaps()
ที่แยกจากกันในขณะนี้ดังนั้นจึงสามารถใช้กับตัวดำเนินการไปป์ได้ (magrittr / pipeR? - ไม่เคยลองด้วยตัวเอง)
แต่ท้ายที่สุดแล้วเป้าหมายของเราคือการรวมเข้าด้วยกัน[.data.table
เพื่อให้เราสามารถเก็บเกี่ยวคุณลักษณะอื่น ๆ เช่นการจัดกลุ่มการรวมกลุ่มในขณะที่เข้าร่วมเป็นต้นซึ่งจะมีข้อ จำกัด เดียวกันกับที่ระบุไว้ข้างต้น
ตั้งแต่ 1.9.4 เป็นต้นมา data.table ใช้การจัดทำดัชนีอัตโนมัติโดยใช้คีย์รองสำหรับการค้นหาแบบไบนารีชุดย่อยที่อิงตามไวยากรณ์ R ปกติ ตัวอย่าง: DT[x == 1]
และDT[x %in% some_vals]
จะสร้างดัชนีโดยอัตโนมัติในการรันครั้งแรกซึ่งจะใช้กับชุดย่อยที่ต่อเนื่องกันจากคอลัมน์เดียวกันไปจนถึงชุดย่อยที่รวดเร็วโดยใช้การค้นหาแบบไบนารี คุณลักษณะนี้จะยังคงพัฒนาต่อไป ตรวจสอบส่วนสำคัญนี้เพื่อดูภาพรวมสั้น ๆ ของคุณลักษณะนี้
จากวิธีfilter()
การใช้งานสำหรับ data.tables จะไม่ใช้ประโยชน์จากคุณสมบัตินี้
คุณลักษณะ dplyr คือมันยังมีส่วนต่อประสานกับฐานข้อมูลโดยใช้ไวยากรณ์เดียวกันซึ่ง data.table ไม่ได้ในขณะนี้
ดังนั้นคุณจะต้องชั่งน้ำหนักในประเด็นเหล่านี้ (และอาจเป็นประเด็นอื่น ๆ ) และตัดสินใจโดยพิจารณาว่าคุณยอมรับข้อแลกเปลี่ยนเหล่านี้หรือไม่
HTH
(1) โปรดทราบว่าการมีประสิทธิภาพของหน่วยความจำจะส่งผลโดยตรงต่อความเร็ว (โดยเฉพาะเมื่อข้อมูลมีขนาดใหญ่ขึ้น) เนื่องจากคอขวดในกรณีส่วนใหญ่คือการย้ายข้อมูลจากหน่วยความจำหลักไปยังแคช (และใช้ประโยชน์จากข้อมูลในแคชให้มากที่สุด - ลดการพลาดแคช - เพื่อลดการเข้าถึงหน่วยความจำหลัก) ยังไม่ลงรายละเอียดที่นี่
dplyr
วิธีการสำหรับตารางข้อมูล แต่ตารางข้อมูลก็มีวิธีการเปรียบเทียบของตัวเองเช่นกัน