Підхід збігів працює, коли у другому кадрі даних є унікальний ключ для кожного значення ключа в першому. Якщо у другому кадрі даних є дублікати, то підходи збігу та злиття неоднакові. Звичайно, матч швидший, оскільки він робить не так багато. Зокрема, він ніколи не шукає дублікатів ключів. (продовження після коду)
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, agregate, data.table та plyr - майже зворотне значення першого. У першому прикладі sqldf в 3 рази повільніший за data.table, а у другому - у 200 разів швидший, ніж plyr, і в 100 разів швидший, ніж data.table. Нижче ми показуємо вхідний код, вихідні таймінги для злиття та вихідні таймінги для сукупності. Також варто зазначити, що 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