Phương pháp so khớp hoạt động khi có một khóa duy nhất trong khung dữ liệu thứ hai cho mỗi giá trị khóa trong khung đầu tiên. Nếu có bản sao trong khung dữ liệu thứ hai thì cách tiếp cận đối sánh và hợp nhất không giống nhau. Tất nhiên, trận đấu sẽ nhanh hơn vì nó không hoạt động nhiều. Đặc biệt nó không bao giờ tìm kiếm các khóa trùng lặp. (tiếp theo sau mã)
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
Trong mã sqldf đã được đăng trong câu hỏi, có vẻ như các chỉ mục đã được sử dụng trên hai bảng nhưng trên thực tế, chúng được đặt trên các bảng đã được ghi đè trước khi lựa chọn sql từng chạy và điều đó giải thích tại sao nó quá chậm. Ý tưởng của sqldf là các khung dữ liệu trong phiên R của bạn tạo thành cơ sở dữ liệu, không phải các bảng trong sqlite. Vì vậy, mỗi khi mã đề cập đến tên bảng không đủ tiêu chuẩn, nó sẽ tìm nó trong không gian làm việc R của bạn - không phải trong cơ sở dữ liệu chính của sqlite. Do đó, câu lệnh select đã được hiển thị đọc d1 và d2 từ không gian làm việc vào cơ sở dữ liệu chính của sqlite để chặn những cái ở đó với các chỉ mục. Kết quả là nó thực hiện một phép nối không có chỉ mục. Nếu bạn muốn sử dụng các phiên bản d1 và d2 có trong cơ sở dữ liệu chính của sqlite, bạn sẽ phải gọi chúng là main.d1 và main. d2 và không như d1 và d2. Ngoài ra, nếu bạn đang cố gắng làm cho nó chạy nhanh nhất có thể thì hãy lưu ý rằng một phép nối đơn giản không thể sử dụng các chỉ mục trên cả hai bảng, do đó bạn có thể tiết kiệm thời gian tạo một trong các chỉ mục. Trong đoạn mã dưới đây, chúng tôi minh họa những điểm này.
Điều đáng chú ý là việc tính toán chính xác có thể tạo ra sự khác biệt lớn về gói nào là nhanh nhất. Ví dụ: chúng tôi thực hiện hợp nhất và tổng hợp bên dưới. Chúng tôi thấy rằng kết quả gần như đảo ngược cho cả hai. Trong ví dụ đầu tiên từ nhanh nhất đến chậm nhất, chúng ta nhận được: data.table, plyr, merge và sqldf trong khi trong ví dụ thứ hai sqldf, tổng hợp, data.table và plyr - gần như ngược lại với cái đầu tiên. Trong ví dụ đầu tiên, sqldf chậm hơn 3 lần so với data.table và trong ví dụ thứ hai, nó nhanh hơn 200 lần so với plyr và nhanh hơn 100 lần so với data.table. Dưới đây chúng tôi hiển thị mã đầu vào, thời gian đầu ra cho hợp nhất và thời gian đầu ra cho tổng hợp. Cũng cần lưu ý rằng sqldf dựa trên cơ sở dữ liệu và do đó có thể xử lý các đối tượng lớn hơn R có thể xử lý (nếu bạn sử dụng đối số dbname của sqldf) trong khi các cách tiếp cận khác bị giới hạn xử lý trong bộ nhớ chính. Ngoài ra, chúng tôi đã minh họa sqldf bằng sqlite nhưng nó cũng hỗ trợ cơ sở dữ liệu H2 và 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"))
)
Kết quả đầu ra từ hai lệnh gọi điểm chuẩn so sánh các phép tính hợp nhất là:
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
Kết quả từ lệnh gọi điểm chuẩn so sánh các tính toán tổng hợp là:
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