Вот лишь несколько небольших примеров того, как вы могли бы ускорить этот процесс, хотя, безусловно, есть и лучшие.Я пытался сохранить структуру ваших циклов и просто оптимизировал их.
Вместо добавления к циклу данных в цикле, я бы создал список в начале и присвоил бы ему значения ив конце свяжите их вместе.Это уже дает вам ускорение примерно на 40%.
Следующая функция просто использует as.character()
во втором операторе if, поскольку они являются другими факторами.Это дает еще 10%.
Последняя, кроме одной функции, использует матрицу вместо data.frame и добавляет к ней значения.И последний реализует все хорошее из вышеперечисленного:)
До сих пор не использовались ни data.tables, ни применяемые функции, ни даже параллельная обработка, что определенно ускорило бы код еще больше, но яЯ уверен, что другие более опытны с ними и могут показать даже лучшие практики.
fdf <- function(){
p <- data.frame(a=integer(),b=integer())
for (i in 1:nrow(innov.df)){
for (j in agrep(innov.df$name[i], innov.df$name, ignore.case=TRUE, value=FALSE,
max.distance = 0.07, useBytes = TRUE)) {
if (i!=j) {
if ((innov.df[i,2]==innov.df[j,2])&&(innov.df[i,3]==innov.df[j,3])) {
p[k,1] <- min(i,j)
p[k,2] <- max(i,j)
k <- k+1
}
}
}
}
p <- data.frame(matrix(p[!is.na(p)],ncol=2, byrow = T))
colnames(p) <- c("a","b")
p
}
flist <- function(){
p <- list()
for (i in 1:nrow(innov.df)) {
for (j in agrep(innov.df$name[i], innov.df$name,
ignore.case=TRUE, value=FALSE,
max.distance = 0.07, useBytes = TRUE)) {
if (i!=j) {
if ((innov.df[i,2])==(innov.df[j,2])&&
(innov.df[i,3])==(innov.df[j,3]))
{
p[[k]] <- cbind(a=min(i,j), b=max(i,j))
k <- k+1
}
}
}
}
p <- data.frame(Filter(Negate(is.null), p))
colnames(p) <- c("a","b")
p
}
flistOpti <- function(){
p <- list()
for (i in 1:nrow(innov.df)) {
for (j in agrep(innov.df$name[i], innov.df$name,
ignore.case=TRUE, value=FALSE,
max.distance = 0.07, useBytes = TRUE)) {
if (i!=j) {
if (as.character(innov.df[i,"idnty_last_nm"])==as.character(innov.df[j,"idnty_last_nm"]) &&
(as.character(innov.df[i,"PERSON_IDENTIFIER_VALUE"])==as.character(innov.df[j,"PERSON_IDENTIFIER_VALUE"]))) {
p[[k]] <- cbind(a=min(i,j), b=max(i,j))
k <- k+1
}
}
}
}
p <- data.frame(Filter(Negate(is.null), p))
colnames(p) <- c("a","b")
p
}
fma <- function(){
p <- matrix(c(a=integer(),b=integer()), ncol=2)
for (i in 1:nrow(innov.df)){
for (j in agrep(innov.df$name[i], innov.df$name, ignore.case=TRUE, value=FALSE,
max.distance = 0.07, useBytes = TRUE)) {
if (i!=j) {
if ((innov.df[i,2]==innov.df[j,2])&&(innov.df[i,3]==innov.df[j,3])) {
p <- c(p, cbind(min(i,j),max(i,j)))
k <- k+1
}
}
}
}
p <- data.frame(matrix(p[!is.na(p)],ncol=2, byrow = T))
colnames(p) <- c("a","b")
p
}
fmaOptim <- function(){
p <- matrix(c(a=integer(),b=integer()), ncol=2)
for (i in 1:nrow(innov.df)){
for (j in agrep(innov.df$name[i], innov.df$name, ignore.case=TRUE, value=FALSE,
max.distance = 0.07, useBytes = TRUE)) {
if (i!=j) {
if (as.character(innov.df[i,"idnty_last_nm"])==as.character(innov.df[j,"idnty_last_nm"]) &&
(as.character(innov.df[i,"PERSON_IDENTIFIER_VALUE"])==as.character(innov.df[j,"PERSON_IDENTIFIER_VALUE"]))) {
p <- c(p, cbind(min(i,j),max(i,j)))
k <- k+1
}
}
}
}
p <- data.frame(matrix(p[!is.na(p)],ncol=2, byrow = T))
colnames(p) <- c("a","b")
p
}
library(microbenchmark)
mc <- microbenchmark(times = 1000,
fdfR = fdf(),
flistR = flist(),
flistOptiR = flistOpti(),
fmaR = fma(),
fmaOptimR = fmaOptim()
)
mc
Unit: microseconds
expr min lq mean median uq max neval cld
fdfR 782.725 831.056 1059.789348 883.3505 1018.7130 24732.664 1000 c
flistR 449.700 470.089 576.289776 489.5335 545.9820 23600.677 1000 b
flistOptiR 394.949 417.227 581.230449 435.1620 492.9325 45357.250 1000 b
fmaR 370.784 389.664 484.542990 402.5015 452.3420 24713.785 1000 ab
fmaOptimR 313.015 335.670 431.991723 349.8295 393.0620 25033.973 1000 a
Вы также можете поместить nrow(innov.df)
вне for(i in 1:nrow(innov.df))
, так как в противном случае он вычисляет количество строк в каждом цикле.Это не привело к ускорению времени, но количество строк в примере всего 2, поэтому, вероятно, оно небольшое, чтобы показать некоторые улучшения.Этот небольшой пример показывает, что при большем количестве строк требуется небольшая оптимизация производительности.
df <- data.frame(
x = runif(100000, 1,10),
id = 1:100000
)
mc <- microbenchmark(times = 1000,
Nrow = {for (i in 1:nrow(df)) {}},
NoNrow = for (i in 1:100000) {}
)
mc
Unit: milliseconds
expr min lq mean median uq max neval cld
Nrow 3.895500 4.060691 4.311444202 4.1584845 4.3051750 10.454830 1000 b
NoNrow 3.384633 3.516409 3.734800425 3.6017420 3.7303085 36.621923 1000 a