วิธีการจับคู่จะทำงานเมื่อมีคีย์ที่ไม่ซ้ำกันในเฟรมข้อมูลที่สองสำหรับแต่ละค่าคีย์ในครั้งแรก หากมีข้อมูลซ้ำกันในเฟรมข้อมูลที่สองวิธีการจับคู่และผสานจะไม่เหมือนกัน แน่นอนว่าการแข่งขันจะเร็วขึ้นเนื่องจากไม่ได้ทำมากนัก โดยเฉพาะอย่างยิ่งจะไม่มองหาคีย์ที่ซ้ำกัน (ต่อหลังรหัส)
DF1 = data.frame(a = c(1, 1, 2, 2), b = 1:4)
DF2 = data.frame(b = c(1, 2, 3, 3, 4), c = letters[1:5])
merge(DF1, DF2)
b a c
1 1 1 a
2 2 1 b
3 3 2 c
4 3 2 d
5 4 2 e
DF1$c = DF2$c[match(DF1$b, DF2$b)]
DF1$c
[1] a b c e
Levels: a b c d e
> DF1
a b c
1 1 1 a
2 1 2 b
3 2 3 c
4 2 4 e
ในรหัส sqldf ที่โพสต์ในคำถามอาจดูเหมือนว่ามีการใช้ดัชนีในสองตาราง แต่ในความเป็นจริงแล้วดัชนีเหล่านี้ถูกวางไว้บนตารางที่ถูกเขียนทับก่อนที่ sql select จะทำงานและในบางส่วนก็อธิบายถึงสาเหตุ มันช้ามาก แนวคิดของ sqldf คือเฟรมข้อมูลในเซสชัน R ของคุณประกอบเป็นฐานข้อมูลไม่ใช่ตารางใน sqlite ดังนั้นทุกครั้งที่โค้ดอ้างถึงชื่อตารางที่ไม่มีเงื่อนไขจะดูในพื้นที่ทำงาน R ของคุณไม่ใช่ในฐานข้อมูลหลักของ sqlite ดังนั้นคำสั่ง select ที่แสดงจะอ่าน d1 และ d2 จากเวิร์กสเปซไปยังฐานข้อมูลหลักของ sqlite เพื่อคัดลอกสิ่งที่อยู่ที่นั่นด้วยดัชนี ด้วยเหตุนี้จึงเข้าร่วมโดยไม่มีดัชนี หากคุณต้องการใช้ประโยชน์จากเวอร์ชันของ d1 และ d2 ที่อยู่ในฐานข้อมูลหลักของ sqlite คุณจะต้องอ้างถึงเป็น main.d1 และ main d2 และไม่เป็น d1 และ d2 นอกจากนี้หากคุณพยายามทำให้มันทำงานได้เร็วที่สุดโปรดทราบว่าการเข้าร่วมแบบธรรมดาไม่สามารถใช้ประโยชน์จากดัชนีบนทั้งสองตารางได้ดังนั้นคุณจึงประหยัดเวลาในการสร้างดัชนีอย่างใดอย่างหนึ่ง ในโค้ดด้านล่างเราจะแสดงประเด็นเหล่านี้
มันคุ้มค่าที่จะสังเกตว่าการคำนวณที่แม่นยำสามารถสร้างความแตกต่างอย่างมากว่าแพ็คเกจใดเร็วที่สุด ตัวอย่างเช่นเราทำการรวมและการรวมด้านล่าง เราเห็นว่าผลลัพธ์เกือบจะกลับกันสำหรับทั้งสอง ในตัวอย่างแรกจากเร็วที่สุดไปยังช้าที่สุดเราได้รับ data.table, plyr, merge และ sqldf ในขณะที่ในตัวอย่างที่สอง sqldf, aggregate, data.table และ plyr - เกือบจะตรงกันข้ามกับอันแรก ในตัวอย่างแรก sqldf ช้ากว่า data.table 3 เท่าและในวินาทีนั้นเร็วกว่า plyr 200 เท่าและเร็วกว่า data.table 100 เท่า ด้านล่างนี้เราจะแสดงรหัสอินพุตการกำหนดเวลาเอาต์พุตสำหรับการผสานและการกำหนดเวลาเอาต์พุตสำหรับการรวม นอกจากนี้ยังควรสังเกตด้วยว่า sqldf ขึ้นอยู่กับฐานข้อมูลดังนั้นจึงสามารถจัดการกับวัตถุที่มีขนาดใหญ่กว่าที่ R สามารถจัดการได้ (ถ้าคุณใช้อาร์กิวเมนต์ dbname ของ sqldf) ในขณะที่วิธีการอื่น ๆ จำกัด เฉพาะการประมวลผลในหน่วยความจำหลัก นอกจากนี้เรายังได้แสดง sqldf ด้วย sqlite แต่ยังรองรับฐานข้อมูล H2 และ PostgreSQL ด้วย
library(plyr)
library(data.table)
library(sqldf)
set.seed(123)
N <- 1e5
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
g1 <- sample(1:1000, N, replace = TRUE)
g2<- sample(1:1000, N, replace = TRUE)
d <- data.frame(d1, g1, g2)
library(rbenchmark)
benchmark(replications = 1, order = "elapsed",
merge = merge(d1, d2),
plyr = join(d1, d2),
data.table = {
dt1 <- data.table(d1, key = "x")
dt2 <- data.table(d2, key = "x")
data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
},
sqldf = sqldf(c("create index ix1 on d1(x)",
"select * from main.d1 join d2 using(x)"))
)
set.seed(123)
N <- 1e5
g1 <- sample(1:1000, N, replace = TRUE)
g2<- sample(1:1000, N, replace = TRUE)
d <- data.frame(x=sample(N,N), y=rnorm(N), g1, g2)
benchmark(replications = 1, order = "elapsed",
aggregate = aggregate(d[c("x", "y")], d[c("g1", "g2")], mean),
data.table = {
dt <- data.table(d, key = "g1,g2")
dt[, colMeans(cbind(x, y)), by = "g1,g2"]
},
plyr = ddply(d, .(g1, g2), summarise, avx = mean(x), avy=mean(y)),
sqldf = sqldf(c("create index ix on d(g1, g2)",
"select g1, g2, avg(x), avg(y) from main.d group by g1, g2"))
)
ผลลัพธ์จากการเรียกใช้เกณฑ์มาตรฐานสองรายการเปรียบเทียบการคำนวณการผสานคือ:
Joining by: x
test replications elapsed relative user.self sys.self user.child sys.child
3 data.table 1 0.34 1.000000 0.31 0.01 NA NA
2 plyr 1 0.44 1.294118 0.39 0.02 NA NA
1 merge 1 1.17 3.441176 1.10 0.04 NA NA
4 sqldf 1 3.34 9.823529 3.24 0.04 NA NA
ผลลัพธ์จากการเรียกใช้เกณฑ์มาตรฐานเปรียบเทียบการคำนวณรวมคือ:
test replications elapsed relative user.self sys.self user.child sys.child
4 sqldf 1 2.81 1.000000 2.73 0.02 NA NA
1 aggregate 1 14.89 5.298932 14.89 0.00 NA NA
2 data.table 1 132.46 47.138790 131.70 0.08 NA NA
3 plyr 1 212.69 75.690391 211.57 0.56 NA NA